@explorins/pers-sdk 2.1.21 → 2.1.24

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.
Files changed (122) hide show
  1. package/dist/business/api/business-api.d.ts +6 -9
  2. package/dist/business/api/business-api.d.ts.map +1 -1
  3. package/dist/business/index.d.ts +1 -0
  4. package/dist/business/index.d.ts.map +1 -1
  5. package/dist/business/services/business-service.d.ts +8 -5
  6. package/dist/business/services/business-service.d.ts.map +1 -1
  7. package/dist/business.cjs +1 -1
  8. package/dist/business.js +1 -1
  9. package/dist/campaign/api/campaign-api.d.ts +21 -14
  10. package/dist/campaign/api/campaign-api.d.ts.map +1 -1
  11. package/dist/campaign/index.d.ts +2 -1
  12. package/dist/campaign/index.d.ts.map +1 -1
  13. package/dist/campaign/models/index.d.ts +16 -6
  14. package/dist/campaign/models/index.d.ts.map +1 -1
  15. package/dist/campaign/services/campaign-service.d.ts +16 -23
  16. package/dist/campaign/services/campaign-service.d.ts.map +1 -1
  17. package/dist/campaign.cjs +36 -16
  18. package/dist/campaign.cjs.map +1 -1
  19. package/dist/campaign.js +36 -16
  20. package/dist/campaign.js.map +1 -1
  21. package/dist/chunks/{business-membership-service-BfHzIQlc.cjs → business-membership-service-DXLG5fP9.cjs} +17 -2
  22. package/dist/chunks/business-membership-service-DXLG5fP9.cjs.map +1 -0
  23. package/dist/chunks/{business-membership-service-CFa-TI39.js → business-membership-service-IyY5CkL0.js} +17 -2
  24. package/dist/chunks/business-membership-service-IyY5CkL0.js.map +1 -0
  25. package/dist/chunks/{index-DgTEdUgC.js → index-8y63MFOX.js} +28 -16
  26. package/dist/chunks/index-8y63MFOX.js.map +1 -0
  27. package/dist/chunks/{index-CGaKfZNU.cjs → index-CVuttuU8.cjs} +27 -14
  28. package/dist/chunks/{index-CGaKfZNU.cjs.map → index-CVuttuU8.cjs.map} +1 -1
  29. package/dist/chunks/{pers-sdk-DHohtBN8.cjs → pers-sdk-DXCcAgUS.cjs} +385 -96
  30. package/dist/chunks/pers-sdk-DXCcAgUS.cjs.map +1 -0
  31. package/dist/chunks/{pers-sdk-BTLsI3bU.js → pers-sdk-DkCRHY5i.js} +385 -96
  32. package/dist/chunks/pers-sdk-DkCRHY5i.js.map +1 -0
  33. package/dist/chunks/{redemption-service-OY_JjwCL.cjs → redemption-service-5Mu78Sne.cjs} +60 -8
  34. package/dist/chunks/redemption-service-5Mu78Sne.cjs.map +1 -0
  35. package/dist/chunks/{redemption-service-CoyjUi8C.js → redemption-service-CoODony4.js} +60 -8
  36. package/dist/chunks/redemption-service-CoODony4.js.map +1 -0
  37. package/dist/chunks/{tenant-manager-B4FygDMF.cjs → tenant-manager-D3toTiB9.cjs} +21 -3
  38. package/dist/chunks/{tenant-manager-B4FygDMF.cjs.map → tenant-manager-D3toTiB9.cjs.map} +1 -1
  39. package/dist/chunks/{tenant-manager-DkWkZfCF.js → tenant-manager-D8-eD2CZ.js} +21 -3
  40. package/dist/chunks/{tenant-manager-DkWkZfCF.js.map → tenant-manager-D8-eD2CZ.js.map} +1 -1
  41. package/dist/chunks/{tenant-service-Ch-V3mj-.cjs → tenant-service-8vZWmTLV.cjs} +16 -1
  42. package/dist/chunks/tenant-service-8vZWmTLV.cjs.map +1 -0
  43. package/dist/chunks/{tenant-service-BnTAZCxS.js → tenant-service-DlhdZAs9.js} +16 -1
  44. package/dist/chunks/tenant-service-DlhdZAs9.js.map +1 -0
  45. package/dist/chunks/{web3-chain-service-DcLiy3m2.cjs → web3-chain-service-CSxlvjMg.cjs} +2 -2
  46. package/dist/chunks/{web3-chain-service-DcLiy3m2.cjs.map → web3-chain-service-CSxlvjMg.cjs.map} +1 -1
  47. package/dist/chunks/{web3-chain-service-nGntR60S.js → web3-chain-service-DRoykR1u.js} +2 -2
  48. package/dist/chunks/{web3-chain-service-nGntR60S.js.map → web3-chain-service-DRoykR1u.js.map} +1 -1
  49. package/dist/chunks/{web3-manager-DRkj7s5C.js → web3-manager-DZXBaBh0.js} +4 -4
  50. package/dist/chunks/{web3-manager-DRkj7s5C.js.map → web3-manager-DZXBaBh0.js.map} +1 -1
  51. package/dist/chunks/{web3-manager-msPdWhlR.cjs → web3-manager-ojRB6_ty.cjs} +4 -4
  52. package/dist/chunks/{web3-manager-msPdWhlR.cjs.map → web3-manager-ojRB6_ty.cjs.map} +1 -1
  53. package/dist/core/auth/api/auth-api.d.ts +37 -2
  54. package/dist/core/auth/api/auth-api.d.ts.map +1 -1
  55. package/dist/core/auth/services/auth-service.d.ts +24 -3
  56. package/dist/core/auth/services/auth-service.d.ts.map +1 -1
  57. package/dist/core/errors/index.d.ts +26 -13
  58. package/dist/core/errors/index.d.ts.map +1 -1
  59. package/dist/core/events/event-emitter.d.ts +13 -1
  60. package/dist/core/events/event-emitter.d.ts.map +1 -1
  61. package/dist/core/events/event-types.d.ts +11 -0
  62. package/dist/core/events/event-types.d.ts.map +1 -1
  63. package/dist/core/pers-config.d.ts +13 -0
  64. package/dist/core/pers-config.d.ts.map +1 -1
  65. package/dist/core.cjs +7 -6
  66. package/dist/core.cjs.map +1 -1
  67. package/dist/core.js +6 -6
  68. package/dist/index.cjs +7 -6
  69. package/dist/index.cjs.map +1 -1
  70. package/dist/index.d.ts +2 -2
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +6 -6
  73. package/dist/managers/auth-manager.d.ts +61 -3
  74. package/dist/managers/auth-manager.d.ts.map +1 -1
  75. package/dist/managers/business-manager.d.ts +4 -4
  76. package/dist/managers/business-manager.d.ts.map +1 -1
  77. package/dist/managers/campaign-manager.d.ts +49 -49
  78. package/dist/managers/campaign-manager.d.ts.map +1 -1
  79. package/dist/managers/events-manager.d.ts.map +1 -1
  80. package/dist/managers/index.d.ts +1 -0
  81. package/dist/managers/index.d.ts.map +1 -1
  82. package/dist/managers/redemption-manager.d.ts +25 -3
  83. package/dist/managers/redemption-manager.d.ts.map +1 -1
  84. package/dist/managers/tenant-manager.d.ts +16 -0
  85. package/dist/managers/tenant-manager.d.ts.map +1 -1
  86. package/dist/node.cjs +6 -6
  87. package/dist/node.js +6 -6
  88. package/dist/package.json +2 -2
  89. package/dist/pers-sdk.d.ts +12 -6
  90. package/dist/pers-sdk.d.ts.map +1 -1
  91. package/dist/redemption/api/redemption-api.d.ts +30 -11
  92. package/dist/redemption/api/redemption-api.d.ts.map +1 -1
  93. package/dist/redemption/index.d.ts +2 -1
  94. package/dist/redemption/index.d.ts.map +1 -1
  95. package/dist/redemption/models/index.d.ts +17 -3
  96. package/dist/redemption/models/index.d.ts.map +1 -1
  97. package/dist/redemption/services/redemption-service.d.ts +18 -14
  98. package/dist/redemption/services/redemption-service.d.ts.map +1 -1
  99. package/dist/redemption.cjs +1 -1
  100. package/dist/redemption.js +1 -1
  101. package/dist/tenant/api/tenant-api.d.ts +7 -0
  102. package/dist/tenant/api/tenant-api.d.ts.map +1 -1
  103. package/dist/tenant/services/tenant-service.d.ts +4 -0
  104. package/dist/tenant/services/tenant-service.d.ts.map +1 -1
  105. package/dist/tenant.cjs +1 -1
  106. package/dist/tenant.js +1 -1
  107. package/dist/web3-chain.cjs +2 -2
  108. package/dist/web3-chain.js +2 -2
  109. package/dist/web3-manager.cjs +5 -5
  110. package/dist/web3-manager.js +5 -5
  111. package/dist/web3.cjs +5 -5
  112. package/dist/web3.js +5 -5
  113. package/package.json +2 -2
  114. package/dist/chunks/business-membership-service-BfHzIQlc.cjs.map +0 -1
  115. package/dist/chunks/business-membership-service-CFa-TI39.js.map +0 -1
  116. package/dist/chunks/index-DgTEdUgC.js.map +0 -1
  117. package/dist/chunks/pers-sdk-BTLsI3bU.js.map +0 -1
  118. package/dist/chunks/pers-sdk-DHohtBN8.cjs.map +0 -1
  119. package/dist/chunks/redemption-service-CoyjUi8C.js.map +0 -1
  120. package/dist/chunks/redemption-service-OY_JjwCL.cjs.map +0 -1
  121. package/dist/chunks/tenant-service-BnTAZCxS.js.map +0 -1
  122. package/dist/chunks/tenant-service-Ch-V3mj-.cjs.map +0 -1
