@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 +582 -96
- package/dist/chunks/{explorer.utils-vHiCoUYQ.js → explorer.utils-DGmj4A0H.js} +3 -3
- package/dist/chunks/{explorer.utils-vHiCoUYQ.js.map → explorer.utils-DGmj4A0H.js.map} +1 -1
- package/dist/chunks/{explorer.utils-Bj4uQw83.cjs → explorer.utils-PMiqibed.cjs} +3 -3
- package/dist/chunks/{explorer.utils-Bj4uQw83.cjs.map → explorer.utils-PMiqibed.cjs.map} +1 -1
- package/dist/chunks/{pers-sdk-DnPahyZ8.js → pers-sdk--FbpI2jX.js} +2 -2
- package/dist/chunks/{pers-sdk-DnPahyZ8.js.map → pers-sdk--FbpI2jX.js.map} +1 -1
- package/dist/chunks/{pers-sdk-Dj8Hub94.cjs → pers-sdk-LxJOa3Ce.cjs} +2 -2
- package/dist/chunks/{pers-sdk-Dj8Hub94.cjs.map → pers-sdk-LxJOa3Ce.cjs.map} +1 -1
- package/dist/core.cjs +2 -2
- package/dist/core.js +2 -2
- package/dist/index.cjs +2 -2
- package/dist/index.js +2 -2
- package/dist/package.json +2 -2
- package/dist/web3/application/web3-application.service.d.ts +6 -2
- package/dist/web3/application/web3-application.service.d.ts.map +1 -1
- package/dist/web3/domain/services/contract-domain.service.d.ts +2 -2
- package/dist/web3/domain/services/contract-domain.service.d.ts.map +1 -1
- package/dist/web3/domain/services/token-domain.service.d.ts +6 -6
- package/dist/web3/domain/services/token-domain.service.d.ts.map +1 -1
- package/dist/web3/index.d.ts +1 -1
- package/dist/web3/index.d.ts.map +1 -1
- package/dist/web3.cjs +1 -1
- package/dist/web3.js +1 -1
- package/package.json +2 -2
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
|
|
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
|
|
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
|
|
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(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
66
|
-
|
|
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
|
-
###
|
|
215
|
+
### Node.js
|
|
216
|
+
|
|
217
|
+
**No additional dependencies required.**
|
|
72
218
|
|
|
73
219
|
```typescript
|
|
74
220
|
import { PersSDK } from '@explorins/pers-sdk';
|
|
75
|
-
import {
|
|
221
|
+
import { NodeHttpClientAdapter } from '@explorins/pers-sdk/platform-adapters';
|
|
76
222
|
|
|
77
|
-
const sdk = new PersSDK(new
|
|
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
|
-
###
|
|
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
|
-
|
|
87
|
-
import {
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
//
|
|
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.
|
|
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.
|
|
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
|
-
//
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
- User redemption tracking
|
|
147
|
-
- Multiple redemption types
|
|
420
|
+
// Get reward tokens
|
|
421
|
+
const rewards = await sdk.tokens.getRewardTokens();
|
|
148
422
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
|
|
468
|
+
const sdk = new PersSDK(new BrowserFetchClientAdapter(), {
|
|
469
|
+
// Environment: 'development' | 'staging' | 'production'
|
|
470
|
+
environment: 'production', // Default: 'production'
|
|
162
471
|
|
|
163
|
-
//
|
|
164
|
-
|
|
472
|
+
// Project key for API authentication (required)
|
|
473
|
+
apiProjectKey: 'your-project-key',
|
|
165
474
|
|
|
166
|
-
//
|
|
167
|
-
|
|
168
|
-
enabled: boolean;
|
|
169
|
-
};
|
|
475
|
+
// API version (currently only v2 supported)
|
|
476
|
+
apiVersion: 'v2', // Default: 'v2'
|
|
170
477
|
|
|
171
|
-
//
|
|
172
|
-
|
|
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
|
|
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(
|
|
530
|
+
const sdk = new PersSDK(new BrowserFetchClientAdapter(), {
|
|
187
531
|
environment: 'production',
|
|
188
532
|
apiProjectKey: 'your-key',
|
|
189
|
-
|
|
190
|
-
authStorage: new IndexedDBTokenStorage()
|
|
533
|
+
authStorage: new IndexedDBTokenStorage() // Secure, async storage
|
|
191
534
|
});
|
|
192
535
|
```
|
|
193
536
|
|
|
194
|
-
### Custom Storage
|
|
537
|
+
### Custom Storage Implementation
|
|
195
538
|
|
|
196
|
-
|
|
539
|
+
Implement the `TokenStorage` interface for custom storage backends:
|
|
197
540
|
|
|
198
541
|
```typescript
|
|
199
|
-
import { TokenStorage
|
|
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
|
|
202
|
-
//
|
|
203
|
-
//
|
|
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
|
-
|
|
208
|
-
|
|
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 {
|
|
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
|
-
|
|
221
|
-
|
|
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
|
|
229
|
-
- Tree-shaking
|
|
230
|
-
- Zero
|
|
231
|
-
- Native browser
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
246
|
-
|
|
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
|
|