npm package: @gitgonewild/chainloyalty
Description: Production-ready TypeScript SDK for ChainLoyalty Web3 Rewards API with CLI dashboard generator
Author: GitGoneWild
Latest version: 2.1.0

# @gitgonewild/chainloyalty

Production-ready TypeScript SDK for the ChainLoyalty Web3 Rewards API, with a CLI to generate a complete loyalty dashboard.

## Installation

```bash
npm install @gitgonewild/chainloyalty
# or
yarn add @gitgonewild/chainloyalty
# or
pnpm add @gitgonewild/chainloyalty
```

## CLI: Generate a Dashboard

Instantly scaffold a complete React dashboard with wallet connection, leaderboard, and your ChainLoyalty API integration.

```bash
# 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 -y
```

### CLI 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 wrapper
```

### Run the Dashboard

```bash
cd my-dashboard
npm install
npm run dev
```

Open http://localhost:5173, connect your MetaMask wallet, and you're ready!

---

## Quick Start (SDK)

```typescript
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

```typescript
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)

```typescript
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.

```typescript
// 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.

```typescript
// 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.

```typescript
// 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).

```typescript
// 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).

```typescript
// Create a new API key
const { apiKey, data } = await client.admin.apiKeys.create({
  name: 'Production App',
  email: 'team@company.com'
});
// 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: 'new@email.com'
});

// 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.

```typescript
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.

```typescript
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.

```typescript
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