@@ -1,14 +1,14 @@
1
1
  import { AccountOwnerType, MembershipRole, WebhookMethod, WebhookExecutionStatus } from '@explorins/pers-shared';
2
- import { i as isTokenExpired, E as ErrorUtils, A as AuthenticationError, b as PersApiError } from './index-DgTEdUgC.js';
2
+ import { i as isTokenExpired, E as ErrorUtils, A as AuthenticationError, b as PersApiError } from './index-8y63MFOX.js';
3
3
  import { UserService, UserApi } from '../user.js';
4
4
  import { createUserStatusSDK } from '../user-status.js';
5
5
  import { a as TokenService, T as TokenApi } from './token-service-BxEO5YVN.js';
6
- import { B as BusinessApi, b as BusinessService, a as BusinessMembershipApi, c as BusinessMembershipService } from './business-membership-service-CFa-TI39.js';
6
+ import { B as BusinessApi, b as BusinessService, a as BusinessMembershipApi, c as BusinessMembershipService } from './business-membership-service-IyY5CkL0.js';
7
7
  import { CampaignService, CampaignApi } from '../campaign.js';
8
- import { a as RedemptionService, R as RedemptionApi } from './redemption-service-CoyjUi8C.js';
8
+ import { a as RedemptionService, R as RedemptionApi } from './redemption-service-CoODony4.js';
9
9
  import { a as TransactionService, T as TransactionApi } from './transaction-request.builder-BZ6Uq6Qe.js';
10
10
  import { a as PaymentService, P as PurchaseApi } from './payment-service-IvM6rryM.js';
11
- import { T as TenantManager } from './tenant-manager-DkWkZfCF.js';
11
+ import { T as TenantManager } from './tenant-manager-D8-eD2CZ.js';
12
12
  import { b as buildPaginationParams, n as normalizeToPaginated } from './pagination-utils-9vQ-Npkr.js';
13
13
  import { a as AnalyticsService, A as AnalyticsApi } from './analytics-service-vm7B7LhS.js';
14
14
  import { DonationService, DonationApi } from '../donation.js';
