@gitgonewild/chainloyalty
v2.1.0
Published
Production-ready TypeScript SDK for ChainLoyalty Web3 Rewards API with CLI dashboard generator
Downloads
36
Maintainers
Readme
@gitgonewild/chainloyalty
Production-ready TypeScript SDK for the ChainLoyalty Web3 Rewards API, with a CLI to generate a complete loyalty dashboard.
Installation
npm install @gitgonewild/chainloyalty
# or
yarn add @gitgonewild/chainloyalty
# or
pnpm add @gitgonewild/chainloyaltyCLI: Generate a Dashboard
Instantly scaffold a complete React dashboard with wallet connection, leaderboard, and your ChainLoyalty API integration.
# Interactive mode
npx @gitgonewild/chainloyalty init my-dashboard
# With options
npx @gitgonewild/chainloyalty init my-dashboard --api-url http://api.example.com --api-key your-key
# Non-interactive with defaults
npx @gitgonewild/chainloyalty init my-dashboard -yCLI Options
| Option | Description |
|--------|-------------|
| --api-url <url> | API URL (default: http://localhost:8000) |
| --api-key <key> | API key for authentication |
| -y, --yes | Skip prompts and use defaults |
| -h, --help | Show help |
What Gets Generated
my-dashboard/
├── package.json # React + Vite + Tailwind setup
├── tailwind.config.js # Pre-configured with ChainLoyalty design system
├── vite.config.js
├── index.html # Google Fonts included
├── .env # Your API config
└── src/
├── main.jsx
├── App.jsx # Routes configured
├── index.css # Tailwind + custom styles
├── context/
│ └── AuthContext.jsx # Wallet state management
├── lib/
│ └── web3.js # MetaMask + ethers.js integration
├── hooks/
│ └── useApi.js # API hooks (rewards, leaderboard, referrals)
├── pages/
│ ├── ConnectWallet.jsx # MetaMask connection page
│ ├── Dashboard.jsx # Wallet info, points, rank overview
│ └── Leaderboard.jsx # Paginated leaderboard with rankings
└── components/
└── layout/
├── Sidebar.jsx # Navigation sidebar
└── AuthShell.jsx # Protected route wrapperRun the Dashboard
cd my-dashboard
npm install
npm run devOpen http://localhost:5173, connect your MetaMask wallet, and you're ready!
Quick Start (SDK)
import { ChainLoyalty } from '@gitgonewild/chainloyalty';
const client = new ChainLoyalty({
apiKey: 'your-api-key',
baseUrl: 'https://api.chainloyalty.io'
});
// Track a purchase event
await client.events.track({
eventType: 'purchase',
walletAddress: '0x1234567890abcdef1234567890abcdef12345678',
metadata: { amount: 100, currency: 'USD' }
});
// Get user rewards
const rewards = await client.rewards.get('0x1234...');
console.log(`Total points: ${rewards.totalPoints}`);Features
- Type-safe - Full TypeScript support with comprehensive types
- Clean API - Intuitive, domain-driven interface design
- Automatic retries - Exponential backoff with configurable retry count
- Error handling - Structured error classes for precise error handling
- Web3-ready - Built-in wallet utilities and SIWE authentication
- Debug mode - Optional request/response logging
Configuration
const client = new ChainLoyalty({
// API key for event tracking and admin operations
apiKey: 'your-api-key',
// Base URL (default: https://api.chainloyalty.io)
baseUrl: 'https://api.chainloyalty.io',
// Request timeout in ms (default: 30000)
timeout: 30000,
// Number of retry attempts (default: 3)
retries: 3,
// Enable debug logging (default: false)
debug: true
});Authentication
Sign-In With Ethereum (SIWE)
import { BrowserProvider } from 'ethers';
// Get signer from wallet
const provider = new BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
// Sign in (combines challenge, signing, and verification)
const { token, user } = await client.auth.signIn(signer);
console.log(`Signed in as ${user.wallet}`);
// Or do it manually
const { message, nonce } = await client.auth.getChallenge(walletAddress);
const signature = await signer.signMessage(message);
const { token } = await client.auth.verify(walletAddress, signature, nonce);Events
Track user actions to trigger reward rules.
// Track a generic event
await client.events.track({
eventType: 'purchase',
walletAddress: '0x...',
metadata: { amount: 50, productId: 'prod-123' }
});
// Convenience methods for common events
await client.events.trackPurchase('0x...', 100, { currency: 'USD' });
await client.events.trackLogin('0x...');
await client.events.trackSignup('0x...');
await client.events.trackAchievement('0x...', 'first-purchase');
await client.events.trackCustom('0x...', 'nft_mint', { tokenId: 42 });
// List events for a wallet
const { data, pagination } = await client.events.list({
wallet: '0x...',
eventType: 'purchase',
page: 1,
limit: 20
});
// Get event statistics
const stats = await client.events.getStats('0x...');
console.log(`Total events: ${stats.totalEvents}`);Rewards
Manage points, badges, and leaderboards.
// Get wallet rewards
const rewards = await client.rewards.get('0x...');
console.log(`Points: ${rewards.totalPoints}`);
console.log(`Badges: ${rewards.badges.length}`);
// Convenience methods
const points = await client.rewards.getPoints('0x...');
const pending = await client.rewards.getPendingPoints('0x...');
const badges = await client.rewards.getBadges('0x...');
// Claim pending rewards
const claimed = await client.rewards.claim('0x...');
console.log(`Claimed ${claimed.claimedPoints} points`);
// Leaderboard
const { leaderboard } = await client.rewards.getLeaderboard({ limit: 10 });
const topWallets = await client.rewards.getTopWallets(5);
const rank = await client.rewards.getRank('0x...');
// Badge checks
const hasBadge = await client.rewards.hasBadge('0x...', 'whale-badge');Referrals
Generate and manage referral codes.
// Generate a referral code (requires auth)
const code = await client.referrals.generate({
maxUses: 10,
expiresInDays: 30
});
console.log(`Share this code: ${code.code}`);
// Apply a referral code
await client.referrals.apply('FRIEND123', '0xNewUserWallet...');
// Validate before applying
const { valid, error } = await client.referrals.validate('CODE', '0x...');
if (valid) {
await client.referrals.apply('CODE', '0x...');
}
// Check code status
const details = await client.referrals.getCode('FRIEND123');
const isExpired = await client.referrals.isExpired('FRIEND123');
const remaining = await client.referrals.getRemainingUses('FRIEND123');
// Get referral stats
const stats = await client.referrals.getStats('0x...');
console.log(`Total referrals: ${stats.totalReferrals}`);
// Get your codes (requires auth)
const myCodes = await client.referrals.getMyCodes();Admin - Rules
Create and manage reward rules (requires API key).
// List rules
const rules = await client.admin.rules.list();
const activeRules = await client.admin.rules.listActive();
const thresholdRules = await client.admin.rules.listByType('THRESHOLD');
// Create a threshold rule (triggers at X events)
const rule = await client.admin.rules.create({
name: 'First Purchase Bonus',
type: 'THRESHOLD',
eventTypes: ['purchase'],
threshold: 1,
reward: { type: 'POINTS', points: 100 }
});
// Create a frequency rule (limits rewards per time period)
await client.admin.rules.createFrequencyRule(
'Daily Login Bonus',
['login'],
'1/day',
{ type: 'POINTS', points: 10 }
);
// Create a conditional rule
await client.admin.rules.createConditionalRule(
'Big Spender',
['purchase'],
[{ field: 'metadata.amount', operator: 'gte', value: 100 }],
{ type: 'BADGE', badgeId: 'big-spender' }
);
// Update and delete
await client.admin.rules.update(ruleId, { active: false });
await client.admin.rules.enable(ruleId);
await client.admin.rules.disable(ruleId);
await client.admin.rules.delete(ruleId);Admin - API Keys
Create and manage API keys programmatically (requires API key with admin privileges).
// Create a new API key
const { apiKey, data } = await client.admin.apiKeys.create({
name: 'Production App',
email: '[email protected]'
});
// IMPORTANT: Save `apiKey` immediately - it's only shown once!
console.log('New API key:', apiKey);
// List all API keys
const { data: keys } = await client.admin.apiKeys.list();
const activeKeys = await client.admin.apiKeys.listActive();
// List with pagination and filters
const { data: keys, pagination } = await client.admin.apiKeys.list({
active: true,
page: 1,
limit: 10
});
// Get a specific API key by ID
const key = await client.admin.apiKeys.get('key-id');
// Update an API key
await client.admin.apiKeys.update('key-id', {
name: 'Updated Name',
email: '[email protected]'
});
// Activate/Deactivate keys
await client.admin.apiKeys.deactivate('key-id');
await client.admin.apiKeys.activate('key-id');
// Rotate a compromised key (generates new value, keeps same ID)
const { apiKey: newKey } = await client.admin.apiKeys.rotate('key-id');
// Update your apps with this new key immediately!
// Validate an API key
const { valid, client: keyClient } = await client.admin.apiKeys.validate('sk_...');
if (valid) {
console.log(`Key belongs to: ${keyClient.name}`);
}
// Delete an API key permanently
await client.admin.apiKeys.delete('key-id');Error Handling
The SDK provides structured error classes for precise error handling.
import {
ChainLoyalty,
AuthenticationError,
ValidationError,
RateLimitError,
NetworkError,
NotFoundError
} from '@gitgonewild/chainloyalty';
try {
await client.events.track({ ... });
} catch (error) {
if (error instanceof AuthenticationError) {
console.log('Invalid API key or token');
} else if (error instanceof ValidationError) {
console.log('Invalid request:', error.errors);
} else if (error instanceof RateLimitError) {
console.log(`Rate limited. Retry after ${error.retryAfter}s`);
} else if (error instanceof NetworkError) {
console.log('Network connection failed');
} else if (error instanceof NotFoundError) {
console.log('Resource not found');
}
// All errors have these properties
console.log(error.code); // e.g., 'VALIDATION_ERROR'
console.log(error.message); // Human-readable message
console.log(error.status); // HTTP status code
console.log(error.details); // Additional context
}Utilities
Wallet utilities for Web3 operations.
import {
isValidAddress,
normalizeAddress,
truncateAddress,
signSIWEMessage,
parseSIWEMessage
} from '@gitgonewild/chainloyalty';
// Validate address format
if (isValidAddress(userInput)) {
const normalized = normalizeAddress(userInput);
}
// Display-friendly address
const display = truncateAddress('0x1234...5678'); // "0x1234...5678"
// SIWE helpers
const { signature, address } = await signSIWEMessage(signer, message);
const parsed = parseSIWEMessage(message);TypeScript
All types are exported for your use.
import type {
WalletAddress,
Event,
EventType,
Badge,
WalletRewards,
Rule,
RuleType,
ReferralCode,
LeaderboardEntry,
// API Key types
APIKey,
CreateAPIKeyRequest,
CreateAPIKeyResponse,
UpdateAPIKeyRequest,
APIKeysListParams,
RotateAPIKeyResponse
} from '@gitgonewild/chainloyalty';API Reference
Client Methods
| Method | Description |
|--------|-------------|
| client.health() | Check API health status |
| client.version() | Get API version info |
| client.setAuthToken(token) | Set JWT auth token |
| client.clearAuthToken() | Clear auth token |
| client.setApiKey(key) | Set API key |
| client.configure(options) | Update configuration |
Modules
| Module | Description |
|--------|-------------|
| client.auth | Wallet authentication (SIWE) |
| client.events | Event tracking |
| client.rewards | Points, badges, leaderboards |
| client.referrals | Referral codes |
| client.admin.rules | Reward rule management |
| client.admin.apiKeys | API key management |
License
MIT
