@explorins/pers-sdk 1.6.37 → 1.6.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,245 +5,731 @@
5
5
 
6
6
  Platform-agnostic TypeScript SDK for PERS (Phygital Experience Rewards System) - Modern Manager-Service architecture providing clean, consistent APIs for tourism loyalty applications.
7
7
 
8
+ ---
9
+
10
+ ## Table of Contents
11
+
12
+ - [Overview](#overview)
13
+ - [Dependencies](#dependencies)
14
+ - [Installation](#installation)
15
+ - [Quick Start](#quick-start)
16
+ - [Platform Integration](#platform-integration)
17
+ - [Architecture](#architecture)
18
+ - [Core Features](#core-features)
19
+ - [Configuration](#configuration)
20
+ - [Advanced Authentication](#advanced-authentication)
21
+ - [Error Handling](#error-handling)
22
+ - [Bundle Size](#bundle-size)
23
+ - [TypeScript Types](#typescript-types)
24
+ - [Documentation](#documentation)
25
+ - [Related Packages](#related-packages)
26
+ - [License](#license)
27
+
28
+ ---
29
+
8
30
  ## Overview
9
31
 
10
- PERS is a comprehensive tourism loyalty platform bridging physical and digital experiences through loyalty programs, campaign management, payments, blockchain integration, business management, and analytics.
32
+ PERS (Phygital Experience Rewards System) is a comprehensive tourism loyalty platform bridging physical and digital experiences. It provides:
33
+
34
+ - **Loyalty Programs**: Token-based rewards, credit systems, and user tiers
35
+ - **Campaign Management**: Marketing campaigns with automated rewards distribution
36
+ - **Business Network**: Multi-tenant business discovery and partnerships
37
+ - **Blockchain Integration**: EVM-compatible chains (Ethereum, Polygon, Camino)
38
+ - **Redemption Engine**: Reward fulfillment with optional blockchain signing
39
+ - **Analytics**: Real-time transaction and user engagement metrics
40
+
41
+ ---
42
+
43
+ ## Dependencies
44
+
45
+ ### Required Peer Dependencies
46
+
47
+ These packages MUST be installed alongside `@explorins/pers-sdk`:
48
+
49
+ ```bash
50
+ npm install @explorins/pers-shared ethers@^6.15.0
51
+ ```
52
+
53
+ | Package | Version | Purpose |
54
+ |---------|---------|---------|
55
+ | `@explorins/pers-shared` | `*` | Shared types, interfaces, and DTOs used across all SDK domains |
56
+ | `ethers` | `^6.15.0` | Blockchain/Web3 operations (required for `sdk.web3` manager) |
57
+
58
+ ### Optional Dependencies (Platform-Specific)
59
+
60
+ | Package | Required For | Notes |
61
+ |---------|--------------|-------|
62
+ | `rxjs` | `AngularHttpClientAdapter` only | Loaded dynamically at runtime; NOT bundled into SDK |
63
+
64
+ > **AI Agent Note**: The SDK has **ZERO runtime RxJS dependency** unless you specifically use `AngularHttpClientAdapter`. Browser, Node.js, and React Native integrations do NOT require RxJS.
65
+
66
+ ### Direct Dependencies
67
+
68
+ | Package | Purpose |
69
+ |---------|---------|
70
+ | `@explorins/web3-ts` | Internal Web3 chain utilities |
71
+
72
+ ---
11
73
 
12
74
  ## Installation
13
75
 
14
76
  ```bash
77
+ # Core SDK
15
78
  npm install @explorins/pers-sdk
79
+
80
+ # Required peer dependencies
81
+ npm install @explorins/pers-shared ethers@^6.15.0
82
+
83
+ # Optional: For Angular applications only
84
+ npm install rxjs
16
85
  ```
17
86
 
87
+ ---
88
+
18
89
  ## Quick Start
19
90
 
91
+ ### Minimum Viable Example
92
+
20
93
  ```typescript
21
94
  import { PersSDK } from '@explorins/pers-sdk';
22
95
  import { BrowserFetchClientAdapter } from '@explorins/pers-sdk/platform-adapters';
23
96
 
97
+ // 1. Initialize SDK (required: adapter + project key)
98
+ const sdk = new PersSDK(new BrowserFetchClientAdapter(), {
99
+ apiProjectKey: 'your-project-key' // Get from PERS dashboard
100
+ });
101
+
102
+ // 2. Authenticate with external JWT (Firebase, Auth0, Cognito, etc.)
103
+ const externalJWT = await yourAuthProvider.getIdToken(); // Your JWT
104
+ const authResult = await sdk.auth.loginWithToken(externalJWT, 'user');
105
+ console.log('Authenticated user:', authResult.user.id);
106
+
107
+ // 3. Use SDK managers
108
+ const campaigns = await sdk.campaigns.getActiveCampaigns();
109
+ const tokens = await sdk.tokens.getTokens();
110
+ ```
111
+
112
+ ### Complete Example
113
+
114
+ ```typescript
115
+ import { PersSDK } from '@explorins/pers-sdk';
116
+ import { BrowserFetchClientAdapter } from '@explorins/pers-sdk/platform-adapters';
117
+
118
+ // Initialize SDK with browser fetch adapter
24
119
  const sdk = new PersSDK(new BrowserFetchClientAdapter(), {
25
120
  environment: 'production',
26
121
  apiProjectKey: 'your-project-key'
27
122
  });
28
123
 
29
- // Authentication
124
+ // Authentication - login with external JWT (Firebase, Auth0, etc.)
125
+ const authResult = await sdk.auth.loginWithToken(firebaseJWT, 'user');
30
126
  const user = await sdk.auth.getCurrentUser();
31
127
 
32
128
  // Business operations
33
129
  const businesses = await sdk.businesses.getActiveBusinesses();
130
+ const business = await sdk.businesses.getBusinessById('business-123');
34
131
 
35
132
  // Campaign management
36
133
  const campaigns = await sdk.campaigns.getActiveCampaigns();
37
- const campaignClaim = await sdk.campaigns.claimCampaign({ campaignId: 'campaign-123', userId: 'user-456' });
134
+ const claim = await sdk.campaigns.claimCampaign({
135
+ campaignId: 'campaign-123',
136
+ businessId: 'business-456'
137
+ });
38
138
 
39
139
  // Token operations
40
140
  const tokens = await sdk.tokens.getTokens();
41
- const balances = await sdk.tokens.getBalances(userId);
141
+ const creditToken = await sdk.tokens.getActiveCreditToken();
142
+ const rewardTokens = await sdk.tokens.getRewardTokens();
143
+
144
+ // User claims history
145
+ const userClaims = await sdk.campaigns.getUserClaims();
42
146
  ```
43
147
 
148
+ ---
149
+
44
150
  ## Platform Integration
45
151
 
152
+ ### Browser / React / Vue
153
+
154
+ **No additional dependencies required.**
155
+
156
+ ```typescript
157
+ import { PersSDK } from '@explorins/pers-sdk';
158
+ import { BrowserFetchClientAdapter } from '@explorins/pers-sdk/platform-adapters';
159
+
160
+ const sdk = new PersSDK(new BrowserFetchClientAdapter(), {
161
+ environment: 'production',
162
+ apiProjectKey: 'your-project-key'
163
+ });
164
+
165
+ // Ready to use
166
+ const campaigns = await sdk.campaigns.getActiveCampaigns();
167
+ ```
168
+
46
169
  ### Angular
47
170
 
171
+ **Requires `rxjs` peer dependency.**
172
+
173
+ ```bash
174
+ npm install rxjs
175
+ ```
176
+
48
177
  ```typescript
49
- import { Injectable } from '@angular/core';
178
+ import { Injectable, inject } from '@angular/core';
50
179
  import { HttpClient } from '@angular/common/http';
51
- import { PersSDK } from '@explorins/pers-sdk';
180
+ import { createPersSDK, PersSDK } from '@explorins/pers-sdk';
52
181
  import { AngularHttpClientAdapter } from '@explorins/pers-sdk/platform-adapters';
182
+ import { IndexedDBTokenStorage } from '@explorins/pers-sdk/core';
53
183
 
54
184
  @Injectable({ providedIn: 'root' })
55
185
  export class PersSDKService {
56
- private sdk: PersSDK;
57
-
58
- constructor(httpClient: HttpClient) {
59
- this.sdk = new PersSDK(new AngularHttpClientAdapter(httpClient), {
60
- environment: 'production',
61
- apiProjectKey: 'your-project-key'
62
- });
186
+ private readonly sdk: PersSDK;
187
+
188
+ constructor() {
189
+ const httpClient = inject(HttpClient);
190
+ // Use createPersSDK factory or new PersSDK()
191
+ this.sdk = createPersSDK(
192
+ new AngularHttpClientAdapter(httpClient),
193
+ {
194
+ environment: 'production',
195
+ apiProjectKey: 'your-project-key',
196
+ authStorage: new IndexedDBTokenStorage() // Recommended
197
+ }
198
+ );
63
199
  }
64
200
 
65
- getSDK(): PersSDK {
66
- return this.sdk;
67
- }
201
+ // Expose managers directly for clean component access
202
+ get auth() { return this.sdk.auth; }
203
+ get users() { return this.sdk.users; }
204
+ get tokens() { return this.sdk.tokens; }
205
+ get businesses() { return this.sdk.businesses; }
206
+ get campaigns() { return this.sdk.campaigns; }
207
+ get redemptions() { return this.sdk.redemptions; }
208
+ get transactions() { return this.sdk.transactions; }
209
+ get purchases() { return this.sdk.purchases; }
210
+ get web3() { return this.sdk.web3; }
211
+ // ... other managers as needed
68
212
  }
69
213
  ```
70
214
 
71
- ### React/Browser
215
+ ### Node.js
216
+
217
+ **No additional dependencies required.**
72
218
 
73
219
  ```typescript
74
220
  import { PersSDK } from '@explorins/pers-sdk';
75
- import { BrowserFetchClientAdapter } from '@explorins/pers-sdk/platform-adapters';
221
+ import { NodeHttpClientAdapter } from '@explorins/pers-sdk/platform-adapters';
76
222
 
77
- const sdk = new PersSDK(new BrowserFetchClientAdapter(), {
223
+ const sdk = new PersSDK(new NodeHttpClientAdapter(), {
78
224
  environment: 'production',
79
225
  apiProjectKey: 'your-project-key'
80
226
  });
227
+
228
+ // Server-side operations
229
+ const businesses = await sdk.businesses.getActiveBusinesses();
81
230
  ```
82
231
 
83
- ### Node.js
232
+ ### React Native
233
+
234
+ **Use the dedicated React Native SDK** (includes passkeys, secure storage, DPoP):
235
+
236
+ ```bash
237
+ npm install @explorins/pers-sdk-react-native @react-native-async-storage/async-storage
238
+ ```
84
239
 
85
240
  ```typescript
86
- import { PersSDK } from '@explorins/pers-sdk';
87
- import { NodeHttpClientAdapter } from '@explorins/pers-sdk/platform-adapters';
241
+ // In your root layout (e.g., _layout.tsx for Expo Router)
242
+ import { PersSDKProvider } from '@explorins/pers-sdk-react-native';
243
+
244
+ export default function RootLayout() {
245
+ return (
246
+ <PersSDKProvider config={{ apiProjectKey: 'your-project-key' }}>
247
+ <YourApp />
248
+ </PersSDKProvider>
249
+ );
250
+ }
88
251
 
89
- const sdk = new PersSDK(new NodeHttpClientAdapter(), {
90
- environment: 'production',
91
- apiProjectKey: 'your-project-key'
92
- });
252
+ // In your components - use hooks
253
+ import { useAuth, useTokens, useCampaigns } from '@explorins/pers-sdk-react-native';
254
+
255
+ function MyComponent() {
256
+ const { login, isAuthenticated } = useAuth();
257
+ const { getTokens } = useTokens();
258
+ const { getActiveCampaigns, claimCampaign } = useCampaigns();
259
+ // ...
260
+ }
93
261
  ```
94
262
 
263
+ See [@explorins/pers-sdk-react-native](https://www.npmjs.com/package/@explorins/pers-sdk-react-native) for full setup including passkey configuration.
264
+
265
+ ---
266
+
95
267
  ## Architecture
96
268
 
97
- The SDK uses a clean Manager-Service pattern:
269
+ The SDK uses a clean Manager-Service pattern with three access levels:
98
270
 
99
271
  ```typescript
100
- // Manager Layer (Primary Interface)
272
+ // ═══════════════════════════════════════════════════════════════════════════
273
+ // MANAGER LAYER (Recommended - High-level, intuitive APIs)
274
+ // ═══════════════════════════════════════════════════════════════════════════
275
+
101
276
  sdk.auth // Authentication & sessions
102
277
  sdk.users // User profiles & management
103
- sdk.tokens // Token operations & balances
278
+ sdk.userStatus // User status/tier management
279
+ sdk.tokens // Token types & configuration
104
280
  sdk.businesses // Business operations
105
281
  sdk.campaigns // Marketing campaigns
106
282
  sdk.redemptions // Reward redemptions
107
283
  sdk.transactions // Transaction history
108
- sdk.payments // Payment processing
284
+ sdk.purchases // Purchase/payment processing
109
285
  sdk.analytics // Reporting & insights
110
286
  sdk.tenants // Multi-tenant configuration
111
287
  sdk.donations // Charitable giving
112
- sdk.files // File operations
288
+ sdk.files // File upload/download operations
113
289
  sdk.web3 // Blockchain operations
290
+ sdk.apiKeys // API key management (Admin)
114
291
 
115
- // Service Layer (Advanced Access)
116
- sdk.users.getUserService() // Direct service access
117
- sdk.campaigns.getCampaignService()
292
+ // ═══════════════════════════════════════════════════════════════════════════
293
+ // SERVICE LAYER (Advanced - Full domain access)
294
+ // ═══════════════════════════════════════════════════════════════════════════
295
+
296
+ sdk.campaigns.getCampaignService() // Full CampaignService access
297
+ sdk.tokens.getTokenService() // Full TokenService access
298
+ sdk.businesses.getBusinessService() // Full BusinessService access
299
+ sdk.purchases.getPurchaseService() // Full PaymentService access
300
+ // ... each manager exposes its underlying service
301
+
302
+ // ═══════════════════════════════════════════════════════════════════════════
303
+ // API LAYER (Expert - Direct REST API access)
304
+ // ═══════════════════════════════════════════════════════════════════════════
305
+
306
+ const apiClient = sdk.api();
307
+ const customData = await apiClient.get<CustomType>('/custom-endpoint');
308
+ await apiClient.post('/custom-endpoint', { data: 'value' });
118
309
  ```
119
310
 
311
+ ### Available Managers Reference
312
+
313
+ | Manager | Accessor | Primary Use Cases |
314
+ |---------|----------|-------------------|
315
+ | `AuthManager` | `sdk.auth` | Login, logout, token management, authentication status |
316
+ | `UserManager` | `sdk.users` | User profiles, account management |
317
+ | `UserStatusManager` | `sdk.userStatus` | User tiers, status levels |
318
+ | `TokenManager` | `sdk.tokens` | Token types, credit tokens, reward tokens |
319
+ | `BusinessManager` | `sdk.businesses` | Business discovery, details, types |
320
+ | `CampaignManager` | `sdk.campaigns` | Campaign discovery, claiming, user history |
321
+ | `RedemptionManager` | `sdk.redemptions` | Redeem rewards, redemption history |
322
+ | `TransactionManager` | `sdk.transactions` | Transaction history, details |
323
+ | `PurchaseManager` | `sdk.purchases` | Payment intents, purchase tokens |
324
+ | `AnalyticsManager` | `sdk.analytics` | Reporting, transaction analytics |
325
+ | `TenantManager` | `sdk.tenants` | Tenant config, client settings |
326
+ | `DonationManager` | `sdk.donations` | Donation types, charitable giving |
327
+ | `FileManager` | `sdk.files` | Signed URLs, media optimization |
328
+ | `Web3Manager` | `sdk.web3` | Blockchain operations, token metadata |
329
+ | `ApiKeyManager` | `sdk.apiKeys` | API key CRUD (Admin only) |
330
+
331
+ ---
332
+
120
333
  ## Core Features
121
334
 
122
335
  ### Authentication
123
- - **Secure DPoP (Demonstrating Proof-of-Possession)**: Enabled by default to bind tokens to the client, preventing replay attacks.
124
- - External JWT integration (Firebase, Auth0, etc.)
125
- - Native token validation and refresh
126
- - User and admin authentication flows
336
+
337
+ The SDK uses **external JWT tokens** for authentication. You provide a JWT from your authentication provider (Firebase, Auth0, Cognito, etc.), and the SDK exchanges it for PERS access tokens.
338
+
339
+ ```typescript
340
+ // Step 1: Get JWT from your auth provider (Firebase example)
341
+ import { getAuth } from 'firebase/auth';
342
+ const firebaseUser = getAuth().currentUser;
343
+ const externalJWT = await firebaseUser?.getIdToken();
344
+
345
+ // Step 2: Exchange JWT for PERS tokens
346
+ const authResult = await sdk.auth.loginWithToken(externalJWT, 'user');
347
+ console.log('User authenticated:', authResult.user.name);
348
+
349
+ // Admin login
350
+ const adminResult = await sdk.auth.loginWithToken(adminJWT, 'admin');
351
+ console.log('Admin authenticated:', adminResult.admin.email);
352
+
353
+ // Check authentication status (async - verifies with server)
354
+ const isAuth = await sdk.auth.isAuthenticated();
355
+
356
+ // Quick check if tokens exist locally (faster, less reliable)
357
+ const hasTokens = await sdk.auth.hasValidAuth();
358
+
359
+ // Get current user
360
+ const user = await sdk.auth.getCurrentUser();
361
+
362
+ // Logout / clear auth
363
+ await sdk.auth.clearAuth();
364
+ ```
365
+
366
+ **How it works:**
367
+ 1. Your app authenticates users via Firebase/Auth0/etc.
368
+ 2. You call `sdk.auth.loginWithToken(jwt)` with that JWT
369
+ 3. PERS validates the JWT and returns PERS-specific access/refresh tokens
370
+ 4. SDK stores tokens and handles automatic refresh
371
+ 5. All subsequent SDK calls are automatically authenticated
372
+
373
+ **Security Features:**
374
+ - **DPoP (Demonstrating Proof-of-Possession)**: Enabled by default - binds tokens to client
375
+ - Automatic token refresh and validation
127
376
  - Flexible storage strategies (LocalStorage, IndexedDB, Memory)
377
+ - Support for user and admin authentication flows
128
378
 
129
379
  ### Business Management
130
- - Business registration and profiles
131
- - Business type management
132
- - Public business discovery
380
+
381
+ ```typescript
382
+ // Get all active businesses
383
+ const businesses = await sdk.businesses.getActiveBusinesses();
384
+
385
+ // Get business by ID
386
+ const business = await sdk.businesses.getBusinessById('business-123');
387
+
388
+ // Get business types
389
+ const types = await sdk.businesses.getBusinessTypes();
390
+ ```
133
391
 
134
392
  ### Campaign System
135
- - Marketing campaign management
136
- - User campaign claims and participation
137
- - Advanced campaign triggers and automation
138
393
 
139
- ### Token Economy
140
- - Token balance management
141
- - Token transfers and transactions
142
- - Multiple token type support
394
+ ```typescript
395
+ // Get active campaigns available for claiming
396
+ const campaigns = await sdk.campaigns.getActiveCampaigns();
397
+
398
+ // Get campaign details
399
+ const campaign = await sdk.campaigns.getCampaignById('campaign-123');
400
+
401
+ // Claim campaign rewards
402
+ const claim = await sdk.campaigns.claimCampaign({
403
+ campaignId: 'campaign-123',
404
+ businessId: 'business-456' // Optional: associated business
405
+ });
406
+
407
+ // Get user's campaign claim history
408
+ const userClaims = await sdk.campaigns.getUserClaims();
409
+ ```
410
+
411
+ ### Token Management
412
+
413
+ ```typescript
414
+ // Get all token types
415
+ const tokens = await sdk.tokens.getTokens();
416
+
417
+ // Get active credit token (main loyalty currency)
418
+ const creditToken = await sdk.tokens.getActiveCreditToken();
143
419
 
144
- ### Reward Redemptions
145
- - Redemption offer management
146
- - User redemption tracking
147
- - Multiple redemption types
420
+ // Get reward tokens
421
+ const rewards = await sdk.tokens.getRewardTokens();
148
422
 
149
- ### Payment Processing
150
- - Payment intent creation
151
- - Purchase token management
152
- - Transaction history
423
+ // Get status tokens (tier/achievement tokens)
424
+ const statusTokens = await sdk.tokens.getStatusTokens();
425
+
426
+ // Get token by blockchain contract
427
+ const token = await sdk.tokens.getTokenByContract('0x123...', 'token-id');
428
+ ```
429
+
430
+ ### Purchase/Payment Processing
431
+
432
+ ```typescript
433
+ // Create payment intent
434
+ const intent = await sdk.purchases.createPaymentIntent(
435
+ 100, // amount
436
+ 'usd', // currency
437
+ 'user@example.com', // email
438
+ 'Token Purchase' // description
439
+ );
440
+
441
+ // Get user's purchase history
442
+ const purchases = await sdk.purchases.getAllUserPurchases();
443
+
444
+ // Get available purchase tokens
445
+ const purchaseTokens = await sdk.purchases.getActivePurchaseTokens();
446
+ ```
447
+
448
+ ---
153
449
 
154
450
  ## Configuration
155
451
 
452
+ ### API Project Key (Required)
453
+
454
+ The `apiProjectKey` is a **tenant-specific identifier** that associates your application with a PERS tenant (organization). You must obtain this from the PERS admin dashboard or from your PERS account manager.
455
+
156
456
  ```typescript
457
+ // Example project key format (64-character hex string)
458
+ apiProjectKey: 'e3e16b5863f0a042b949650d236a37b0758bd51177463d627921112d2291fe01'
459
+ ```
460
+
461
+ ### Full Configuration Example
462
+
463
+ ```typescript
464
+ import { PersSDK } from '@explorins/pers-sdk';
157
465
  import { IndexedDBTokenStorage } from '@explorins/pers-sdk/core';
466
+ import { BrowserFetchClientAdapter } from '@explorins/pers-sdk/platform-adapters';
158
467
 
159
- interface PersConfig {
160
- environment?: 'development' | 'staging' | 'production';
161
- apiProjectKey: string;
468
+ const sdk = new PersSDK(new BrowserFetchClientAdapter(), {
469
+ // Environment: 'development' | 'staging' | 'production'
470
+ environment: 'production', // Default: 'production'
162
471
 
163
- // Storage Strategy (Recommended: IndexedDB)
164
- authStorage?: TokenStorage; // Defaults to LocalStorage if omitted
472
+ // Project key for API authentication (required)
473
+ apiProjectKey: 'your-project-key',
165
474
 
166
- // DPoP Security (Default: enabled)
167
- dpop?: {
168
- enabled: boolean;
169
- };
475
+ // API version (currently only v2 supported)
476
+ apiVersion: 'v2', // Default: 'v2'
170
477
 
171
- // Advanced overrides
172
- authProvider?: PersAuthProvider;
173
- }
478
+ // Request timeout in milliseconds
479
+ timeout: 30000, // Default: 30000
480
+
481
+ // Retry attempts for failed requests
482
+ retries: 3, // Default: 3
483
+
484
+ // Token storage strategy (recommended: IndexedDB)
485
+ authStorage: new IndexedDBTokenStorage(), // Default: LocalStorage
486
+
487
+ // DPoP (Demonstrating Proof-of-Possession) configuration
488
+ dpop: {
489
+ enabled: true, // Default: true (recommended for security)
490
+ },
491
+
492
+ // Authentication type for auto-created provider
493
+ authType: 'user', // 'user' | 'admin', Default: 'user'
494
+
495
+ // Token refresh margin (seconds before expiry to refresh)
496
+ tokenRefreshMargin: 60, // Default: 60
497
+
498
+ // Background refresh threshold (seconds)
499
+ backgroundRefreshThreshold: 30 // Default: 30
500
+ });
174
501
  ```
175
502
 
503
+ ### Configuration Options Reference
504
+
505
+ | Option | Type | Default | Description |
506
+ |--------|------|---------|-------------|
507
+ | `environment` | `'development' \| 'staging' \| 'production'` | `'production'` | API environment target |
508
+ | `apiProjectKey` | `string` | - | **Required.** Project key for API authentication |
509
+ | `apiVersion` | `'v2'` | `'v2'` | API version |
510
+ | `timeout` | `number` | `30000` | Request timeout (ms) |
511
+ | `retries` | `number` | `3` | Retry attempts |
512
+ | `authStorage` | `TokenStorage` | `LocalStorage` | Token storage implementation |
513
+ | `dpop.enabled` | `boolean` | `true` | Enable DPoP security |
514
+ | `authType` | `'user' \| 'admin'` | `'user'` | Authentication type |
515
+ | `authProvider` | `PersAuthProvider` | auto-created | Custom auth provider (overrides authType) |
516
+
517
+ ---
518
+
176
519
  ## Advanced Authentication
177
520
 
178
- ### Using IndexedDB (Recommended)
521
+ ### Using IndexedDB Storage (Recommended)
179
522
 
180
- For better security and performance, use the built-in `IndexedDBTokenStorage` instead of the default LocalStorage.
523
+ For better security and performance, use IndexedDB instead of LocalStorage:
181
524
 
182
525
  ```typescript
183
526
  import { PersSDK } from '@explorins/pers-sdk';
184
527
  import { IndexedDBTokenStorage } from '@explorins/pers-sdk/core';
528
+ import { BrowserFetchClientAdapter } from '@explorins/pers-sdk/platform-adapters';
185
529
 
186
- const sdk = new PersSDK(adapter, {
530
+ const sdk = new PersSDK(new BrowserFetchClientAdapter(), {
187
531
  environment: 'production',
188
532
  apiProjectKey: 'your-key',
189
- // Activates IndexedDB for tokens and keys
190
- authStorage: new IndexedDBTokenStorage()
533
+ authStorage: new IndexedDBTokenStorage() // Secure, async storage
191
534
  });
192
535
  ```
193
536
 
194
- ### Custom Storage & Fallbacks
537
+ ### Custom Storage Implementation
195
538
 
196
- You can implement your own storage strategy (e.g., hybrid Fallback) by implementing the `TokenStorage` interface. The SDK provides type-safe key constants.
539
+ Implement the `TokenStorage` interface for custom storage backends:
197
540
 
198
541
  ```typescript
199
- import { TokenStorage, AUTH_STORAGE_KEYS, DPOP_STORAGE_KEYS } from '@explorins/pers-sdk/core';
542
+ import type { TokenStorage } from '@explorins/pers-sdk/core';
543
+ import { AUTH_STORAGE_KEYS, DPOP_STORAGE_KEYS } from '@explorins/pers-sdk/core';
200
544
 
201
- class HybridStorage implements TokenStorage {
202
- // IMPORTANT: Set to 'false' if your storage backend only supports strings (like LocalStorage).
203
- // This ensures the SDK generates exportable keys that can be serialized.
204
- // Set to 'true' (like IndexedDB) to enable high-security non-extractable CryptoKey objects.
545
+ class CustomStorage implements TokenStorage {
546
+ // CRITICAL: Set to 'false' for string-only backends (LocalStorage-like)
547
+ // Set to 'true' for object-capable backends (IndexedDB-like)
205
548
  readonly supportsObjects = false;
206
549
 
207
- // Your custom implementation...
208
- // Use AUTH_STORAGE_KEYS.ACCESS_TOKEN, DPOP_STORAGE_KEYS.PRIVATE, etc.
550
+ async get(key: string): Promise<unknown | null> {
551
+ // Use AUTH_STORAGE_KEYS.ACCESS_TOKEN, DPOP_STORAGE_KEYS.PRIVATE, etc.
552
+ return yourBackend.get(key);
553
+ }
554
+
555
+ async set(key: string, value: unknown): Promise<void> {
556
+ await yourBackend.set(key, value);
557
+ }
558
+
559
+ async remove(key: string): Promise<void> {
560
+ await yourBackend.remove(key);
561
+ }
562
+
563
+ async clear(): Promise<void> {
564
+ await yourBackend.clear();
565
+ }
209
566
  }
210
567
  ```
211
568
 
569
+ ---
570
+
212
571
  ## Error Handling
213
572
 
573
+ The SDK provides structured error types for consistent error handling:
574
+
214
575
  ```typescript
215
- import { PersApiError } from '@explorins/pers-sdk/core';
576
+ import {
577
+ PersApiError,
578
+ AuthenticationError,
579
+ ErrorUtils
580
+ } from '@explorins/pers-sdk/core';
216
581
 
217
582
  try {
218
583
  const user = await sdk.auth.getCurrentUser();
219
584
  } catch (error) {
220
- if (error instanceof PersApiError) {
221
- console.error('PERS API Error:', error.message, error.statusCode);
585
+ // Check for specific error types
586
+ if (error instanceof AuthenticationError) {
587
+ // Handle authentication failure (401)
588
+ console.error('Auth failed:', error.message);
589
+ console.error('Endpoint:', error.endpoint);
590
+ console.error('User message:', error.userMessage);
591
+ // Redirect to login...
592
+
593
+ } else if (error instanceof PersApiError) {
594
+ // Handle general API errors
595
+ console.error('API Error:', error.message);
596
+ console.error('Status:', error.status);
597
+ console.error('Retryable:', error.retryable);
598
+
599
+ } else {
600
+ // Handle unexpected errors
601
+ console.error('Unexpected error:', error);
222
602
  }
223
603
  }
604
+
605
+ // Utility functions for error inspection
606
+ const status = ErrorUtils.getStatus(error); // Extract status code
607
+ const message = ErrorUtils.getMessage(error); // Extract error message
608
+ const retryable = ErrorUtils.isRetryable(error); // Check if retryable
224
609
  ```
225
610
 
611
+ ### Error Types Reference
612
+
613
+ | Error Class | Status | Use Case |
614
+ |-------------|--------|----------|
615
+ | `PersApiError` | Various | General API request failures |
616
+ | `AuthenticationError` | 401 | Authentication/authorization failures |
617
+ | `NetworkError` | - | Network connectivity issues |
618
+ | `TokenRefreshNeeded` | - | Internal: token refresh required |
619
+ | `LogoutRequired` | - | Internal: session invalidated |
620
+
621
+ ---
622
+
226
623
  ## Bundle Size
227
624
 
228
- - Core SDK: ~85 KB (minified)
229
- - Tree-shaking friendly
230
- - Zero external authentication dependencies
231
- - Native browser API implementation
625
+ - **Core SDK**: ~85 KB (minified)
626
+ - **Tree-shaking**: Fully supported - import only what you need
627
+ - **Zero runtime dependencies**: No RxJS, no heavy libraries in core
628
+ - **Native APIs**: Uses browser-native `fetch`, `crypto`, `IndexedDB`
232
629
 
233
- ## Documentation
630
+ ---
631
+
632
+ ## TypeScript Types
633
+
634
+ All domain interfaces are exported from `@explorins/pers-shared`. Import types directly for strong typing:
635
+
636
+ ```typescript
637
+ import type {
638
+ // User & Auth
639
+ UserDTO,
640
+ SessionAuthContextResponseDTO,
641
+
642
+ // Business
643
+ BusinessDTO,
644
+ BusinessTypeDTO,
645
+
646
+ // Campaigns
647
+ CampaignDTO,
648
+ CampaignClaimDTO,
649
+ CampaignClaimRequestDTO,
650
+
651
+ // Tokens
652
+ TokenDTO,
653
+ TokenMetadataDTO,
654
+
655
+ // Transactions
656
+ TransactionDTO,
657
+
658
+ // Redemptions
659
+ RedemptionDTO,
660
+ RedemptionRedeemDTO,
661
+
662
+ // Payments
663
+ PaymentIntentDTO,
664
+ PurchaseDTO,
665
+ PurchaseTokenDTO,
666
+
667
+ // Tenant
668
+ TenantDTO,
669
+ TenantClientConfigDTO
670
+ } from '@explorins/pers-shared';
671
+ ```
234
672
 
235
- For comprehensive documentation, examples, and advanced usage:
673
+ ### Key Interfaces Reference
674
+
675
+ | Domain | Interface | Description |
676
+ |--------|-----------|-------------|
677
+ | **Auth** | `UserDTO` | Authenticated user profile |
678
+ | **Auth** | `SessionAuthContextResponseDTO` | Login response with tokens + user/admin |
679
+ | **Business** | `BusinessDTO` | Business entity with details |
680
+ | **Business** | `BusinessTypeDTO` | Business category/type definition |
681
+ | **Campaign** | `CampaignDTO` | Campaign with rewards and rules |
682
+ | **Campaign** | `CampaignClaimDTO` | User's claim record |
683
+ | **Campaign** | `CampaignClaimRequestDTO` | Request body for claiming |
684
+ | **Token** | `TokenDTO` | Token type definition (credit, reward, status) |
685
+ | **Token** | `TokenMetadataDTO` | On-chain token metadata |
686
+ | **Transaction** | `TransactionDTO` | Transaction record |
687
+ | **Redemption** | `RedemptionDTO` | Redemption offer |
688
+ | **Redemption** | `RedemptionRedeemDTO` | Redemption result |
689
+ | **Payment** | `PaymentIntentDTO` | Stripe payment intent |
690
+ | **Payment** | `PurchaseDTO` | Purchase record |
691
+ | **Tenant** | `TenantDTO` | Tenant configuration |
692
+
693
+ ### Usage Example
236
694
 
237
- **[https://docs.pers.ninja/1.intro](https://docs.pers.ninja/1.intro)**
695
+ ```typescript
696
+ import { PersSDK } from '@explorins/pers-sdk';
697
+ import { BrowserFetchClientAdapter } from '@explorins/pers-sdk/platform-adapters';
698
+ import type { CampaignDTO, CampaignClaimRequestDTO } from '@explorins/pers-shared';
238
699
 
239
- For detailed API reference:
700
+ const sdk = new PersSDK(new BrowserFetchClientAdapter(), {
701
+ apiProjectKey: 'your-key'
702
+ });
703
+
704
+ // Type-safe campaign operations
705
+ const campaigns: CampaignDTO[] = await sdk.campaigns.getActiveCampaigns();
706
+
707
+ const claimRequest: CampaignClaimRequestDTO = {
708
+ campaignId: campaigns[0].id,
709
+ businessId: 'business-123'
710
+ };
711
+
712
+ const claim = await sdk.campaigns.claimCampaign(claimRequest);
713
+ ```
240
714
 
241
- **[https://docs.pers.ninja/sdk](https://docs.pers.ninja/sdk)** (Interactive API Documentation)
715
+ ---
716
+
717
+ ## Documentation
718
+
719
+ - **Getting Started Guide**: [https://docs.pers.ninja/1.intro](https://docs.pers.ninja/1.intro)
720
+ - **API Reference**: [https://docs.pers.ninja/sdk](https://docs.pers.ninja/sdk)
721
+ - **TypeDoc API Docs**: Generated with `npm run docs`
722
+
723
+ ---
242
724
 
243
725
  ## Related Packages
244
726
 
245
- - [@explorins/pers-sdk-react-native](https://www.npmjs.com/package/@explorins/pers-sdk-react-native) - React Native integration
246
- - [@explorins/pers-shared](https://www.npmjs.com/package/@explorins/pers-shared) - Shared types and utilities
727
+ | Package | Description |
728
+ |---------|-------------|
729
+ | [@explorins/pers-sdk-react-native](https://www.npmjs.com/package/@explorins/pers-sdk-react-native) | React Native integration with passkey support |
730
+ | [@explorins/pers-shared](https://www.npmjs.com/package/@explorins/pers-shared) | Shared types, interfaces, and DTOs |
731
+
732
+ ---
247
733
 
248
734
  ## License
249
735