@@ -30,7 +30,8 @@ const DEFAULT_PERS_CONFIG = {
30
30
  retries: 3,
31
31
  tokenRefreshMargin: 60, // Refresh tokens 60 seconds before expiry
32
32
  backgroundRefreshThreshold: 30, // Use background refresh if >30s remaining
33
- captureWalletEvents: true // Auto-connect to wallet events after auth
33
+ captureWalletEvents: true, // Auto-connect to wallet events after auth
34
+ autoRestoreSession: true // Auto-restore session from stored tokens on init
34
35
  };
35
36
  /**
36
37
  * Build the API root URL based on config
@@ -97,11 +98,28 @@ class AuthApi {
97
98
  }
98
99
  /**
99
100
  * Login tenant admin with JWT
101
+ *
102
+ * Authenticates an admin in a tenant context.
103
+ *
104
+ * @param jwt - Authentication token (Firebase JWT)
105
+ * @param options - Tenant authentication options (tenantId for multi-tenant admins)
106
+ * @returns Session response with tenant context
107
+ * @throws MultipleContextSelectionError when tenantId is required but not provided
108
+ *
109
+ * @example
110
+ * ```typescript
111
+ * // Single tenant - auto-selects
112
+ * const response = await authApi.loginTenantAdmin(jwt);
113
+ *
114
+ * // Multiple tenants - explicit selection
115
+ * const response = await authApi.loginTenantAdmin(jwt, { tenantId: 'tenant-123' });
116
+ * ```
100
117
  */
101
- async loginTenantAdmin(jwt) {
118
+ async loginTenantAdmin(jwt, options) {
102
119
  const body = {
103
120
  authToken: jwt,
104
- authType: AccountOwnerType.TENANT
121
+ authType: AccountOwnerType.TENANT,
122
+ context: options?.tenantId ? { tenantId: options.tenantId } : undefined
105
123
  };
106
124
  return this.apiClient.post(`${this.basePath}/token`, body, { bypassAuth: true });
107
125
  }
@@ -159,6 +177,30 @@ class AuthApi {
159
177
  async refreshAccessToken(refreshToken) {
160
178
  return this.apiClient.post(`${this.basePath}/refresh`, { refreshToken }, { bypassAuth: true, isRefreshRequest: true });
161
179
  }
180
+ // ==========================================
181
+ // IDENTITY VERIFICATION (for session restore)
182
+ // Note: These duplicate calls in domain APIs (user-api, business-api)
183
+ // but are kept here to avoid circular dependencies during initialization.
184
+ // If endpoints change, update both locations.
185
+ // ==========================================
186
+ /**
187
+ * Get current authenticated user
188
+ */
189
+ async getCurrentUser() {
190
+ return this.apiClient.get('/users/me');
191
+ }
192
+ /**
193
+ * Get current business context
194
+ */
195
+ async getCurrentBusiness() {
196
+ return this.apiClient.get('/businesses/me');
197
+ }
198
+ /**
199
+ * Get current admin context
200
+ */
201
+ async getCurrentAdmin() {
202
+ return this.apiClient.get('/admins/me');
203
+ }
162
204
  }
163
205
 
164
206
  /**
@@ -183,6 +225,12 @@ var AuthStatus;
183
225
  AuthStatus["SESSION_RESTORATION_FAILED"] = "session_restoration_failed";
184
226
  })(AuthStatus || (AuthStatus = {}));
185
227
 
228
+ /**
229
+ * Type guard to check if provider implements extended storage methods
230
+ */
231
+ function isExtendedProvider(provider) {
232
+ return 'setAuthType' in provider && typeof provider.setAuthType === 'function';
233
+ }
186
234
  /**
187
235
  * Platform-agnostic authentication service
188
236
  * Handles login, token refresh, and storage operations
@@ -194,6 +242,12 @@ class AuthService {
194
242
  this.activeRefreshPromise = null;
195
243
  this.currentAuthStatus = AuthStatus.UNAUTHENTICATED;
196
244
  }
245
+ /**
246
+ * Get extended provider if available, null otherwise
247
+ */
248
+ get extendedProvider() {
249
+ return this.authProvider && isExtendedProvider(this.authProvider) ? this.authProvider : null;
250
+ }
197
251
  /**
198
252
  * Emit auth status change to the app
199
253
  */
@@ -201,9 +255,10 @@ class AuthService {
201
255
  if (this.currentAuthStatus === status)
202
256
  return; // No change
203
257
  this.currentAuthStatus = status;
204
- if (this.authProvider && typeof this.authProvider.onAuthStatusChange === 'function') {
258
+ const extended = this.extendedProvider;
259
+ if (extended?.onAuthStatusChange) {
205
260
  try {
206
- await this.authProvider.onAuthStatusChange(status);
261
+ await extended.onAuthStatusChange(status);
207
262
  }
208
263
  catch (error) {
209
264
  console.warn('[AuthService] Auth status change callback failed:', error);
@@ -215,9 +270,14 @@ class AuthService {
215
270
  // ==========================================
216
271
  /**
217
272
  * Login tenant admin with JWT
273
+ *
274
+ * @param jwt - Authentication token (Firebase JWT)
275
+ * @param options - Tenant authentication options (tenantId for multi-tenant admins)
276
+ * @returns Session response with tenant context
277
+ * @throws Error with code MULTIPLE_CONTEXT_SELECTION_REQUIRED when tenantId is required but not provided
218
278
  */
219
- async loginTenantAdmin(jwt) {
220
- const response = await this.authApi.loginTenantAdmin(jwt);
279
+ async loginTenantAdmin(jwt, options) {
280
+ const response = await this.authApi.loginTenantAdmin(jwt, options);
221
281
  if (this.authProvider && response.accessToken) {
222
282
  await this.storeTokens(response.accessToken, response.refreshToken, AccountOwnerType.TENANT, jwt);
223
283
  }
@@ -298,9 +358,13 @@ class AuthService {
298
358
  if (!tokenToUse) {
299
359
  throw new Error('No refresh token available for token refresh');
300
360
  }
361
+ // Get the current authType to preserve it after refresh
362
+ const extended = this.extendedProvider;
363
+ const currentAuthType = extended?.getAuthType ? await extended.getAuthType() ?? undefined : undefined;
301
364
  const response = await this.authApi.refreshAccessToken(tokenToUse);
302
365
  if (this.authProvider && response.accessToken) {
303
- await this.storeTokens(response.accessToken, response.refreshToken);
366
+ // Preserve the authType during refresh
367
+ await this.storeTokens(response.accessToken, response.refreshToken, currentAuthType);
304
368
  }
305
369
  return response;
306
370
  }
@@ -338,6 +402,27 @@ class AuthService {
338
402
  return !!token;
339
403
  }
340
404
  // ==========================================
405
+ // CONTEXT RETRIEVAL
406
+ // ==========================================
407
+ /**
408
+ * Get current authenticated user
409
+ */
410
+ async getCurrentUser() {
411
+ return this.authApi.getCurrentUser();
412
+ }
413
+ /**
414
+ * Get current business context
415
+ */
416
+ async getCurrentBusiness() {
417
+ return this.authApi.getCurrentBusiness();
418
+ }
419
+ /**
420
+ * Get current admin context
421
+ */
422
+ async getCurrentAdmin() {
423
+ return this.authApi.getCurrentAdmin();
424
+ }
425
+ // ==========================================
341
426
  // PRIVATE HELPERS
342
427
  // ==========================================
343
428
  /**
@@ -351,17 +436,18 @@ class AuthService {
351
436
  if (refreshToken) {
352
437
  await this.authProvider.setRefreshToken(refreshToken);
353
438
  }
354
- // Type-safe handling of extended token storage features
355
- const extendedProvider = this.authProvider;
356
- if (providerToken && extendedProvider.setProviderToken) {
357
- await extendedProvider.setProviderToken(providerToken);
358
- }
359
- if (authType && extendedProvider.setAuthType) {
360
- console.log('[AuthService] Storing auth type:', authType);
361
- await extendedProvider.setAuthType(authType);
439
+ // Handle optional extended storage methods
440
+ const extended = this.extendedProvider;
441
+ if (extended) {
442
+ if (providerToken && extended.setProviderToken) {
443
+ await extended.setProviderToken(providerToken);
444
+ }
445
+ if (authType && extended.setAuthType) {
446
+ await extended.setAuthType(authType);
447
+ }
362
448
  }
363
- else {
364
- console.warn('[AuthService] Auth type not stored - authType:', authType, 'has setAuthType:', !!extendedProvider.setAuthType);
449
+ else if (authType) {
450
+ console.warn('[AuthService] Auth type not stored - provider does not implement setAuthType');
365
451
  }
366
452
  // Emit authenticated status on successful token storage
367
453
  await this.emitAuthStatus(AuthStatus.AUTHENTICATED);
@@ -1401,6 +1487,7 @@ function generateEventId() {
1401
1487
  *
1402
1488
  * All events flow through one subscription point.
1403
1489
  * Optional filtering at subscription level.
1490
+ * Supports replay of last auth event for late subscribers.
1404
1491
  *
1405
1492
  * @example Basic Usage
1406
1493
  * ```typescript
@@ -1424,6 +1511,13 @@ function generateEventId() {
1424
1511
  * showNotification(event.userMessage);
1425
1512
  * }, { excludeDomains: ['validation'] });
1426
1513
  *
1514
+ * // Subscribe with replay - get last auth event if missed
1515
+ * sdk.events.subscribe((event) => {
1516
+ * if (event.type === 'session_restored') {
1517
+ * setUser(event.details.user);
1518
+ * }
1519
+ * }, { domains: ['authentication'], replay: true });
1520
+ *
1427
1521
  * // Cleanup
1428
1522
  * unsubscribe();
1429
1523
  * ```
@@ -1431,6 +1525,8 @@ function generateEventId() {
1431
1525
  let emitterInstanceCounter = 0;
1432
1526
  class PersEventEmitter {
1433
1527
  constructor() {
1528
+ // Store last auth event for replay to late subscribers
1529
+ this.lastAuthEvent = null;
1434
1530
  this.handlers = new Set();
1435
1531
  this._instanceId = ++emitterInstanceCounter;
1436
1532
  }
@@ -1441,7 +1537,7 @@ class PersEventEmitter {
1441
1537
  * Subscribe to events
1442
1538
  *
1443
1539
  * @param handler - Callback for matching events
1444
- * @param filter - Optional filter by domain and/or level
1540
+ * @param filter - Optional filter by domain and/or level. Set `replay: true` to receive last auth event if missed.
1445
1541
  * @returns Unsubscribe function
1446
1542
  *
1447
1543
  * @example All events
@@ -1465,10 +1561,35 @@ class PersEventEmitter {
1465
1561
  * confetti();
1466
1562
  * }, { domains: ['transaction'], levels: ['success'] });
1467
1563
  * ```
1564
+ *
1565
+ * @example Auth events with replay (catches session_restored even if emitted before subscription)
1566
+ * ```typescript
1567
+ * sdk.events.subscribe((event) => {
1568
+ * if (event.type === 'session_restored') {
1569
+ * const { user } = event.details;
1570
+ * setUser(user);
1571
+ * }
1572
+ * }, { domains: ['authentication'], replay: true });
1573
+ * ```
1468
1574
  */
1469
1575
  subscribe(handler, filter) {
1470
1576
  const filteredHandler = { handler, filter };
1471
1577
  this.handlers.add(filteredHandler);
1578
+ // If replay is requested and we have a cached auth event, replay it immediately
1579
+ if (filter?.replay && this.lastAuthEvent) {
1580
+ // Check if event matches the filter
1581
+ if (!filter || this.matchesFilter(this.lastAuthEvent, filter)) {
1582
+ // Use queueMicrotask to ensure handler runs after subscribe returns
1583
+ queueMicrotask(() => {
1584
+ try {
1585
+ handler(this.lastAuthEvent);
1586
+ }
1587
+ catch (error) {
1588
+ console.error('[PersEventEmitter] Replay handler error:', error);
1589
+ }
1590
+ });
1591
+ }
1592
+ }
1472
1593
  return () => this.handlers.delete(filteredHandler);
1473
1594
  }
1474
1595
  /**
@@ -1493,6 +1614,7 @@ class PersEventEmitter {
1493
1614
  * Emit a success event
1494
1615
  *
1495
1616
  * Domain is restricted to business domains only (Domain type).
1617
+ * Auth events (login_success, session_restored) are cached for replay to late subscribers.
1496
1618
  *
1497
1619
  * @param event - Success event data (id and timestamp auto-generated)
1498
1620
  * @returns The complete event object
@@ -1513,6 +1635,15 @@ class PersEventEmitter {
1513
1635
  id: generateEventId(),
1514
1636
  timestamp: Date.now()
1515
1637
  };
1638
+ // Cache auth events for replay to late subscribers
1639
+ if (event.domain === 'authentication' &&
1640
+ (event.type === 'login_success' || event.type === 'session_restored')) {
1641
+ this.lastAuthEvent = fullEvent;
1642
+ }
1643
+ // Clear cached auth on logout
1644
+ if (event.domain === 'authentication' && event.type === 'logout_success') {
1645
+ this.lastAuthEvent = null;
1646
+ }
1516
1647
  this.notifyHandlers(fullEvent);
1517
1648
  return fullEvent;
1518
1649
  }
@@ -1540,6 +1671,10 @@ class PersEventEmitter {
1540
1671
  id: generateEventId(),
1541
1672
  timestamp: Date.now()
1542
1673
  };
1674
+ // Clear cached auth on auth failure (session invalid)
1675
+ if (event.domain === 'authentication' && event.type === 'session_restoration_failed') {
1676
+ this.lastAuthEvent = null;
1677
+ }
1543
1678
  this.notifyHandlers(fullEvent);
1544
1679
  return fullEvent;
1545
1680
  }
@@ -1663,7 +1798,8 @@ class AuthManager {
1663
1798
  this.events?.emitSuccess({
1664
1799
  domain: 'authentication',
1665
1800
  type: 'login_success',
1666
- userMessage: 'Successfully logged in'
1801
+ userMessage: 'Successfully logged in',
1802
+ details: { user: result.user }
1667
1803
  });
1668
1804
  return result;
1669
1805
  }
@@ -1711,7 +1847,66 @@ class AuthManager {
1711
1847
  */
1712
1848
  async loginAsBusiness(jwtToken, options) {
1713
1849
  const authService = this.apiClient.getAuthService();
1714
- return authService.loginBusiness(jwtToken, options);
1850
+ const result = await authService.loginBusiness(jwtToken, options);
1851
+ this.events?.emitSuccess({
1852
+ domain: 'authentication',
1853
+ type: 'login_success',
1854
+ userMessage: 'Successfully logged in as business',
1855
+ details: { user: result.user, business: result.business }
1856
+ });
1857
+ return result;
1858
+ }
1859
+ /**
1860
+ * Login as tenant admin with JWT token
1861
+ *
1862
+ * Authenticates an admin in a tenant context.
1863
+ *
1864
+ * **Auto-Selection Behavior:**
1865
+ * - If admin has access to a single tenant, it's auto-selected
1866
+ * - If admin has access to multiple tenants and no tenantId is provided,
1867
+ * throws `MULTIPLE_CONTEXT_SELECTION_REQUIRED` error with available options
1868
+ *
1869
+ * @param jwtToken - JWT token from auth provider (Firebase, etc.)
1870
+ * @param options - Tenant authentication options (tenantId for multi-tenant admins)
1871
+ * @returns Promise resolving to authentication response with tenant context
1872
+ * @throws Error with code `MULTIPLE_CONTEXT_SELECTION_REQUIRED` when tenantId is needed
1873
+ *
1874
+ * @example Single Tenant Access
1875
+ * ```typescript
1876
+ * // Auto-selects the admin's only tenant
1877
+ * const result = await sdk.auth.loginAsTenant(jwt);
1878
+ * console.log('Tenant:', result.admin?.tenantId);
1879
+ * ```
1880
+ *
1881
+ * @example Multiple Tenant Access
1882
+ * ```typescript
1883
+ * try {
1884
+ * const result = await sdk.auth.loginAsTenant(jwt);
1885
+ * } catch (error) {
1886
+ * if (error.code === 'MULTIPLE_CONTEXT_SELECTION_REQUIRED') {
1887
+ * // Show tenant selector UI
1888
+ * const selectedId = await showTenantSelector(error.details.availableOptions);
1889
+ * const result = await sdk.auth.loginAsTenant(jwt, { tenantId: selectedId });
1890
+ * }
1891
+ * }
1892
+ * ```
1893
+ *
1894
+ * @example Direct Tenant Selection
1895
+ * ```typescript
1896
+ * const result = await sdk.auth.loginAsTenant(jwt, { tenantId: 'tenant-123' });
1897
+ * console.log('Authenticated as admin for tenant:', result.admin?.tenantId);
1898
+ * ```
1899
+ */
1900
+ async loginAsTenant(jwtToken, options) {
1901
+ const authService = this.apiClient.getAuthService();
1902
+ const result = await authService.loginTenantAdmin(jwtToken, options);
1903
+ this.events?.emitSuccess({
1904
+ domain: 'authentication',
1905
+ type: 'login_success',
1906
+ userMessage: 'Successfully logged in as tenant admin',
1907
+ details: { admin: result.admin }
1908
+ });
1909
+ return result;
1715
1910
  }
1716
1911
  /**
1717
1912
  * Get current business context
@@ -1729,7 +1924,27 @@ class AuthManager {
1729
1924
  * ```
1730
1925
  */
1731
1926
  async getCurrentBusiness() {
1732
- return this.apiClient.get('/businesses/me');
1927
+ const authService = this.apiClient.getAuthService();
1928
+ return authService.getCurrentBusiness();
1929
+ }
1930
+ /**
1931
+ * Get current admin context
1932
+ *
1933
+ * Retrieves the current admin data if authenticated as tenant admin.
1934
+ * Requires prior tenant authentication via {@link loginAsTenant}.
1935
+ *
1936
+ * @returns Promise resolving to current admin data
1937
+ * @throws {PersApiError} When not authenticated as tenant admin
1938
+ *
1939
+ * @example
1940
+ * ```typescript
1941
+ * const admin = await sdk.auth.getCurrentAdmin();
1942
+ * console.log('Current admin:', admin.email);
1943
+ * ```
1944
+ */
1945
+ async getCurrentAdmin() {
1946
+ const authService = this.apiClient.getAuthService();
1947
+ return authService.getCurrentAdmin();
1733
1948
  }
1734
1949
  /**
1735
1950
  * Login with raw user data
@@ -1773,7 +1988,8 @@ class AuthManager {
1773
1988
  * ```
1774
1989
  */
1775
1990
  async getCurrentUser() {
1776
- return this.apiClient.get('/users/me');
1991
+ const authService = this.apiClient.getAuthService();
1992
+ return authService.getCurrentUser();
1777
1993
  }
1778
1994
  /**
1779
1995
  * Check if user is authenticated
@@ -3575,7 +3791,7 @@ class CampaignManager {
3575
3791
  * Returns campaigns with pagination metadata for efficient data loading.
3576
3792
  * Intelligent access: Public gets active only, Business gets own campaigns, Admin gets all.
3577
3793
  *
3578
- * @param options - Pagination and filter options (page, limit, sortBy, sortOrder, active, tag, search, businessId, include)
3794
+ * @param options - Pagination and filter options (page, limit, sortBy, sortOrder, active, tag, search, businessId, startDate, endDate, include)
3579
3795
  * @returns Promise resolving to paginated campaigns with metadata
3580
3796
  *
3581
3797
  * @example
@@ -3605,18 +3821,22 @@ class CampaignManager {
3605
3821
  * active: true
3606
3822
  * });
3607
3823
  *
3608
- * // Get active campaigns sorted by creation date
3609
- * const activeCampaigns = await sdk.campaigns.getCampaigns({
3610
- * active: true,
3611
- * sortBy: 'createdAt',
3612
- * sortOrder: 'DESC',
3613
- * page: 1,
3614
- * limit: 25
3824
+ * // Filter by date range
3825
+ * const dateFiltered = await sdk.campaigns.getCampaigns({
3826
+ * startDate: new Date('2026-05-01'),
3827
+ * endDate: new Date('2026-12-31'),
3828
+ * active: true
3615
3829
  * });
3616
3830
  *
3617
- * // Include related data (trigger sources and businesses)
3831
+ * // Get campaigns with claim count
3832
+ * const withCounts = await sdk.campaigns.getCampaigns({
3833
+ * include: ['claimCount']
3834
+ * });
3835
+ * withCounts.data.forEach(c => console.log(`${c.name}: ${c.claimCount} claims`));
3836
+ *
3837
+ * // Include related data (trigger sources, businesses, and claim count)
3618
3838
  * const campaignsWithRelations = await sdk.campaigns.getCampaigns({
3619
- * include: ['triggerSources', 'businesses']
3839
+ * include: ['triggerSources', 'businesses', 'claimCount']
3620
3840
  * });
3621
3841
  * ```
3622
3842
  */
@@ -4067,58 +4287,52 @@ class CampaignManager {
4067
4287
  async deleteCampaignBusinessEngagement(campaignId, engagementId) {
4068
4288
  return this.campaignService.deleteCampaignBusinessEngagement(campaignId, engagementId);
4069
4289
  }
4070
- /**
4071
- * Admin: Get all campaign claims
4072
- *
4073
- * Retrieves all campaign claims across the system for comprehensive reporting
4074
- * and analytics. This operation requires administrator privileges and provides
4075
- * system-wide visibility into campaign performance and user engagement.
4076
- *
4077
- * @returns Promise resolving to array of all campaign claims
4078
- * @throws {PersApiError} When not authenticated as administrator
4079
- *
4080
- * @example
4081
- * ```typescript
4082
- * // Admin operation - get campaign performance data
4083
- * const allClaims = await sdk.campaigns.getCampaignClaims();
4084
- *
4085
- * console.log(`Campaign Performance Report:`);
4086
- * console.log(`Total claims: ${allClaims.length}`);
4087
- *
4088
- * // Analyze claims by campaign
4089
- * const claimsByCampaign = allClaims.reduce((acc, claim) => {
4090
- * const campaignId = claim.campaignId;
4091
- * acc[campaignId] = (acc[campaignId] || 0) + 1;
4092
- * return acc;
4093
- * }, {});
4094
- *
4095
- * console.log('\nClaims by Campaign:');
4096
- * Object.entries(claimsByCampaign).forEach(([campaignId, count]) => {
4097
- * console.log(`${campaignId}: ${count} claims`);
4098
- * });
4099
- * ```
4100
- */
4101
4290
  /**
4102
4291
  * Admin: Get campaign claims with optional filters
4103
4292
  *
4104
- * Retrieves campaign claims with optional filtering by campaign, user, or business.
4293
+ * Retrieves campaign claims with optional filtering by campaign, user, business, or date range.
4105
4294
  * This operation requires administrator privileges and provides system-wide
4106
4295
  * visibility into campaign performance and user engagement.
4107
4296
  *
4108
4297
  * @param filters - Optional filters and pagination options
4298
+ * @param filters.campaignId - Filter by specific campaign ID
4299
+ * @param filters.userId - Filter by specific user ID
4300
+ * @param filters.businessId - Filter by specific business ID
4301
+ * @param filters.dateFrom - Filter claims from this date (inclusive)
4302
+ * @param filters.dateTo - Filter claims until this date (inclusive)
4303
+ * @param filters.page - Page number for pagination
4304
+ * @param filters.limit - Items per page
4305
+ * @param filters.sortBy - Field to sort by
4306
+ * @param filters.sortOrder - Sort direction ('asc' or 'desc')
4307
+ * @param include - Optional relations to include for enrichment
4109
4308
  * @returns Promise resolving to paginated campaign claims
4110
4309
  * @throws {PersApiError} When not authenticated as administrator
4111
4310
  *
4112
- * @example
4311
+ * @example Get All Claims
4312
+ * ```typescript
4313
+ * const { data: allClaims, pagination } = await sdk.campaigns.getCampaignClaims();
4314
+ * console.log(`Total: ${pagination.total}`);
4315
+ * ```
4316
+ *
4317
+ * @example Filter by User
4113
4318
  * ```typescript
4114
- * // Get all claims
4115
- * const allClaims = await sdk.campaigns.getCampaignClaims();
4319
+ * const { data: userClaims } = await sdk.campaigns.getCampaignClaims({ userId: 'user-123' });
4320
+ * ```
4116
4321
  *
4117
- * // Get claims for specific user
4118
- * const userClaims = await sdk.campaigns.getCampaignClaims({ userId: 'user-123' });
4322
+ * @example Filter by Date Range
4323
+ * ```typescript
4324
+ * // Get claims within a specific date range
4325
+ * const { data: monthClaims } = await sdk.campaigns.getCampaignClaims({
4326
+ * dateFrom: new Date('2024-01-01'),
4327
+ * dateTo: new Date('2024-01-31'),
4328
+ * limit: 100
4329
+ * });
4330
+ * console.log(`${monthClaims.length} claims in January 2024`);
4331
+ * ```
4119
4332
  *
4120
- * // Get claims for specific campaign with pagination
4121
- * const page1 = await sdk.campaigns.getCampaignClaims({
4333
+ * @example With Pagination and Campaign Filter
4334
+ * ```typescript
4335
+ * const { data: page1 } = await sdk.campaigns.getCampaignClaims({
4122
4336
  * campaignId: 'campaign-456',
4123
4337
  * page: 1,
4124
4338
  * limit: 50
@@ -4723,9 +4937,19 @@ class RedemptionManager {
4723
4937
  *
4724
4938
  * Retrieves all redemption redeems across the platform with filtering capabilities.
4725
4939
  * This is an admin-level operation that allows monitoring and analytics of redemption
4726
- * activity. Supports filtering by user, redemption offer, and enrichment of related entities.
4727
- *
4728
- * @param filters - Filter options (userId, redemptionId, pagination)
4940
+ * activity. Supports filtering by user, redemption offer, date range, and enrichment of related entities.
4941
+ *
4942
+ * @param filters - Filter options (userId, redemptionId, businessId, status, dateFrom, dateTo, pagination)
4943
+ * @param filters.userId - Filter by specific user ID
4944
+ * @param filters.redemptionId - Filter by specific redemption offer ID
4945
+ * @param filters.businessId - Filter by specific business ID
4946
+ * @param filters.status - Filter by redeem status
4947
+ * @param filters.dateFrom - Filter redeems from this date (inclusive)
4948
+ * @param filters.dateTo - Filter redeems until this date (inclusive)
4949
+ * @param filters.page - Page number for pagination
4950
+ * @param filters.limit - Items per page
4951
+ * @param filters.sortBy - Field to sort by
4952
+ * @param filters.sortOrder - Sort direction ('asc' or 'desc')
4729
4953
  * @param include - Optional relations to include for enrichment
4730
4954
  * @returns Promise resolving to paginated list of redemption redeems
4731
4955
  * @throws {PersApiError} When not authenticated as admin
@@ -4750,6 +4974,18 @@ class RedemptionManager {
4750
4974
  * console.log(`User has ${userRedeems.length} redemptions`);
4751
4975
  * ```
4752
4976
  *
4977
+ * @example Filter by Date Range
4978
+ * ```typescript
4979
+ * // Get redeems within a specific date range
4980
+ * const { data: recentRedeems } = await sdk.redemptions.getRedemptionRedeems({
4981
+ * dateFrom: new Date('2024-01-01'),
4982
+ * dateTo: new Date('2024-01-31'),
4983
+ * limit: 100
4984
+ * });
4985
+ *
4986
+ * console.log(`${recentRedeems.length} redeems in January 2024`);
4987
+ * ```
4988
+ *
4753
4989
  * @example With Enriched Data
4754
4990
  * ```typescript
4755
4991
  * const { data: redeems } = await sdk.redemptions.getRedemptionRedeems(
@@ -8686,7 +8922,8 @@ class WalletEventsManager {
8686
8922
  }
8687
8923
  // Save subscriptions for auto-resubscribe on reconnect
8688
8924
  this.lastSubscriptions.wallets = wallets;
8689
- return this.client.subscribeWallets(wallets);
8925
+ const result = await this.client.subscribeWallets(wallets);
8926
+ return result;
8690
8927
  }
8691
8928
  /**
8692
8929
  * Subscribe to chain events (Admin Dashboard)
@@ -8709,7 +8946,8 @@ class WalletEventsManager {
8709
8946
  }
8710
8947
  // Save subscriptions for auto-resubscribe on reconnect
8711
8948
  this.lastSubscriptions.chains = chains;
8712
- return this.client.subscribeChains(chains);
8949
+ const result = await this.client.subscribeChains(chains);
8950
+ return result;
8713
8951
  }
8714
8952
  /**
8715
8953
  * Unsubscribe from wallet events
@@ -9019,6 +9257,24 @@ class PersSDK {
9019
9257
  this.apiClient.setEvents(this._events);
9020
9258
  // Auto-connect to wallet events on successful login (if enabled)
9021
9259
  this.setupWalletEventsAutoConnect();
9260
+ // Auto-restore session from stored tokens (if enabled, default: true)
9261
+ this.setupAutoRestoreSession();
9262
+ }
9263
+ /**
9264
+ * Setup automatic session restoration from stored tokens
9265
+ * @internal
9266
+ */
9267
+ setupAutoRestoreSession() {
9268
+ const config = this.apiClient.getConfig();
9269
+ // Check if autoRestoreSession is enabled (default: true)
9270
+ if (config.autoRestoreSession === false) {
9271
+ return;
9272
+ }
9273
+ // Fire-and-forget: restore session asynchronously
9274
+ // Events will be emitted on success/failure
9275
+ this.restoreSession().catch(() => {
9276
+ // Error already emitted via session_restoration_failed event
9277
+ });
9022
9278
  }
9023
9279
  /**
9024
9280
  * Setup auto-connect for wallet events on authentication
@@ -9096,22 +9352,23 @@ class PersSDK {
9096
9352
  /**
9097
9353
  * Restore user session from stored tokens
9098
9354
  *
9099
- * Call this method after SDK initialization to restore the user's session
9100
- * if valid tokens exist. This is useful for maintaining login state across
9101
- * app restarts.
9355
+ * **Note:** This method is called automatically on SDK initialization when
9356
+ * `autoRestoreSession` is enabled (default: true). You only need to call this
9357
+ * manually if you disabled auto-restore or need to force a session refresh.
9358
+ *
9359
+ * Validates stored tokens and fetches user data to restore the session.
9360
+ * Emits `session_restored` event on success, `session_restoration_failed` on error.
9102
9361
  *
9103
9362
  * **Important:** Only works for USER and BUSINESS accounts. Admin/tenant
9104
9363
  * accounts don't support user data fetching, so this will return null for them
9105
9364
  * (though their tokens remain valid for API calls).
9106
9365
  *
9107
- * Emits auth domain success event when session is restored.
9108
- *
9109
9366
  * @returns Promise resolving to User data if session restored, null if no session or admin account
9110
9367
  * @throws {PersError} If token validation or user fetch fails
9111
9368
  *
9112
9369
  * @example
9113
9370
  * ```typescript
9114
- * // Call after initial render for better perceived performance
9371
+ * // Manual restore (only needed if autoRestoreSession: false)
9115
9372
  * const user = await sdk.restoreSession();
9116
9373
  * if (user) {
9117
9374
  * console.log('Welcome back,', user.name);
@@ -9125,25 +9382,57 @@ class PersSDK {
9125
9382
  }
9126
9383
  // Check auth type - only restore session for user and business accounts
9127
9384
  const authProvider = this.apiClient.getConfig().authProvider;
9128
- if (authProvider?.getAuthType) {
9129
- const authType = await authProvider.getAuthType();
9130
- if (authType === AccountOwnerType.TENANT) {
9131
- // Admin sessions don't support getCurrentUser(), skip restoration
9132
- // Tokens are valid and will be used for API calls
9385
+ const authType = authProvider?.getAuthType ? await authProvider.getAuthType() : AccountOwnerType.USER;
9386
+ if (authType === AccountOwnerType.TENANT) {
9387
+ // Ensure token is valid (refresh if expired) before fetching admin
9388
+ try {
9389
+ await this.auth.ensureValidToken();
9390
+ // Fetch current admin data
9391
+ const adminData = await this.auth.getCurrentAdmin();
9392
+ // Emit session restored for tenant admin
9393
+ this._events.emitSuccess({
9394
+ type: 'session_restored',
9395
+ domain: 'authentication',
9396
+ userMessage: 'Admin session restored successfully',
9397
+ details: { admin: adminData }
9398
+ });
9133
9399
  return null;
9134
9400
  }
9401
+ catch (error) {
9402
+ await this.auth.clearAuth();
9403
+ this._events.emitError({
9404
+ type: 'session_restoration_failed',
9405
+ domain: 'authentication',
9406
+ userMessage: 'Admin session restoration failed',
9407
+ code: 'SESSION_INVALID',
9408
+ details: { error }
9409
+ });
9410
+ throw error;
9411
+ }
9135
9412
  }
9136
9413
  try {
9137
9414
  // Ensure token is valid (refresh if expired) before fetching user
9138
9415
  await this.auth.ensureValidToken();
9139
- // Fetch user data to restore session
9416
+ // For BUSINESS auth, only fetch business context (no access to /users/me)
9417
+ if (authType === AccountOwnerType.BUSINESS) {
9418
+ const businessData = await this.auth.getCurrentBusiness();
9419
+ // Emit event with business data (no user data for business auth)
9420
+ this._events.emitSuccess({
9421
+ type: 'session_restored',
9422
+ domain: 'authentication',
9423
+ userMessage: 'Business session restored successfully',
9424
+ details: { business: businessData }
9425
+ });
9426
+ return null; // No user data for business auth
9427
+ }
9428
+ // For USER auth, fetch user data
9140
9429
  const userData = await this.auth.getCurrentUser();
9141
- // Emit event through proper event emitter
9430
+ // Emit event with user data
9142
9431
  this._events.emitSuccess({
9143
9432
  type: 'session_restored',
9144
9433
  domain: 'authentication',
9145
9434
  userMessage: 'Session restored successfully',
9146
- details: { userId: userData.id }
9435
+ details: { user: userData }
9147
9436
  });
9148
9437
  return userData;
9149
9438
  }
@@ -9648,4 +9937,4 @@ function createPersSDK(httpClient, config) {
9648
9937
  }
9649
9938
 
9650
9939
  export { AuthStatus as A, BusinessManager as B, CampaignManager as C, DefaultAuthProvider as D, FileApi as E, FileManager as F, FileService as G, ApiKeyApi as H, WebhookApi as I, WebhookService as J, PersEventsClient as K, LocalStorageTokenStorage as L, MemoryTokenStorage as M, createPersEventsClient as N, PersSDK as P, RedemptionManager as R, SDK_NAME as S, TokenManager as T, UserManager as U, WebDPoPCryptoProvider as W, AuthTokenManager as a, AUTH_STORAGE_KEYS as b, createPersSDK as c, DPOP_STORAGE_KEYS as d, SDK_VERSION as e, SDK_USER_AGENT as f, PersApiClient as g, DEFAULT_PERS_CONFIG as h, buildApiRoot as i, buildWalletEventsWsUrl as j, StaticJwtAuthProvider as k, AuthApi as l, mergeWithDefaults as m, AuthService as n, DPoPManager as o, PersEventEmitter as p, AuthManager as q, UserStatusManager as r, TransactionManager as s, PurchaseManager as t, ApiKeyManager as u, AnalyticsManager as v, DonationManager as w, TriggerSourceManager as x, WebhookManager as y, WalletEventsManager as z };
9651
- //# sourceMappingURL=pers-sdk-BTLsI3bU.js.map
9940
+ //# sourceMappingURL=pers-sdk-DkCRHY5i.js.map