@explorins/pers-sdk 2.1.2 → 2.1.4

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 (108) hide show
  1. package/dist/analytics/api/analytics-api.d.ts +175 -1
  2. package/dist/analytics/api/analytics-api.d.ts.map +1 -1
  3. package/dist/analytics/models/index.d.ts +2 -5
  4. package/dist/analytics/models/index.d.ts.map +1 -1
  5. package/dist/analytics/services/analytics-service.d.ts +32 -1
  6. package/dist/analytics/services/analytics-service.d.ts.map +1 -1
  7. package/dist/analytics.cjs +9 -44
  8. package/dist/analytics.cjs.map +1 -1
  9. package/dist/analytics.js +2 -45
  10. package/dist/analytics.js.map +1 -1
  11. package/dist/campaign/api/campaign-api.d.ts +59 -4
  12. package/dist/campaign/api/campaign-api.d.ts.map +1 -1
  13. package/dist/campaign/services/campaign-service.d.ts +49 -7
  14. package/dist/campaign/services/campaign-service.d.ts.map +1 -1
  15. package/dist/campaign.cjs +150 -14
  16. package/dist/campaign.cjs.map +1 -1
  17. package/dist/campaign.js +150 -14
  18. package/dist/campaign.js.map +1 -1
  19. package/dist/chunks/analytics-service-B9IfG6ox.js +271 -0
  20. package/dist/chunks/analytics-service-B9IfG6ox.js.map +1 -0
  21. package/dist/chunks/analytics-service-DwkeBB08.cjs +274 -0
  22. package/dist/chunks/analytics-service-DwkeBB08.cjs.map +1 -0
  23. package/dist/chunks/{pers-sdk-DnLw822h.js → pers-sdk-CAM0iQyK.js} +1203 -267
  24. package/dist/chunks/pers-sdk-CAM0iQyK.js.map +1 -0
  25. package/dist/chunks/{pers-sdk-D5lE9ZFW.cjs → pers-sdk-Di_R6AiT.cjs} +1207 -268
  26. package/dist/chunks/pers-sdk-Di_R6AiT.cjs.map +1 -0
  27. package/dist/chunks/{redemption-service-D-hBqh42.js → redemption-service-CQtTLdic.js} +32 -10
  28. package/dist/chunks/redemption-service-CQtTLdic.js.map +1 -0
  29. package/dist/chunks/{redemption-service-rMB6T2W5.cjs → redemption-service-DsH7sRdv.cjs} +32 -10
  30. package/dist/chunks/redemption-service-DsH7sRdv.cjs.map +1 -0
  31. package/dist/chunks/{transaction-request.builder-C1vVVFto.js → transaction-request.builder-C8ahJYwi.js} +122 -70
  32. package/dist/chunks/transaction-request.builder-C8ahJYwi.js.map +1 -0
  33. package/dist/chunks/{transaction-request.builder-BpgtuMMq.cjs → transaction-request.builder-CkYd5bl6.cjs} +122 -70
  34. package/dist/chunks/transaction-request.builder-CkYd5bl6.cjs.map +1 -0
  35. package/dist/core/auth/auth-provider.interface.d.ts +1 -0
  36. package/dist/core/auth/auth-provider.interface.d.ts.map +1 -1
  37. package/dist/core/auth/default-auth-provider.d.ts +2 -0
  38. package/dist/core/auth/default-auth-provider.d.ts.map +1 -1
  39. package/dist/core/auth/refresh-manager.d.ts +2 -0
  40. package/dist/core/auth/refresh-manager.d.ts.map +1 -1
  41. package/dist/core/auth/services/auth-service.d.ts.map +1 -1
  42. package/dist/core/auth/token-storage.d.ts +2 -1
  43. package/dist/core/auth/token-storage.d.ts.map +1 -1
  44. package/dist/core/pers-api-client.d.ts.map +1 -1
  45. package/dist/core/pers-config.d.ts +0 -18
  46. package/dist/core/pers-config.d.ts.map +1 -1
  47. package/dist/core.cjs +5 -4
  48. package/dist/core.cjs.map +1 -1
  49. package/dist/core.js +4 -4
  50. package/dist/index.cjs +13 -6
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.d.ts +1 -0
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +5 -5
  55. package/dist/managers/analytics-manager.d.ts +165 -2
  56. package/dist/managers/analytics-manager.d.ts.map +1 -1
  57. package/dist/managers/campaign-manager.d.ts +180 -30
  58. package/dist/managers/campaign-manager.d.ts.map +1 -1
  59. package/dist/managers/index.d.ts +1 -0
  60. package/dist/managers/index.d.ts.map +1 -1
  61. package/dist/managers/redemption-manager.d.ts +52 -2
  62. package/dist/managers/redemption-manager.d.ts.map +1 -1
  63. package/dist/managers/transaction-manager.d.ts +66 -131
  64. package/dist/managers/transaction-manager.d.ts.map +1 -1
  65. package/dist/managers/trigger-source-manager.d.ts +194 -0
  66. package/dist/managers/trigger-source-manager.d.ts.map +1 -0
  67. package/dist/managers/user-manager.d.ts +38 -7
  68. package/dist/managers/user-manager.d.ts.map +1 -1
  69. package/dist/node.cjs +4 -4
  70. package/dist/node.js +4 -4
  71. package/dist/package.json +2 -2
  72. package/dist/pers-sdk.d.ts +68 -23
  73. package/dist/pers-sdk.d.ts.map +1 -1
  74. package/dist/redemption/api/redemption-api.d.ts +8 -4
  75. package/dist/redemption/api/redemption-api.d.ts.map +1 -1
  76. package/dist/redemption/services/redemption-service.d.ts +7 -3
  77. package/dist/redemption/services/redemption-service.d.ts.map +1 -1
  78. package/dist/redemption.cjs +1 -1
  79. package/dist/redemption.js +1 -1
  80. package/dist/transaction/api/transaction-api.d.ts +37 -42
  81. package/dist/transaction/api/transaction-api.d.ts.map +1 -1
  82. package/dist/transaction/models/index.d.ts +21 -0
  83. package/dist/transaction/models/index.d.ts.map +1 -1
  84. package/dist/transaction/services/transaction-service.d.ts +10 -15
  85. package/dist/transaction/services/transaction-service.d.ts.map +1 -1
  86. package/dist/transaction.cjs +1 -1
  87. package/dist/transaction.js +1 -1
  88. package/dist/trigger-source/api/trigger-source-api.d.ts +86 -0
  89. package/dist/trigger-source/api/trigger-source-api.d.ts.map +1 -0
  90. package/dist/trigger-source/index.d.ts +9 -0
  91. package/dist/trigger-source/index.d.ts.map +1 -0
  92. package/dist/trigger-source/services/trigger-source-service.d.ts +42 -0
  93. package/dist/trigger-source/services/trigger-source-service.d.ts.map +1 -0
  94. package/dist/user/api/user-api.d.ts +26 -1
  95. package/dist/user/api/user-api.d.ts.map +1 -1
  96. package/dist/user/services/user-service.d.ts +3 -1
  97. package/dist/user/services/user-service.d.ts.map +1 -1
  98. package/dist/user.cjs +34 -4
  99. package/dist/user.cjs.map +1 -1
  100. package/dist/user.js +34 -4
  101. package/dist/user.js.map +1 -1
  102. package/package.json +2 -2
  103. package/dist/chunks/pers-sdk-D5lE9ZFW.cjs.map +0 -1
  104. package/dist/chunks/pers-sdk-DnLw822h.js.map +0 -1
  105. package/dist/chunks/redemption-service-D-hBqh42.js.map +0 -1
  106. package/dist/chunks/redemption-service-rMB6T2W5.cjs.map +0 -1
  107. package/dist/chunks/transaction-request.builder-BpgtuMMq.cjs.map +0 -1
  108. package/dist/chunks/transaction-request.builder-C1vVVFto.js.map +0 -1
@@ -7,12 +7,12 @@ var userStatus = require('../user-status.cjs');
7
7
  var tokenService = require('./token-service-BlbXrxnS.cjs');
8
8
  var businessMembershipService = require('./business-membership-service-8KC_qRj7.cjs');
9
9
  var campaign = require('../campaign.cjs');
10
- var redemptionService = require('./redemption-service-rMB6T2W5.cjs');
11
- var transactionRequest_builder = require('./transaction-request.builder-BpgtuMMq.cjs');
10
+ var redemptionService = require('./redemption-service-DsH7sRdv.cjs');
11
+ var transactionRequest_builder = require('./transaction-request.builder-CkYd5bl6.cjs');
12
12
  var paymentService = require('./payment-service-Bkw7ZXev.cjs');
13
13
  var tenantService = require('./tenant-service-fj-pkXTw.cjs');
14
14
  var paginationUtils = require('./pagination-utils-B2jRHMSO.cjs');
15
- var analytics = require('../analytics.cjs');
15
+ var analyticsService = require('./analytics-service-DwkeBB08.cjs');
16
16
  var donation = require('../donation.cjs');
17
17
 
18
18
  /**
@@ -30,8 +30,7 @@ const DEFAULT_PERS_CONFIG = {
30
30
  timeout: 30000,
31
31
  retries: 3,
32
32
  tokenRefreshMargin: 60, // Refresh tokens 60 seconds before expiry
33
- backgroundRefreshThreshold: 30, // Use background refresh if >30s remaining
34
- autoRestoreSession: true // Automatically restore session on initialization
33
+ backgroundRefreshThreshold: 30 // Use background refresh if >30s remaining
35
34
  };
36
35
  /**
37
36
  * Internal function to construct API root from environment
@@ -341,8 +340,12 @@ class AuthService {
341
340
  await extendedProvider.setProviderToken(providerToken);
342
341
  }
343
342
  if (authType && extendedProvider.setAuthType) {
343
+ console.log('[AuthService] Storing auth type:', authType);
344
344
  await extendedProvider.setAuthType(authType);
345
345
  }
346
+ else {
347
+ console.warn('[AuthService] Auth type not stored - authType:', authType, 'has setAuthType:', !!extendedProvider.setAuthType);
348
+ }
346
349
  // Emit authenticated status on successful token storage
347
350
  await this.emitAuthStatus(exports.AuthStatus.AUTHENTICATED);
348
351
  }
@@ -361,8 +364,15 @@ class TokenRefreshManager {
361
364
  this.authService = authService;
362
365
  this.authProvider = authProvider;
363
366
  this.tokenRefreshMarginSeconds = 120; // 2 minutes
367
+ this.lastValidationTime = 0;
368
+ this.validationCacheDurationMs = 30000; // 30 seconds
364
369
  }
365
370
  async ensureValidToken() {
371
+ const now = Date.now();
372
+ // Skip validation if we checked recently (within cache duration)
373
+ if (now - this.lastValidationTime < this.validationCacheDurationMs) {
374
+ return;
375
+ }
366
376
  try {
367
377
  const token = await this.authProvider.getToken();
368
378
  if (!token) {
@@ -373,6 +383,14 @@ class TokenRefreshManager {
373
383
  if (!refreshSuccess) {
374
384
  await this.authService.handleAuthFailure();
375
385
  }
386
+ else {
387
+ // Update validation time on successful refresh
388
+ this.lastValidationTime = now;
389
+ }
390
+ }
391
+ else {
392
+ // Token is valid, update validation time
393
+ this.lastValidationTime = now;
376
394
  }
377
395
  }
378
396
  catch (error) {
@@ -456,42 +474,77 @@ class MemoryTokenStorage {
456
474
  }
457
475
  }
458
476
  /**
459
- * Token manager for authentication tokens
477
+ * Token manager for authentication tokens with memory caching
460
478
  */
461
479
  class AuthTokenManager {
462
480
  constructor(storage = new LocalStorageTokenStorage()) {
463
481
  this.storage = storage;
482
+ this.cache = {};
464
483
  }
465
484
  async getAccessToken() {
485
+ // Return cached value if available
486
+ if (this.cache.accessToken !== undefined) {
487
+ return this.cache.accessToken;
488
+ }
466
489
  const val = await this.storage.get(AUTH_STORAGE_KEYS.ACCESS_TOKEN);
467
490
  // Ensure we return string for tokens
468
- return typeof val === 'string' ? val : null;
491
+ const token = typeof val === 'string' ? val : null;
492
+ this.cache.accessToken = token;
493
+ return token;
469
494
  }
470
495
  async setAccessToken(token) {
496
+ this.cache.accessToken = token;
471
497
  await this.storage.set(AUTH_STORAGE_KEYS.ACCESS_TOKEN, token);
472
498
  }
473
499
  async getRefreshToken() {
500
+ // Return cached value if available
501
+ if (this.cache.refreshToken !== undefined) {
502
+ return this.cache.refreshToken;
503
+ }
474
504
  const val = await this.storage.get(AUTH_STORAGE_KEYS.REFRESH_TOKEN);
475
- return typeof val === 'string' ? val : null;
505
+ const token = typeof val === 'string' ? val : null;
506
+ this.cache.refreshToken = token;
507
+ return token;
476
508
  }
477
509
  async setRefreshToken(token) {
510
+ this.cache.refreshToken = token;
478
511
  await this.storage.set(AUTH_STORAGE_KEYS.REFRESH_TOKEN, token);
479
512
  }
480
513
  async getProviderToken() {
514
+ // Return cached value if available
515
+ if (this.cache.providerToken !== undefined) {
516
+ return this.cache.providerToken;
517
+ }
481
518
  const val = await this.storage.get(AUTH_STORAGE_KEYS.PROVIDER_TOKEN);
482
- return typeof val === 'string' ? val : null;
519
+ const token = typeof val === 'string' ? val : null;
520
+ this.cache.providerToken = token;
521
+ return token;
483
522
  }
484
523
  async setProviderToken(token) {
524
+ this.cache.providerToken = token;
485
525
  await this.storage.set(AUTH_STORAGE_KEYS.PROVIDER_TOKEN, token);
486
526
  }
487
527
  async getAuthType() {
528
+ // Return cached value if available
529
+ if (this.cache.authType !== undefined) {
530
+ return this.cache.authType;
531
+ }
488
532
  const authType = await this.storage.get(AUTH_STORAGE_KEYS.AUTH_TYPE);
489
- return typeof authType === 'string' ? authType : null;
533
+ const type = typeof authType === 'string' ? authType : null;
534
+ this.cache.authType = type;
535
+ return type;
490
536
  }
491
537
  async setAuthType(authType) {
538
+ this.cache.authType = authType;
492
539
  await this.storage.set(AUTH_STORAGE_KEYS.AUTH_TYPE, authType);
493
540
  }
494
541
  async setTokens(accessToken, refreshToken, providerToken) {
542
+ // Update cache for all tokens
543
+ this.cache.accessToken = accessToken;
544
+ if (refreshToken)
545
+ this.cache.refreshToken = refreshToken;
546
+ if (providerToken)
547
+ this.cache.providerToken = providerToken;
495
548
  await this.setAccessToken(accessToken);
496
549
  if (refreshToken)
497
550
  await this.setRefreshToken(refreshToken);
@@ -499,13 +552,23 @@ class AuthTokenManager {
499
552
  await this.setProviderToken(providerToken);
500
553
  }
501
554
  async clearAllTokens() {
555
+ // Clear cache
556
+ this.cache = {};
502
557
  await this.storage.clear();
503
558
  }
504
559
  async hasAccessToken() {
560
+ // Use cached value if available to avoid storage read
561
+ if (this.cache.accessToken !== undefined) {
562
+ return !!this.cache.accessToken;
563
+ }
505
564
  const token = await this.getAccessToken();
506
565
  return !!token;
507
566
  }
508
567
  async hasRefreshToken() {
568
+ // Use cached value if available to avoid storage read
569
+ if (this.cache.refreshToken !== undefined) {
570
+ return !!this.cache.refreshToken;
571
+ }
509
572
  const token = await this.getRefreshToken();
510
573
  return !!token;
511
574
  }
@@ -733,6 +796,7 @@ class DPoPManager {
733
796
  class DefaultAuthProvider {
734
797
  constructor(config = {}) {
735
798
  this.config = config;
799
+ this.authTypeCache = null;
736
800
  this.authType = config.authType || persShared.AccountOwnerType.USER;
737
801
  const storage = config.storage || this.createStorage();
738
802
  this.tokenManager = new AuthTokenManager(storage);
@@ -793,6 +857,15 @@ class DefaultAuthProvider {
793
857
  }
794
858
  async setAccessToken(token) {
795
859
  await this.tokenManager.setAccessToken(token);
860
+ // Invalidate cache when token changes
861
+ this.authTypeCache = null;
862
+ // Eager DPoP key generation after login
863
+ if (this.dpopManager) {
864
+ // Fire and forget - generate keys in background
865
+ this.dpopManager.ensureKeyPair().catch(err => {
866
+ console.warn('[DefaultAuthProvider] DPoP key generation failed:', err);
867
+ });
868
+ }
796
869
  }
797
870
  async setRefreshToken(token) {
798
871
  await this.tokenManager.setRefreshToken(token);
@@ -802,16 +875,51 @@ class DefaultAuthProvider {
802
875
  }
803
876
  async clearTokens() {
804
877
  await this.tokenManager.clearAllTokens();
878
+ // Invalidate cache on clear
879
+ this.authTypeCache = null;
805
880
  if (this.dpopManager) {
806
881
  await this.dpopManager.clearKeys();
807
882
  }
808
883
  }
809
884
  async setTokens(accessToken, refreshToken, providerToken) {
810
885
  await this.tokenManager.setTokens(accessToken, refreshToken, providerToken);
886
+ // Invalidate cache when tokens change
887
+ this.authTypeCache = null;
811
888
  }
812
889
  async hasValidToken() {
813
890
  return this.tokenManager.hasAccessToken();
814
891
  }
892
+ async getAuthType() {
893
+ // Read from JWT instead of separate storage for single source of truth
894
+ const token = await this.tokenManager.getAccessToken();
895
+ if (!token) {
896
+ this.authTypeCache = null;
897
+ return null;
898
+ }
899
+ // Return cached result if token hasn't changed
900
+ if (this.authTypeCache && this.authTypeCache.token === token) {
901
+ return this.authTypeCache.type;
902
+ }
903
+ try {
904
+ // Decode JWT payload (without verification - we just need to read the claim)
905
+ const parts = token.split('.');
906
+ if (parts.length !== 3) {
907
+ console.warn('[DefaultAuthProvider] Invalid JWT format');
908
+ return null;
909
+ }
910
+ const payloadJson = atob(parts[1]);
911
+ const payload = JSON.parse(payloadJson);
912
+ // Use accountOwnerType from AuthJWTPayload interface
913
+ const authType = payload.accountType || null;
914
+ // Cache result with token signature
915
+ this.authTypeCache = { token, type: authType };
916
+ return authType;
917
+ }
918
+ catch (error) {
919
+ console.warn('[DefaultAuthProvider] Failed to parse auth type from JWT:', error);
920
+ return null;
921
+ }
922
+ }
815
923
  }
816
924
 
817
925
  /**
@@ -1006,13 +1114,15 @@ class PersApiClient {
1006
1114
  * @internal
1007
1115
  */
1008
1116
  emitErrorEvent(errorDetails, errorMessage, endpoint, method, status, error) {
1009
- console.log('[PersApiClient] emitErrorEvent called', {
1010
- hasEvents: !!this._events,
1011
- instanceId: this._events?.instanceId ?? 'none',
1012
- subscriberCount: this._events?.subscriberCount ?? 0,
1013
- domain: errorDetails.domain,
1014
- message: errorDetails.message || errorMessage
1015
- });
1117
+ /* console.log('[PersApiClient] emitErrorEvent called', {
1118
+ hasEvents: !!this._events,
1119
+ instanceId: this._events?.instanceId ?? 'none',
1120
+ subscriberCount: this._events?.subscriberCount ?? 0,
1121
+ domain: errorDetails.domain,
1122
+ code: errorDetails.code,
1123
+ status: status,
1124
+ message: errorDetails.message || errorMessage
1125
+ }); */
1016
1126
  this._events?.emitError({
1017
1127
  domain: errorDetails.domain || 'external',
1018
1128
  type: errorDetails.code || 'API_ERROR',
@@ -1975,26 +2085,57 @@ class UserManager {
1975
2085
  * requires administrator privileges and returns full user profiles including
1976
2086
  * private information.
1977
2087
  *
1978
- * @returns Promise resolving to array of all users with complete data
2088
+ * @param options - Pagination and sorting options
2089
+ * @param options.page - Page number (1-based, default: 1)
2090
+ * @param options.limit - Items per page (default: 50)
2091
+ * @param options.sortBy - Sort by field. Supported fields:
2092
+ * - 'id', 'email', 'identifierEmail', 'firstName', 'lastName'
2093
+ * - 'externalId', 'accountAddress', 'isActive'
2094
+ * - 'createdAt', 'updatedAt'
2095
+ * - Default: 'createdAt'
2096
+ * @param options.sortOrder - Sort order: SortOrder.ASC or SortOrder.DESC (default: DESC)
2097
+ * @param search - Optional search query to filter users
2098
+ * @returns Promise resolving to paginated users with complete data
1979
2099
  * @throws {PersApiError} When not authenticated as admin
1980
2100
  *
1981
- * @example
2101
+ * @example Basic Usage
1982
2102
  * ```typescript
1983
2103
  * // Admin operation - requires admin authentication
1984
2104
  * try {
1985
- * const allUsers = await sdk.users.getAllUsers();
1986
- * console.log(`Total users: ${allUsers.length}`);
2105
+ * const result = await sdk.users.getAllUsers();
2106
+ * console.log(`Total users: ${result.pagination.total}`);
1987
2107
  *
1988
- * allUsers.forEach(user => {
1989
- * console.log(`${user.name} - ${user.email} - Active: ${user.isActive}`);
2108
+ * result.data.forEach(user => {
2109
+ * console.log(`${user.firstName} - ${user.email} - Active: ${user.isActive}`);
1990
2110
  * });
1991
2111
  * } catch (error) {
1992
2112
  * console.log('Admin access required');
1993
2113
  * }
1994
2114
  * ```
2115
+ *
2116
+ * @example With Sorting
2117
+ * ```typescript
2118
+ * import { SortOrder } from '@explorins/pers-sdk';
2119
+ *
2120
+ * // Get users sorted by email ascending
2121
+ * const result = await sdk.users.getAllUsers({
2122
+ * page: 1,
2123
+ * limit: 20,
2124
+ * sortBy: 'email',
2125
+ * sortOrder: SortOrder.ASC
2126
+ * });
2127
+ *
2128
+ * // Get users sorted by creation date (newest first)
2129
+ * const recent = await sdk.users.getAllUsers({
2130
+ * page: 1,
2131
+ * limit: 10,
2132
+ * sortBy: 'createdAt',
2133
+ * sortOrder: SortOrder.DESC
2134
+ * });
2135
+ * ```
1995
2136
  */
1996
- async getAllUsers(options) {
1997
- return this.userService.getAllRemoteUsers(options);
2137
+ async getAllUsers(options, search) {
2138
+ return this.userService.getAllRemoteUsers(options, search);
1998
2139
  }
1999
2140
  /**
2000
2141
  * Business/Admin: Create or update a user
@@ -3159,6 +3300,7 @@ class CampaignManager {
3159
3300
  * business partnerships, eligibility criteria, and claiming requirements.
3160
3301
  *
3161
3302
  * @param campaignId - Unique campaign identifier
3303
+ * @param include - Relations to include: 'triggerSources', 'businesses'
3162
3304
  * @returns Promise resolving to campaign data with complete details
3163
3305
  * @throws {PersApiError} When campaign with specified ID is not found
3164
3306
  *
@@ -3187,9 +3329,17 @@ class CampaignManager {
3187
3329
  * console.log('Campaign not found:', error.message);
3188
3330
  * }
3189
3331
  * ```
3332
+ *
3333
+ * @example With Include Relations
3334
+ * ```typescript
3335
+ * // Get campaign with trigger sources and businesses included
3336
+ * const campaign = await sdk.campaigns.getCampaignById('campaign-123', ['triggerSources', 'businesses']);
3337
+ * console.log('Trigger sources:', campaign.included?.triggerSources);
3338
+ * console.log('Businesses:', campaign.included?.businesses);
3339
+ * ```
3190
3340
  */
3191
- async getCampaignById(campaignId) {
3192
- return this.campaignService.getCampaignById(campaignId);
3341
+ async getCampaignById(campaignId, include) {
3342
+ return this.campaignService.getCampaignById(campaignId, include);
3193
3343
  }
3194
3344
  /**
3195
3345
  * Claim a campaign reward
@@ -3334,6 +3484,11 @@ class CampaignManager {
3334
3484
  * page: 1,
3335
3485
  * limit: 25
3336
3486
  * });
3487
+ *
3488
+ * // Include related data (trigger sources and businesses)
3489
+ * const campaignsWithRelations = await sdk.campaigns.getCampaigns({
3490
+ * include: ['triggerSources', 'businesses']
3491
+ * });
3337
3492
  * ```
3338
3493
  */
3339
3494
  async getCampaigns(options) {
@@ -3451,57 +3606,188 @@ class CampaignManager {
3451
3606
  async toggleCampaignTestnet(campaignId) {
3452
3607
  return this.campaignService.toggleCampaignTestnet(campaignId);
3453
3608
  }
3609
+ // ==========================================
3610
+ // CAMPAIGN TRIGGER OPERATIONS
3611
+ // Rules & limits for campaign activation
3612
+ // ==========================================
3454
3613
  /**
3455
- * Admin: Get campaign triggers
3614
+ * Admin: Get all campaign triggers (paginated)
3456
3615
  *
3457
- * Retrieves all available campaign trigger mechanisms that can be used to
3458
- * automatically activate campaigns based on user actions or system events.
3459
- * Requires administrator privileges.
3616
+ * Retrieves all campaign trigger rules that define rate limits, geo-validation,
3617
+ * conditions, and trigger types for campaign activation.
3460
3618
  *
3461
- * @returns Promise resolving to array of campaign trigger definitions
3619
+ * @param options - Pagination options
3620
+ * @returns Promise resolving to paginated list of campaign triggers
3462
3621
  *
3463
3622
  * @example
3464
3623
  * ```typescript
3465
- * // Admin operation - view available triggers
3466
- * const triggers = await sdk.campaigns.getCampaignTriggers();
3467
- *
3468
- * console.log('Available Campaign Triggers:');
3469
- * triggers.forEach(trigger => {
3470
- * console.log(`- ${trigger.name}: ${trigger.description}`);
3471
- * console.log(` Type: ${trigger.type}`);
3472
- * console.log(` Parameters: ${JSON.stringify(trigger.parameters)}`);
3624
+ * const triggers = await sdk.campaigns.getCampaignTriggers({ page: 1, limit: 20 });
3625
+ * console.log(`Found ${triggers.total} triggers`);
3626
+ * triggers.data.forEach(trigger => {
3627
+ * console.log(`- ${trigger.name}: max ${trigger.maxPerDayPerUser}/day`);
3473
3628
  * });
3474
3629
  * ```
3475
3630
  */
3476
3631
  async getCampaignTriggers(options) {
3477
- return this.campaignService.getCampaignTriggers();
3632
+ return this.campaignService.getCampaignTriggers(options);
3633
+ }
3634
+ /**
3635
+ * Admin: Get campaign trigger by ID
3636
+ *
3637
+ * @param triggerId - The campaign trigger ID
3638
+ * @returns Promise resolving to the campaign trigger
3639
+ *
3640
+ * @example
3641
+ * ```typescript
3642
+ * const trigger = await sdk.campaigns.getCampaignTriggerById('trigger-123');
3643
+ * console.log('Max per day:', trigger.maxPerDayPerUser);
3644
+ * ```
3645
+ */
3646
+ async getCampaignTriggerById(triggerId) {
3647
+ return this.campaignService.getCampaignTriggerById(triggerId);
3648
+ }
3649
+ /**
3650
+ * Admin: Create a new campaign trigger
3651
+ *
3652
+ * Creates a trigger rule that defines rate limits, geo-validation, and conditions
3653
+ * for campaign activation. Triggers are created independently and then assigned
3654
+ * to campaigns via `setCampaignTrigger()`.
3655
+ *
3656
+ * @param data - Trigger configuration
3657
+ * @returns Promise resolving to created trigger
3658
+ *
3659
+ * @example
3660
+ * ```typescript
3661
+ * const trigger = await sdk.campaigns.createCampaignTrigger({
3662
+ * name: 'Daily Check-in',
3663
+ * maxPerDayPerUser: 1,
3664
+ * maxPerUser: 100,
3665
+ * minCooldownSeconds: 3600,
3666
+ * maxGeoDistanceInMeters: 50,
3667
+ * triggerType: 'CLAIM_BY_USER'
3668
+ * });
3669
+ *
3670
+ * // Then assign to campaign
3671
+ * await sdk.campaigns.setCampaignTrigger(campaignId, trigger.id);
3672
+ * ```
3673
+ */
3674
+ async createCampaignTrigger(data) {
3675
+ const result = await this.campaignService.createCampaignTrigger(data);
3676
+ this.events?.emitSuccess({
3677
+ domain: 'campaign',
3678
+ type: 'CAMPAIGN_TRIGGER_CREATED',
3679
+ userMessage: `Trigger "${data.name}" created successfully`,
3680
+ details: { triggerId: result.id, name: data.name }
3681
+ });
3682
+ return result;
3683
+ }
3684
+ /**
3685
+ * Admin: Update an existing campaign trigger
3686
+ *
3687
+ * @param triggerId - The campaign trigger ID
3688
+ * @param data - Updated trigger configuration (partial)
3689
+ * @returns Promise resolving to updated trigger
3690
+ *
3691
+ * @example
3692
+ * ```typescript
3693
+ * const updated = await sdk.campaigns.updateCampaignTrigger('trigger-123', {
3694
+ * maxPerDayPerUser: 5,
3695
+ * minCooldownSeconds: 1800
3696
+ * });
3697
+ * ```
3698
+ */
3699
+ async updateCampaignTrigger(triggerId, data) {
3700
+ const result = await this.campaignService.updateCampaignTrigger(triggerId, data);
3701
+ this.events?.emitSuccess({
3702
+ domain: 'campaign',
3703
+ type: 'CAMPAIGN_TRIGGER_UPDATED',
3704
+ userMessage: 'Trigger updated successfully',
3705
+ details: { triggerId, updates: Object.keys(data) }
3706
+ });
3707
+ return result;
3708
+ }
3709
+ /**
3710
+ * Admin: Delete a campaign trigger
3711
+ *
3712
+ * @param triggerId - The campaign trigger ID
3713
+ * @returns Promise resolving to success status
3714
+ *
3715
+ * @example
3716
+ * ```typescript
3717
+ * await sdk.campaigns.deleteCampaignTrigger('trigger-123');
3718
+ * ```
3719
+ */
3720
+ async deleteCampaignTrigger(triggerId) {
3721
+ const result = await this.campaignService.deleteCampaignTrigger(triggerId);
3722
+ this.events?.emitSuccess({
3723
+ domain: 'campaign',
3724
+ type: 'CAMPAIGN_TRIGGER_DELETED',
3725
+ userMessage: 'Trigger deleted successfully',
3726
+ details: { triggerId }
3727
+ });
3728
+ return result;
3478
3729
  }
3479
3730
  /**
3480
- * Admin: Set campaign trigger
3731
+ * Admin: Assign a trigger to a campaign
3481
3732
  *
3482
- * Associates a specific trigger mechanism with a campaign, enabling automatic
3483
- * campaign activation based on defined conditions. Requires administrator privileges.
3733
+ * Associates a trigger rule with a campaign. A campaign can have only one trigger
3734
+ * at a time. Assigning a new trigger replaces any existing trigger.
3484
3735
  *
3485
3736
  * @param campaignId - ID of the campaign
3486
3737
  * @param triggerId - ID of the trigger to associate
3487
- * @returns Promise resolving to updated campaign data
3488
- * @throws {PersApiError} When not authenticated as admin or entities not found
3738
+ * @returns Promise resolving to updated campaign
3489
3739
  *
3490
3740
  * @example
3491
3741
  * ```typescript
3492
- * // Admin operation - set up automatic campaign trigger
3493
3742
  * const updated = await sdk.campaigns.setCampaignTrigger(
3494
- * 'new-user-welcome',
3495
- * 'user-registration-trigger'
3743
+ * 'campaign-123',
3744
+ * 'trigger-456'
3496
3745
  * );
3497
- *
3498
- * console.log('Trigger set for campaign:', updated.title);
3499
- * console.log('Trigger will activate on user registration');
3746
+ * console.log('Trigger assigned:', updated.trigger?.name);
3500
3747
  * ```
3501
3748
  */
3502
3749
  async setCampaignTrigger(campaignId, triggerId) {
3503
- return this.campaignService.setCampaignTrigger(campaignId, triggerId);
3750
+ const result = await this.campaignService.setCampaignTrigger(campaignId, triggerId);
3751
+ this.events?.emitSuccess({
3752
+ domain: 'campaign',
3753
+ type: 'CAMPAIGN_TRIGGER_ASSIGNED',
3754
+ userMessage: 'Trigger assigned to campaign',
3755
+ details: { campaignId, triggerId }
3756
+ });
3757
+ return result;
3758
+ }
3759
+ /**
3760
+ * Admin: Remove a trigger from a campaign
3761
+ *
3762
+ * Removes the trigger rule from a campaign. The trigger itself is not deleted
3763
+ * and can be reassigned to other campaigns.
3764
+ *
3765
+ * @param campaignId - ID of the campaign
3766
+ * @param triggerId - ID of the trigger to remove
3767
+ * @returns Promise resolving to updated campaign
3768
+ *
3769
+ * @example
3770
+ * ```typescript
3771
+ * const updated = await sdk.campaigns.removeCampaignTrigger(
3772
+ * 'campaign-123',
3773
+ * 'trigger-456'
3774
+ * );
3775
+ * console.log('Trigger removed:', updated.trigger === null);
3776
+ * ```
3777
+ */
3778
+ async removeCampaignTrigger(campaignId, triggerId) {
3779
+ const result = await this.campaignService.removeCampaignTrigger(campaignId, triggerId);
3780
+ this.events?.emitSuccess({
3781
+ domain: 'campaign',
3782
+ type: 'CAMPAIGN_TRIGGER_REMOVED',
3783
+ userMessage: 'Trigger removed from campaign',
3784
+ details: { campaignId, triggerId }
3785
+ });
3786
+ return result;
3504
3787
  }
3788
+ // ==========================================
3789
+ // TOKEN UNIT OPERATIONS
3790
+ // ==========================================
3505
3791
  /**
3506
3792
  * Admin: Create campaign token unit
3507
3793
  *
@@ -3710,8 +3996,8 @@ class CampaignManager {
3710
3996
  * });
3711
3997
  * ```
3712
3998
  */
3713
- async getCampaignClaims(filters) {
3714
- return this.campaignService.getCampaignClaims(filters);
3999
+ async getCampaignClaims(filters, include) {
4000
+ return this.campaignService.getCampaignClaims(filters, include);
3715
4001
  }
3716
4002
  /**
3717
4003
  * Admin: Get campaign claims by user ID
@@ -3746,8 +4032,8 @@ class CampaignManager {
3746
4032
  * console.log(`\nTotal rewards earned: ${totalRewards}`);
3747
4033
  * ```
3748
4034
  */
3749
- async getCampaignClaimsByUserId(userId, options) {
3750
- return this.campaignService.getCampaignClaimsByUserId(userId);
4035
+ async getCampaignClaimsByUserId(userId, options, include) {
4036
+ return this.campaignService.getCampaignClaimsByUserId(userId, options, include);
3751
4037
  }
3752
4038
  /**
3753
4039
  * Admin: Get campaign claims by business ID
@@ -3787,8 +4073,79 @@ class CampaignManager {
3787
4073
  * console.log(`\nTotal rewards distributed: ${totalRewardsDistributed}`);
3788
4074
  * ```
3789
4075
  */
3790
- async getCampaignClaimsByBusinessId(businessId, options) {
3791
- return this.campaignService.getCampaignClaimsByBusinessId(businessId);
4076
+ async getCampaignClaimsByBusinessId(businessId, options, include) {
4077
+ return this.campaignService.getCampaignClaimsByBusinessId(businessId, options, include);
4078
+ }
4079
+ // ==========================================
4080
+ // TRIGGER SOURCE ASSIGNMENT
4081
+ // Note: TriggerSource CRUD is in TriggerSourceManager (sdk.triggerSources)
4082
+ // ==========================================
4083
+ /**
4084
+ * Admin: Assign a trigger source to a campaign
4085
+ *
4086
+ * Associates a trigger source with a campaign, enabling the trigger source
4087
+ * to activate campaign rewards when triggered. A campaign can have multiple
4088
+ * trigger sources. Requires administrator privileges.
4089
+ *
4090
+ * Note: To create/update/delete trigger sources, use `sdk.triggerSources`.
4091
+ *
4092
+ * @param campaignId - Campaign UUID
4093
+ * @param triggerSourceId - Trigger source UUID
4094
+ * @returns Promise resolving to updated campaign with trigger source assigned
4095
+ * @throws {PersApiError} When not authenticated as admin or entities not found
4096
+ *
4097
+ * @example
4098
+ * ```typescript
4099
+ * // Create trigger source first
4100
+ * const source = await sdk.triggerSources.create({
4101
+ * type: 'QR_CODE',
4102
+ * name: 'Store Entrance QR'
4103
+ * });
4104
+ *
4105
+ * // Then assign to campaign
4106
+ * const updated = await sdk.campaigns.assignTriggerSource(
4107
+ * 'campaign-123',
4108
+ * source.id
4109
+ * );
4110
+ *
4111
+ * console.log('Trigger source assigned:', updated.triggerSourceIds.length);
4112
+ * ```
4113
+ */
4114
+ async assignTriggerSource(campaignId, triggerSourceId) {
4115
+ const result = await this.campaignService.assignTriggerSourceToCampaign(campaignId, triggerSourceId);
4116
+ this.events?.emitSuccess({
4117
+ domain: 'campaign',
4118
+ type: 'TRIGGER_SOURCE_ASSIGNED',
4119
+ userMessage: 'Trigger source assigned to campaign',
4120
+ details: { campaignId, triggerSourceId }
4121
+ });
4122
+ return result;
4123
+ }
4124
+ /**
4125
+ * Admin: Remove a trigger source from a campaign
4126
+ *
4127
+ * Removes the association between a trigger source and a campaign. The trigger
4128
+ * source itself is not deleted and can be reassigned to other campaigns.
4129
+ * Requires administrator privileges.
4130
+ *
4131
+ * @param campaignId - Campaign UUID
4132
+ * @param triggerSourceId - Trigger source UUID
4133
+ * @returns Promise resolving to updated campaign with trigger source removed
4134
+ * @throws {PersApiError} When not authenticated as admin or entities not found
4135
+ *
4136
+ * @example
4137
+ * ```typescript
4138
+ * // Remove a trigger source from a campaign
4139
+ * const updated = await sdk.campaigns.removeTriggerSource(
4140
+ * 'campaign-123',
4141
+ * 'source-456'
4142
+ * );
4143
+ *
4144
+ * console.log('Remaining trigger source IDs:', updated.triggerSourceIds.length);
4145
+ * ```
4146
+ */
4147
+ async removeTriggerSource(campaignId, triggerSourceId) {
4148
+ return this.campaignService.removeTriggerSourceFromCampaign(campaignId, triggerSourceId);
3792
4149
  }
3793
4150
  /**
3794
4151
  * Get the full campaign service for advanced operations
@@ -4172,8 +4529,57 @@ class RedemptionManager {
4172
4529
  * });
4173
4530
  * ```
4174
4531
  */
4175
- async getUserRedemptions(options) {
4176
- return this.redemptionService.getUserRedeems(options);
4532
+ async getUserRedemptions(options, include) {
4533
+ return this.redemptionService.getUserRedeems(options, include);
4534
+ }
4535
+ /**
4536
+ * Admin: Get all redemption redeems with filtering and enriched data
4537
+ *
4538
+ * Retrieves all redemption redeems across the platform with filtering capabilities.
4539
+ * This is an admin-level operation that allows monitoring and analytics of redemption
4540
+ * activity. Supports filtering by user, redemption offer, and enrichment of related entities.
4541
+ *
4542
+ * @param filters - Filter options (userId, redemptionId, pagination)
4543
+ * @param include - Optional relations to include for enrichment
4544
+ * @returns Promise resolving to paginated list of redemption redeems
4545
+ * @throws {PersApiError} When not authenticated as admin
4546
+ *
4547
+ * @example Get All Redeems
4548
+ * ```typescript
4549
+ * // Admin operation - get all redemption redeems
4550
+ * const { data: allRedeems, pagination } = await sdk.redemptions.getRedemptionRedeems();
4551
+ *
4552
+ * console.log(`Total redeems: ${pagination.total}`);
4553
+ * console.log(`Page ${pagination.page} of ${pagination.pages}`);
4554
+ * ```
4555
+ *
4556
+ * @example Filter by User
4557
+ * ```typescript
4558
+ * // Get redeems for specific user
4559
+ * const { data: userRedeems } = await sdk.redemptions.getRedemptionRedeems({
4560
+ * userId: 'user-123',
4561
+ * limit: 50
4562
+ * });
4563
+ *
4564
+ * console.log(`User has ${userRedeems.length} redemptions`);
4565
+ * ```
4566
+ *
4567
+ * @example With Enriched Data
4568
+ * ```typescript
4569
+ * const { data: redeems } = await sdk.redemptions.getRedemptionRedeems(
4570
+ * { page: 1, limit: 20 },
4571
+ * ['redemption', 'user', 'business']
4572
+ * );
4573
+ *
4574
+ * redeems.forEach(redeem => {
4575
+ * const redemptionName = redeem.included?.redemption?.name || 'Unknown';
4576
+ * const userEmail = redeem.included?.user?.email || redeem.userId;
4577
+ * console.log(`${redemptionName} - ${userEmail}`);
4578
+ * });
4579
+ * ```
4580
+ */
4581
+ async getRedemptionRedeems(filters, include) {
4582
+ return this.redemptionService.getRedemptionRedeems(filters, include);
4177
4583
  }
4178
4584
  /**
4179
4585
  * Admin: Create new redemption offer
@@ -4416,8 +4822,8 @@ class RedemptionManager {
4416
4822
  *
4417
4823
  * @example Administrative Reporting
4418
4824
  * ```typescript
4419
- * // Admin: Get all tenant transactions for analysis
4420
- * const allTransactions = await sdk.transactions.getTenantTransactions();
4825
+ * // Admin: Get paginated transactions for analysis
4826
+ * const allTransactions = await sdk.transactions.getPaginatedTransactions({ page: 1, limit: 100 });
4421
4827
  *
4422
4828
  * // Export transaction data
4423
4829
  * const csvBlob = await sdk.transactions.exportTransactionsCSV();
@@ -4440,13 +4846,18 @@ class TransactionManager {
4440
4846
  * Provides complete transaction audit trail and verification data.
4441
4847
  *
4442
4848
  * @param transactionId - Unique transaction identifier
4849
+ * @param include - Optional relations to include (sender, recipient, business) for enriched entity data
4443
4850
  * @returns Promise resolving to complete transaction data
4444
4851
  * @throws {PersApiError} When transaction with specified ID is not found or access denied
4445
4852
  *
4446
4853
  * @example
4447
4854
  * ```typescript
4448
4855
  * try {
4449
- * const transaction = await sdk.transactions.getTransactionById('txn-abc123');
4856
+ * // Get transaction with enriched sender/recipient data
4857
+ * const transaction = await sdk.transactions.getTransactionById(
4858
+ * 'txn-abc123',
4859
+ * ['sender', 'recipient', 'business']
4860
+ * );
4450
4861
  *
4451
4862
  * console.log('Transaction Details:');
4452
4863
  * console.log('ID:', transaction.id);
@@ -4459,16 +4870,19 @@ class TransactionManager {
4459
4870
  * console.log('Description:', transaction.description);
4460
4871
  * }
4461
4872
  *
4462
- * if (transaction.business) {
4463
- * console.log('Business:', transaction.business.displayName);
4873
+ * // Access enriched sender data
4874
+ * if (transaction.included?.sender) {
4875
+ * console.log('Sender:', transaction.included.sender);
4464
4876
  * }
4465
4877
  *
4466
- * // Show token movements
4467
- * if (transaction.tokenTransfers?.length) {
4468
- * console.log('\nToken Transfers:');
4469
- * transaction.tokenTransfers.forEach(transfer => {
4470
- * console.log(`${transfer.amount} ${transfer.token.symbol} ${transfer.direction}`);
4471
- * });
4878
+ * // Access enriched recipient data
4879
+ * if (transaction.included?.recipient) {
4880
+ * console.log('Recipient:', transaction.included.recipient);
4881
+ * }
4882
+ *
4883
+ * // Access enriched business data
4884
+ * if (transaction.included?.engagedBusiness) {
4885
+ * console.log('Business:', transaction.included.engagedBusiness.displayName);
4472
4886
  * }
4473
4887
  *
4474
4888
  * // Show blockchain confirmation
@@ -4481,8 +4895,8 @@ class TransactionManager {
4481
4895
  * }
4482
4896
  * ```
4483
4897
  */
4484
- async getTransactionById(transactionId) {
4485
- return this.transactionService.getTransactionById(transactionId);
4898
+ async getTransactionById(transactionId, include) {
4899
+ return this.transactionService.getTransactionById(transactionId, include);
4486
4900
  }
4487
4901
  /**
4488
4902
  * Create a new transaction
@@ -4576,150 +4990,62 @@ class TransactionManager {
4576
4990
  /**
4577
4991
  * Get user's transaction history
4578
4992
  *
4579
- * Retrieves transaction history for the authenticated user, filtered by
4580
- * transaction role. Provides chronological view of all user's loyalty
4993
+ * Retrieves transaction history for the authenticated user with comprehensive
4994
+ * filtering options. Provides chronological view of all user's loyalty
4581
4995
  * activities including purchases, rewards, redemptions, and transfers.
4996
+ * Optionally enrich with related entities (sender, recipient, business).
4582
4997
  *
4583
- * @param role - Optional role filter (TransactionRole.SENDER, TransactionRole.RECIPIENT). If undefined, returns all user transactions
4584
- * @param limit - Maximum number of transactions to return (default: 1000)
4585
- * @returns Promise resolving to array of user's transactions
4998
+ * @param options - Query options including filters, pagination, and include relations
4999
+ * @returns Promise resolving to paginated transaction data with optional included entities
4586
5000
  *
4587
5001
  * @example All Transactions
4588
5002
  * ```typescript
4589
- * const allTransactions = await sdk.transactions.getUserTransactionHistory('ALL');
5003
+ * const result = await sdk.transactions.getUserTransactionHistory();
4590
5004
  *
4591
- * console.log(` Transaction History (${allTransactions.length} transactions):`);
5005
+ * console.log(`Transaction History (${result.data.length} of ${result.pagination.total} transactions)`);
4592
5006
  *
4593
- * allTransactions.forEach((transaction, index) => {
5007
+ * result.data.forEach((transaction, index) => {
4594
5008
  * const date = new Date(transaction.createdAt).toLocaleDateString();
4595
5009
  * console.log(`\n${index + 1}. ${transaction.type} - ${date}`);
4596
5010
  * console.log(` ${transaction.description || 'No description'}`);
4597
5011
  * console.log(` Status: ${transaction.status}`);
4598
- *
4599
- * if (transaction.amount && transaction.currency) {
4600
- * console.log(` Amount: ${transaction.amount} ${transaction.currency}`);
4601
- * }
4602
- *
4603
- * if (transaction.business) {
4604
- * console.log(` Business: ${transaction.business.displayName}`);
4605
- * }
4606
5012
  * });
4607
5013
  * ```
4608
5014
  *
4609
- * @example Filtered by Type
5015
+ * @example Filter by Role and Status
4610
5016
  * ```typescript
4611
- * // Get only purchase transactions
4612
- * const purchases = await sdk.transactions.getUserTransactionHistory('PURCHASE');
4613
- *
4614
- * let totalSpent = 0;
4615
- * let totalRewards = 0;
4616
- *
4617
- * purchases.forEach(purchase => {
4618
- * if (purchase.amount) {
4619
- * totalSpent += purchase.amount;
4620
- * }
4621
- *
4622
- * if (purchase.tokensEarned?.length) {
4623
- * purchase.tokensEarned.forEach(reward => {
4624
- * totalRewards += reward.amount;
4625
- * });
4626
- * }
5017
+ * // Get only completed sent transactions
5018
+ * const sent = await sdk.transactions.getUserTransactionHistory({
5019
+ * role: TransactionRole.SENDER,
5020
+ * status: TransactionStatus.COMPLETED,
5021
+ * include: ['recipient', 'business'],
5022
+ * page: 1,
5023
+ * limit: 50
4627
5024
  * });
4628
5025
  *
4629
- * console.log('Purchase Summary:');
4630
- * console.log(`Total purchases: ${purchases.length}`);
4631
- * console.log(`Total spent: $${totalSpent.toFixed(2)}`);
4632
- * console.log(`Total rewards earned: ${totalRewards} points`);
4633
- * ```
4634
- *
4635
- * @example Recent Activity
4636
- * ```typescript
4637
- * const recentTransactions = await sdk.transactions.getUserTransactionHistory('ALL');
4638
- *
4639
- * // Filter to last 30 days
4640
- * const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
4641
- * const recentActivity = recentTransactions.filter(t =>
4642
- * new Date(t.createdAt) > thirtyDaysAgo
4643
- * );
4644
- *
4645
- * console.log(`Recent Activity (${recentActivity.length} transactions in last 30 days):`);
4646
- *
4647
- * // Group by type
4648
- * const activityByType = recentActivity.reduce((acc, t) => {
4649
- * acc[t.type] = (acc[t.type] || 0) + 1;
4650
- * return acc;
4651
- * }, {});
4652
- *
4653
- * Object.entries(activityByType).forEach(([type, count]) => {
4654
- * console.log(`${type}: ${count} transactions`);
5026
+ * sent.data.forEach(tx => {
5027
+ * console.log(`Sent to: ${tx.included?.recipient?.displayName || tx.recipientAddress}`);
4655
5028
  * });
4656
5029
  * ```
4657
- */
4658
- async getUserTransactionHistory(role, options) {
4659
- return this.transactionService.getUserTransactionHistory(role, options);
4660
- }
4661
- /**
4662
- * Admin: Get all tenant transactions
4663
- *
4664
- * Retrieves all transactions across the entire tenant/organization for
4665
- * comprehensive reporting and analysis. This operation requires administrator
4666
- * privileges and provides system-wide transaction visibility.
4667
- *
4668
- * @param limit - Maximum number of transactions to return (default: 1000)
4669
- * @returns Promise resolving to array of all tenant transactions
4670
- * @throws {PersApiError} When not authenticated as administrator
4671
5030
  *
4672
- * @example
5031
+ * @example Filter by Trigger Process (Campaign/Redemption)
4673
5032
  * ```typescript
4674
- * // Admin operation - comprehensive transaction analysis
4675
- * const allTransactions = await sdk.transactions.getTenantTransactions();
4676
- *
4677
- * console.log(`Tenant Transaction Overview:`);
4678
- * console.log(`Total transactions: ${allTransactions.length}`);
4679
- *
4680
- * // Analyze by status
4681
- * const statusCounts = allTransactions.reduce((acc, t) => {
4682
- * acc[t.status] = (acc[t.status] || 0) + 1;
4683
- * return acc;
4684
- * }, {});
4685
- *
4686
- * console.log('\nBy status:');
4687
- * Object.entries(statusCounts).forEach(([status, count]) => {
4688
- * console.log(`${status}: ${count} transactions`);
5033
+ * // Get all transactions triggered by a specific campaign claim
5034
+ * const claimTxs = await sdk.transactions.getUserTransactionHistory({
5035
+ * triggerProcessId: 'claim-abc123',
5036
+ * include: ['sender', 'recipient', 'business']
4689
5037
  * });
4690
5038
  *
4691
- * // Analyze by type
4692
- * const typeCounts = allTransactions.reduce((acc, t) => {
4693
- * acc[t.type] = (acc[t.type] || 0) + 1;
4694
- * return acc;
4695
- * }, {});
4696
- *
4697
- * console.log('\nBy type:');
4698
- * Object.entries(typeCounts).forEach(([type, count]) => {
4699
- * console.log(`${type}: ${count} transactions`);
5039
+ * claimTxs.data.forEach(tx => {
5040
+ * console.log('Transaction from claim:', tx.id);
5041
+ * if (tx.included?.engagedBusiness) {
5042
+ * console.log('Business:', tx.included.engagedBusiness.displayName);
5043
+ * }
4700
5044
  * });
4701
- *
4702
- * // Calculate volume metrics
4703
- * const totalVolume = allTransactions.reduce((sum, t) =>
4704
- * sum + (t.amount || 0), 0
4705
- * );
4706
- *
4707
- * const avgTransactionSize = totalVolume / allTransactions.length;
4708
- *
4709
- * console.log('\nVolume metrics:');
4710
- * console.log(`Total volume: $${totalVolume.toFixed(2)}`);
4711
- * console.log(`Average transaction: $${avgTransactionSize.toFixed(2)}`);
4712
- *
4713
- * // Recent activity analysis
4714
- * const last24Hours = allTransactions.filter(t =>
4715
- * new Date(t.createdAt) > new Date(Date.now() - 24 * 60 * 60 * 1000)
4716
- * );
4717
- *
4718
- * console.log(`\n⏰ Last 24 hours: ${last24Hours.length} transactions`);
4719
5045
  * ```
4720
5046
  */
4721
- async getTenantTransactions(options) {
4722
- return this.transactionService.getTenantTransactions(options);
5047
+ async getUserTransactionHistory(options) {
5048
+ return this.transactionService.getUserTransactionHistory(options);
4723
5049
  }
4724
5050
  /**
4725
5051
  * Admin: Get paginated transactions
@@ -4783,9 +5109,23 @@ class TransactionManager {
4783
5109
  * console.log(`$${transaction.amount} - ${transaction.business?.displayName}`);
4784
5110
  * });
4785
5111
  * ```
5112
+ *
5113
+ * @example With Included Relations
5114
+ * ```typescript
5115
+ * // Include sender and recipient entities
5116
+ * const result = await sdk.transactions.getPaginatedTransactions(
5117
+ * { page: 1, limit: 50 },
5118
+ * ['sender', 'recipient', 'business']
5119
+ * );
5120
+ *
5121
+ * result.data.forEach(tx => {
5122
+ * if (tx.included?.sender) console.log('From:', tx.included.sender);
5123
+ * if (tx.included?.recipient) console.log('To:', tx.included.recipient);
5124
+ * });
5125
+ * ```
4786
5126
  */
4787
- async getPaginatedTransactions(params) {
4788
- return this.transactionService.getPaginatedTransactions(params);
5127
+ async getPaginatedTransactions(params, include) {
5128
+ return this.transactionService.getPaginatedTransactions(params, include);
4789
5129
  }
4790
5130
  /**
4791
5131
  * Admin: Export transactions as CSV
@@ -6262,8 +6602,8 @@ class ApiKeyManager {
6262
6602
  class AnalyticsManager {
6263
6603
  constructor(apiClient) {
6264
6604
  this.apiClient = apiClient;
6265
- const analyticsApi = new analytics.AnalyticsApi(apiClient);
6266
- this.analyticsService = new analytics.AnalyticsService(analyticsApi);
6605
+ const analyticsApi = new analyticsService.AnalyticsApi(apiClient);
6606
+ this.analyticsService = new analyticsService.AnalyticsService(analyticsApi);
6267
6607
  }
6268
6608
  /**
6269
6609
  * Get transaction analytics
@@ -6449,20 +6789,193 @@ class AnalyticsManager {
6449
6789
  return this.analyticsService.getTransactionAnalytics(request);
6450
6790
  }
6451
6791
  /**
6452
- * Get the full analytics service for advanced operations
6792
+ * Get campaign claim analytics with aggregation
6453
6793
  *
6454
- * Provides access to the complete AnalyticsService instance for advanced analytics
6455
- * operations, custom metrics, predictive analytics, cohort analysis, and
6456
- * operations not covered by the high-level manager methods.
6794
+ * Retrieves aggregated analytics for campaign claims with flexible grouping,
6795
+ * filtering, and metric selection. Provides insights into campaign performance,
6796
+ * claim patterns, and user engagement across the loyalty ecosystem.
6457
6797
  *
6458
- * @returns AnalyticsService instance with full API access
6798
+ * @param request - Analytics request with filters, groupBy, and metrics
6799
+ * @returns Promise resolving to campaign claim analytics data
6459
6800
  *
6460
- * @example Advanced Analytics Operations
6801
+ * @example Claims per campaign
6461
6802
  * ```typescript
6462
- * const analyticsService = sdk.analytics.getAnalyticsService();
6803
+ * const analytics = await sdk.analytics.getCampaignClaimAnalytics({
6804
+ * filters: { status: 'COMPLETED' },
6805
+ * groupBy: ['campaignId'],
6806
+ * metrics: ['count'],
6807
+ * sortBy: 'count',
6808
+ * sortOrder: 'DESC',
6809
+ * limit: 10
6810
+ * });
6463
6811
  *
6464
- * // Access user engagement analytics
6465
- * const engagementMetrics = await analyticsService.getUserEngagementMetrics({
6812
+ * console.log('Top campaigns:', analytics.results);
6813
+ * ```
6814
+ */
6815
+ async getCampaignClaimAnalytics(request) {
6816
+ return this.analyticsService.getCampaignClaimAnalytics(request);
6817
+ }
6818
+ /**
6819
+ * Get user analytics with engagement metrics
6820
+ *
6821
+ * Retrieves aggregated user statistics including engagement rate, active users,
6822
+ * transaction metrics, and per-active-user averages. Provides comprehensive
6823
+ * insights into user behavior, engagement patterns, and platform adoption metrics.
6824
+ *
6825
+ * NEW: Added per-active-user metrics (averageTransactionsPerActiveUser, etc.) which
6826
+ * show concentrated engagement among active users - more useful than diluted all-user averages.
6827
+ *
6828
+ * Request structure matches TransactionAnalytics and CampaignClaimAnalytics:
6829
+ * - Use filters object for business-specific scoping
6830
+ * - startDate/endDate at root level for date range filtering
6831
+ *
6832
+ * @param request - Analytics request with optional filters and date range
6833
+ * @returns Promise resolving to user analytics data with per-user and per-active-user metrics
6834
+ *
6835
+ * @example Basic user analytics (compare per-user vs per-active-user)
6836
+ * ```typescript
6837
+ * const analytics = await sdk.analytics.getUserAnalytics({});
6838
+ * console.log(`Total users: ${analytics.totalUsers}`);
6839
+ * console.log(`Active users: ${analytics.activeUsers} (${analytics.engagementRate.toFixed(1)}%)`);
6840
+ *
6841
+ * // Per-user averages (includes inactive users - lower numbers)
6842
+ * console.log(`\\nPer-User Averages (all users):`);
6843
+ * console.log(` Transactions: ${analytics.averageTransactionsPerUser.toFixed(2)}`);
6844
+ * console.log(` Claims: ${analytics.averageClaimsPerUser.toFixed(2)}`);
6845
+ * console.log(` Redemptions: ${analytics.averageRedemptionsPerUser.toFixed(2)}`);
6846
+ *
6847
+ * // Per-active-user averages (only engaged users - higher, more meaningful numbers)
6848
+ * console.log(`\\nPer-Active-User Averages (engaged users only):`);
6849
+ * console.log(` Transactions: ${analytics.averageTransactionsPerActiveUser.toFixed(2)}`);
6850
+ * console.log(` Claims: ${analytics.averageClaimsPerActiveUser.toFixed(2)}`);
6851
+ * console.log(` Redemptions: ${analytics.averageRedemptionsPerActiveUser.toFixed(2)}`);
6852
+ * ```
6853
+ *
6854
+ * @example Monthly user analytics with date range
6855
+ * ```typescript
6856
+ * const analytics = await sdk.analytics.getUserAnalytics({
6857
+ * startDate: new Date('2026-02-01'),
6858
+ * endDate: new Date('2026-02-28')
6859
+ * });
6860
+ *
6861
+ * console.log('February 2026 User Metrics:');
6862
+ * console.log(`Total users: ${analytics.totalUsers}`);
6863
+ * console.log(`Active users: ${analytics.activeUsers}`);
6864
+ * console.log(`New users: ${analytics.newUsers}`);
6865
+ * console.log(`Engagement rate: ${analytics.engagementRate.toFixed(2)}%`);
6866
+ * console.log(`Total transaction volume: $${analytics.totalTransactionVolume.toLocaleString()}`);
6867
+ * console.log(`Avg transaction amount: $${analytics.averageTransactionAmount.toFixed(2)}`);
6868
+ * console.log(`\\nFilters applied: ${analytics.metadata.dateRange?.startDate} to ${analytics.metadata.dateRange?.endDate}`);
6869
+ * ```
6870
+ *
6871
+ * @example Business-specific user analytics with filters
6872
+ * ```typescript
6873
+ * const analytics = await sdk.analytics.getUserAnalytics({
6874
+ * filters: { businessId: 'business-123' },
6875
+ * startDate: new Date('2026-01-01'),
6876
+ * endDate: new Date('2026-12-31')
6877
+ * });
6878
+ *
6879
+ * console.log(`Business customer metrics for 2026:`);
6880
+ * console.log(`Active customers: ${analytics.activeUsers} / ${analytics.totalUsers}`);
6881
+ * console.log(`Customer engagement: ${analytics.engagementRate.toFixed(1)}%`);
6882
+ * console.log(`Avg spend per customer: $${analytics.averageTransactionAmount.toFixed(2)}`);
6883
+ * console.log(`Avg spend per active customer: $${(analytics.totalTransactionVolume / analytics.activeUsers).toFixed(2)}`);
6884
+ * console.log(`Avg claims per active customer: ${analytics.averageClaimsPerActiveUser.toFixed(2)}`);
6885
+ * ```
6886
+ */
6887
+ async getUserAnalytics(request = {}) {
6888
+ return this.analyticsService.getUserAnalytics(request);
6889
+ }
6890
+ /**
6891
+ * Get user transaction ranking with enriched user data
6892
+ *
6893
+ * Retrieves ranked list of users with full user details (email, externalUserId)
6894
+ * and transaction metrics. Data enrichment happens via efficient SQL JOINs + UNION
6895
+ * (handles legacy transactions). Ideal for leaderboards, engagement analysis, and
6896
+ * identifying power users for targeted campaigns.
6897
+ *
6898
+ * Use Cases:
6899
+ * - Admin leaderboards showing top users by activity
6900
+ * - User engagement analysis with full user context
6901
+ * - Identifying power users for campaigns
6902
+ * - Customer segmentation by transaction behavior
6903
+ *
6904
+ * @param request - Ranking request with filters, sorting, and limit
6905
+ * @returns Promise resolving to ranked user list with transaction metrics
6906
+ *
6907
+ * @example Top 50 users by transaction count
6908
+ * ```typescript
6909
+ * const ranking = await sdk.analytics.getUserRanking({
6910
+ * sortBy: 'totalTransactions',
6911
+ * sortOrder: 'DESC',
6912
+ * limit: 50
6913
+ * });
6914
+ *
6915
+ * console.log(`Top ${ranking.totalUsers} users:`);
6916
+ * ranking.results.forEach((user, index) => {
6917
+ * console.log(`#${index + 1}: ${user.email || user.externalUserId}`);
6918
+ * console.log(` Transactions: ${user.totalTransactions}`);
6919
+ * console.log(` Token spent: ${user.tokenSpent}`);
6920
+ * });
6921
+ * ```
6922
+ *
6923
+ * @example Top users by STAMP spending
6924
+ * ```typescript
6925
+ * const ranking = await sdk.analytics.getUserRanking({
6926
+ * filters: { tokenType: 'STAMP' },
6927
+ * sortBy: 'tokenSpent',
6928
+ * sortOrder: 'DESC',
6929
+ * limit: 20
6930
+ * });
6931
+ *
6932
+ * console.log('Top 20 STAMP spenders:');
6933
+ * ranking.results.forEach((user, index) => {
6934
+ * const identifier = user.email || user.externalUserId || user.userId;
6935
+ * console.log(`${index + 1}. ${identifier} - ${user.tokenSpent} STAMP`);
6936
+ * });
6937
+ * ```
6938
+ */
6939
+ async getUserRanking(request = {}) {
6940
+ return this.analyticsService.getUserRanking(request);
6941
+ }
6942
+ /**
6943
+ * Get business transaction ranking with enriched business data
6944
+ *
6945
+ * Returns ranked list of businesses with full business details and transaction metrics.
6946
+ *
6947
+ * @param request - Ranking request with filters, sorting, and limit
6948
+ * @returns Promise resolving to ranked business list
6949
+ */
6950
+ async getBusinessRanking(request = {}) {
6951
+ return this.analyticsService.getBusinessRanking(request);
6952
+ }
6953
+ /**
6954
+ * Get monthly user retention analytics
6955
+ *
6956
+ * Returns monthly retention data with user metrics and retention rates.
6957
+ *
6958
+ * @param request - Retention request with monthsBack and filters
6959
+ * @returns Promise resolving to monthly retention data
6960
+ */
6961
+ async getRetentionAnalytics(request = {}) {
6962
+ return this.analyticsService.getRetentionAnalytics(request);
6963
+ }
6964
+ /**
6965
+ * Get the full analytics service for advanced operations
6966
+ *
6967
+ * Provides access to the complete AnalyticsService instance for advanced analytics
6968
+ * operations, custom metrics, predictive analytics, cohort analysis, and
6969
+ * operations not covered by the high-level manager methods.
6970
+ *
6971
+ * @returns AnalyticsService instance with full API access
6972
+ *
6973
+ * @example Advanced Analytics Operations
6974
+ * ```typescript
6975
+ * const analyticsService = sdk.analytics.getAnalyticsService();
6976
+ *
6977
+ * // Access user engagement analytics
6978
+ * const engagementMetrics = await analyticsService.getUserEngagementMetrics({
6466
6979
  * timeframe: 'last-90-days',
6467
6980
  * includeSegmentation: true
6468
6981
  * });
@@ -6542,6 +7055,360 @@ class DonationManager {
6542
7055
  }
6543
7056
  }
6544
7057
 
7058
+ /**
7059
+ * Platform-Agnostic TriggerSource API Client
7060
+ *
7061
+ * Handles all trigger source operations:
7062
+ * - CRUD operations for trigger sources (QR codes, NFC tags, GPS geofences, webhooks, etc.)
7063
+ * - Trigger sources are independent entities that can be assigned to campaigns
7064
+ *
7065
+ * Uses @explorins/pers-shared DTOs for consistency with backend.
7066
+ */
7067
+ class TriggerSourceApi {
7068
+ constructor(apiClient) {
7069
+ this.apiClient = apiClient;
7070
+ }
7071
+ /**
7072
+ * PUBLIC: Get trigger sources with optional filters and pagination
7073
+ *
7074
+ * @param options - Filter and pagination options
7075
+ * @returns Paginated list of trigger sources
7076
+ *
7077
+ * @example
7078
+ * ```typescript
7079
+ * // Get all QR code trigger sources
7080
+ * const qrSources = await triggerSourceApi.getTriggerSources({ type: 'QR_CODE' });
7081
+ *
7082
+ * // Get trigger sources for a specific campaign
7083
+ * const campaignSources = await triggerSourceApi.getTriggerSources({
7084
+ * campaignId: 'campaign-123',
7085
+ * page: 1,
7086
+ * limit: 20
7087
+ * });
7088
+ * ```
7089
+ */
7090
+ async getTriggerSources(options) {
7091
+ const params = paginationUtils.buildPaginationParams(options);
7092
+ if (options?.type)
7093
+ params.set('type', options.type);
7094
+ if (options?.businessId)
7095
+ params.set('businessId', options.businessId);
7096
+ if (options?.campaignId)
7097
+ params.set('campaignId', options.campaignId);
7098
+ if (options?.active !== undefined)
7099
+ params.set('active', String(options.active));
7100
+ const response = await this.apiClient.get(`/trigger-sources?${params.toString()}`);
7101
+ return paginationUtils.normalizeToPaginated(response);
7102
+ }
7103
+ /**
7104
+ * PUBLIC: Get trigger source by ID
7105
+ *
7106
+ * @param triggerSourceId - UUID of the trigger source
7107
+ * @returns Trigger source details
7108
+ */
7109
+ async getTriggerSourceById(triggerSourceId) {
7110
+ return this.apiClient.get(`/trigger-sources/${triggerSourceId}`);
7111
+ }
7112
+ /**
7113
+ * ADMIN: Create a new trigger source
7114
+ *
7115
+ * @param triggerSource - Trigger source creation data
7116
+ * @returns Created trigger source
7117
+ *
7118
+ * @example
7119
+ * ```typescript
7120
+ * const qrSource = await triggerSourceApi.createTriggerSource({
7121
+ * type: 'QR_CODE',
7122
+ * name: 'Store Entrance QR',
7123
+ * description: 'QR code at main entrance',
7124
+ * businessId: 'business-123',
7125
+ * coordsLatitude: 47.6062,
7126
+ * coordsLongitude: -122.3321
7127
+ * });
7128
+ * ```
7129
+ */
7130
+ async createTriggerSource(triggerSource) {
7131
+ return this.apiClient.post('/trigger-sources', triggerSource);
7132
+ }
7133
+ /**
7134
+ * ADMIN: Update a trigger source
7135
+ *
7136
+ * @param triggerSourceId - UUID of the trigger source to update
7137
+ * @param triggerSource - Updated trigger source data (partial)
7138
+ * @returns Updated trigger source
7139
+ */
7140
+ async updateTriggerSource(triggerSourceId, triggerSource) {
7141
+ return this.apiClient.put(`/trigger-sources/${triggerSourceId}`, triggerSource);
7142
+ }
7143
+ /**
7144
+ * ADMIN: Delete (soft delete) a trigger source
7145
+ *
7146
+ * @param triggerSourceId - UUID of the trigger source to delete
7147
+ * @returns Success status
7148
+ */
7149
+ async deleteTriggerSource(triggerSourceId) {
7150
+ return this.apiClient.delete(`/trigger-sources/${triggerSourceId}`);
7151
+ }
7152
+ }
7153
+
7154
+ /**
7155
+ * Platform-Agnostic TriggerSource Service
7156
+ *
7157
+ * Contains trigger source business logic and operations that work across platforms.
7158
+ * No framework dependencies - pure TypeScript business logic.
7159
+ */
7160
+ class TriggerSourceService {
7161
+ constructor(triggerSourceApi) {
7162
+ this.triggerSourceApi = triggerSourceApi;
7163
+ }
7164
+ /**
7165
+ * Get trigger sources with optional filters
7166
+ */
7167
+ async getTriggerSources(options) {
7168
+ return this.triggerSourceApi.getTriggerSources(options);
7169
+ }
7170
+ /**
7171
+ * Get trigger source by ID
7172
+ */
7173
+ async getTriggerSourceById(triggerSourceId) {
7174
+ return this.triggerSourceApi.getTriggerSourceById(triggerSourceId);
7175
+ }
7176
+ /**
7177
+ * ADMIN: Create a new trigger source
7178
+ */
7179
+ async createTriggerSource(triggerSource) {
7180
+ return this.triggerSourceApi.createTriggerSource(triggerSource);
7181
+ }
7182
+ /**
7183
+ * ADMIN: Update a trigger source
7184
+ */
7185
+ async updateTriggerSource(triggerSourceId, triggerSource) {
7186
+ return this.triggerSourceApi.updateTriggerSource(triggerSourceId, triggerSource);
7187
+ }
7188
+ /**
7189
+ * ADMIN: Delete a trigger source
7190
+ */
7191
+ async deleteTriggerSource(triggerSourceId) {
7192
+ return this.triggerSourceApi.deleteTriggerSource(triggerSourceId);
7193
+ }
7194
+ }
7195
+
7196
+ /**
7197
+ * TriggerSource Manager - Clean, high-level interface for trigger source operations
7198
+ *
7199
+ * Manages trigger sources which are physical or digital activation points for campaigns:
7200
+ * - QR_CODE: Scannable QR codes
7201
+ * - NFC_TAG: NFC tap points
7202
+ * - GPS_GEOFENCE: Location-based triggers
7203
+ * - API_WEBHOOK: External system integration
7204
+ * - TRANSACTION: Purchase/payment based triggers
7205
+ *
7206
+ * Trigger sources are independent entities that can be created, managed, and then
7207
+ * assigned to campaigns. This separation allows reuse and flexible campaign configuration.
7208
+ *
7209
+ * @group Managers
7210
+ * @category TriggerSource Management
7211
+ *
7212
+ * @example Basic TriggerSource Operations
7213
+ * ```typescript
7214
+ * // Get all QR code trigger sources
7215
+ * const qrSources = await sdk.triggerSources.getAll({ type: 'QR_CODE' });
7216
+ *
7217
+ * // Create a new QR code trigger source
7218
+ * const source = await sdk.triggerSources.create({
7219
+ * type: 'QR_CODE',
7220
+ * name: 'Store Entrance QR',
7221
+ * businessId: 'business-123'
7222
+ * });
7223
+ *
7224
+ * // Assign to campaign (via CampaignManager)
7225
+ * await sdk.campaigns.assignTriggerSource('campaign-456', source.id);
7226
+ * ```
7227
+ */
7228
+ class TriggerSourceManager {
7229
+ constructor(apiClient, events) {
7230
+ this.apiClient = apiClient;
7231
+ this.events = events;
7232
+ const triggerSourceApi = new TriggerSourceApi(apiClient);
7233
+ this.triggerSourceService = new TriggerSourceService(triggerSourceApi);
7234
+ }
7235
+ /**
7236
+ * Get trigger sources with optional filters and pagination
7237
+ *
7238
+ * Retrieves trigger sources (QR codes, NFC tags, GPS geofences, webhooks, etc.)
7239
+ * that can be used to activate campaigns. Supports filtering by type, business,
7240
+ * campaign association, and active status.
7241
+ *
7242
+ * @param options - Filter and pagination options
7243
+ * @returns Promise resolving to paginated trigger sources
7244
+ *
7245
+ * @example
7246
+ * ```typescript
7247
+ * // Get all QR code trigger sources
7248
+ * const qrSources = await sdk.triggerSources.getAll({ type: 'QR_CODE' });
7249
+ *
7250
+ * // Get trigger sources for a specific business
7251
+ * const businessSources = await sdk.triggerSources.getAll({
7252
+ * businessId: 'business-123',
7253
+ * active: true,
7254
+ * page: 1,
7255
+ * limit: 20
7256
+ * });
7257
+ *
7258
+ * // Get trigger sources assigned to a campaign
7259
+ * const campaignSources = await sdk.triggerSources.getAll({
7260
+ * campaignId: 'campaign-456'
7261
+ * });
7262
+ * ```
7263
+ */
7264
+ async getAll(options) {
7265
+ return this.triggerSourceService.getTriggerSources(options);
7266
+ }
7267
+ /**
7268
+ * Get trigger source by ID
7269
+ *
7270
+ * Retrieves detailed information for a specific trigger source including
7271
+ * its type, location, metadata, and usage analytics.
7272
+ *
7273
+ * @param triggerSourceId - UUID of the trigger source
7274
+ * @returns Promise resolving to trigger source details
7275
+ * @throws {PersApiError} When trigger source with specified ID is not found
7276
+ *
7277
+ * @example
7278
+ * ```typescript
7279
+ * const source = await sdk.triggerSources.getById('source-123');
7280
+ *
7281
+ * console.log('Trigger Source:', source.name);
7282
+ * console.log('Type:', source.type);
7283
+ * console.log('Active:', source.isActive);
7284
+ *
7285
+ * if (source.coordsLatitude && source.coordsLongitude) {
7286
+ * console.log('Location:', source.coordsLatitude, source.coordsLongitude);
7287
+ * }
7288
+ * ```
7289
+ */
7290
+ async getById(triggerSourceId) {
7291
+ return this.triggerSourceService.getTriggerSourceById(triggerSourceId);
7292
+ }
7293
+ /**
7294
+ * Admin: Create a new trigger source
7295
+ *
7296
+ * Creates a new trigger source (QR code, NFC tag, GPS geofence, webhook, or
7297
+ * transaction-based trigger) that can be assigned to campaigns. Requires
7298
+ * administrator privileges.
7299
+ *
7300
+ * @param triggerSource - Trigger source creation data
7301
+ * @returns Promise resolving to created trigger source
7302
+ * @throws {PersApiError} When not authenticated as admin or validation fails
7303
+ *
7304
+ * @example
7305
+ * ```typescript
7306
+ * // Create a QR code trigger source
7307
+ * const qrSource = await sdk.triggerSources.create({
7308
+ * type: 'QR_CODE',
7309
+ * name: 'Store Entrance QR',
7310
+ * description: 'QR code at main entrance',
7311
+ * businessId: 'business-123',
7312
+ * coordsLatitude: 47.6062,
7313
+ * coordsLongitude: -122.3321
7314
+ * });
7315
+ *
7316
+ * // Create an NFC tag trigger source
7317
+ * const nfcSource = await sdk.triggerSources.create({
7318
+ * type: 'NFC_TAG',
7319
+ * name: 'Product Display NFC',
7320
+ * metadata: { productId: 'SKU-12345' }
7321
+ * });
7322
+ *
7323
+ * // Create a GPS geofence trigger source
7324
+ * const geoSource = await sdk.triggerSources.create({
7325
+ * type: 'GPS_GEOFENCE',
7326
+ * name: 'Store Area',
7327
+ * coordsLatitude: 47.6062,
7328
+ * coordsLongitude: -122.3321,
7329
+ * metadata: { radiusMeters: 100 }
7330
+ * });
7331
+ * ```
7332
+ */
7333
+ async create(triggerSource) {
7334
+ const result = await this.triggerSourceService.createTriggerSource(triggerSource);
7335
+ this.events?.emitSuccess({
7336
+ domain: 'trigger-source',
7337
+ type: 'TRIGGER_SOURCE_CREATED',
7338
+ userMessage: 'Trigger source created successfully',
7339
+ details: { triggerSourceId: result.id, type: result.type }
7340
+ });
7341
+ return result;
7342
+ }
7343
+ /**
7344
+ * Admin: Update a trigger source
7345
+ *
7346
+ * Updates an existing trigger source's configuration. All fields are optional;
7347
+ * only provided fields will be updated. Requires administrator privileges.
7348
+ *
7349
+ * @param triggerSourceId - UUID of the trigger source to update
7350
+ * @param triggerSource - Updated trigger source data (partial)
7351
+ * @returns Promise resolving to updated trigger source
7352
+ * @throws {PersApiError} When not authenticated as admin or trigger source not found
7353
+ *
7354
+ * @example
7355
+ * ```typescript
7356
+ * // Update trigger source name and location
7357
+ * const updated = await sdk.triggerSources.update('source-123', {
7358
+ * name: 'Updated Store Entrance QR',
7359
+ * description: 'New description',
7360
+ * coordsLatitude: 47.6063,
7361
+ * coordsLongitude: -122.3322
7362
+ * });
7363
+ * ```
7364
+ */
7365
+ async update(triggerSourceId, triggerSource) {
7366
+ const result = await this.triggerSourceService.updateTriggerSource(triggerSourceId, triggerSource);
7367
+ this.events?.emitSuccess({
7368
+ domain: 'trigger-source',
7369
+ type: 'TRIGGER_SOURCE_UPDATED',
7370
+ userMessage: 'Trigger source updated successfully',
7371
+ details: { triggerSourceId }
7372
+ });
7373
+ return result;
7374
+ }
7375
+ /**
7376
+ * Admin: Delete a trigger source
7377
+ *
7378
+ * Soft deletes a trigger source, making it inactive. The trigger source will
7379
+ * be removed from any campaigns it was assigned to. Requires administrator
7380
+ * privileges.
7381
+ *
7382
+ * @param triggerSourceId - UUID of the trigger source to delete
7383
+ * @returns Promise resolving to success status
7384
+ * @throws {PersApiError} When not authenticated as admin or trigger source not found
7385
+ *
7386
+ * @example
7387
+ * ```typescript
7388
+ * const success = await sdk.triggerSources.delete('source-123');
7389
+ * console.log('Trigger source deleted:', success);
7390
+ * ```
7391
+ */
7392
+ async delete(triggerSourceId) {
7393
+ const result = await this.triggerSourceService.deleteTriggerSource(triggerSourceId);
7394
+ this.events?.emitSuccess({
7395
+ domain: 'trigger-source',
7396
+ type: 'TRIGGER_SOURCE_DELETED',
7397
+ userMessage: 'Trigger source deleted successfully',
7398
+ details: { triggerSourceId }
7399
+ });
7400
+ return result;
7401
+ }
7402
+ /**
7403
+ * Get the full trigger source service for advanced operations
7404
+ *
7405
+ * @returns TriggerSourceService instance with full API access
7406
+ */
7407
+ getTriggerSourceService() {
7408
+ return this.triggerSourceService;
7409
+ }
7410
+ }
7411
+
6545
7412
  /**
6546
7413
  * @fileoverview PERS SDK - Platform-agnostic TypeScript SDK with High-Level Managers
6547
7414
  *
@@ -6655,78 +7522,71 @@ class PersSDK {
6655
7522
  // Initialize event emitter and wire to API client for error events
6656
7523
  this._events = new PersEventEmitter();
6657
7524
  this.apiClient.setEvents(this._events);
6658
- // Initialize domain managers (pass events to managers that emit success events)
6659
- this._auth = new AuthManager(this.apiClient, this._events);
6660
- this._users = new UserManager(this.apiClient, this._events);
6661
- this._userStatus = new UserStatusManager(this.apiClient);
6662
- this._tokens = new TokenManager(this.apiClient);
6663
- this._businesses = new BusinessManager(this.apiClient, this._events);
6664
- this._campaigns = new CampaignManager(this.apiClient, this._events);
6665
- this._redemptions = new RedemptionManager(this.apiClient, this._events);
6666
- this._transactions = new TransactionManager(this.apiClient, this._events);
6667
- this._purchases = new PurchaseManager(this.apiClient);
6668
- this._files = new FileManager(this.apiClient);
6669
- this._tenants = new TenantManager(this.apiClient);
6670
- this._apiKeys = new ApiKeyManager(this.apiClient);
6671
- this._analytics = new AnalyticsManager(this.apiClient);
6672
- this._donations = new DonationManager(this.apiClient);
6673
- // Automatically restore session if enabled and tokens exist
6674
- if (config.autoRestoreSession !== false) {
6675
- this.restoreSessionIfTokensExist().catch(err => {
6676
- console.warn('[PersSDK] Failed to restore session on initialization:', err);
6677
- });
6678
- }
6679
7525
  }
6680
7526
  /**
6681
- * Restore user session if valid tokens exist in storage
7527
+ * Restore user session from stored tokens
7528
+ *
7529
+ * Call this method after SDK initialization to restore the user's session
7530
+ * if valid tokens exist. This is useful for maintaining login state across
7531
+ * app restarts.
6682
7532
  *
6683
- * This method is called automatically during SDK initialization when
6684
- * `autoRestoreSession` is enabled (default). It checks for stored tokens
6685
- * and fetches user data to restore the authentication state.
7533
+ * **Important:** Only works for USER and BUSINESS accounts. Admin/tenant
7534
+ * accounts don't support user data fetching, so this will return null for them
7535
+ * (though their tokens remain valid for API calls).
6686
7536
  *
6687
7537
  * Emits auth domain success event when session is restored.
6688
7538
  *
6689
- * @internal
6690
- * @returns Promise that resolves when session is restored or determined to be invalid
7539
+ * @returns Promise resolving to User data if session restored, null if no session or admin account
7540
+ * @throws {PersError} If token validation or user fetch fails
7541
+ *
7542
+ * @example
7543
+ * ```typescript
7544
+ * // Call after initial render for better perceived performance
7545
+ * const user = await sdk.restoreSession();
7546
+ * if (user) {
7547
+ * console.log('Welcome back,', user.name);
7548
+ * }
7549
+ * ```
6691
7550
  */
6692
- async restoreSessionIfTokensExist() {
6693
- try {
6694
- const hasToken = await this._auth.hasValidAuth();
6695
- if (hasToken) {
6696
- console.log('[PersSDK] Valid tokens found, restoring session...');
6697
- try {
6698
- // Fetch user data to validate tokens and restore session
6699
- const userData = await this._auth.getCurrentUser();
6700
- console.log('[PersSDK] Session restored successfully');
6701
- // Emit event through proper event emitter
6702
- // Send minimal data (just userId) - consumers can fetch full user if needed
6703
- this._events.emitSuccess({
6704
- type: 'session_restored',
6705
- domain: 'authentication',
6706
- userMessage: 'Session restored successfully',
6707
- details: { userId: userData.id }
6708
- });
6709
- }
6710
- catch (error) {
6711
- // Tokens exist but are invalid (expired, revoked, etc.)
6712
- console.warn('[PersSDK] Failed to restore session, tokens may be invalid:', error);
6713
- await this._auth.clearAuth();
6714
- // Emit restoration failed event
6715
- this._events.emitError({
6716
- type: 'session_restoration_failed',
6717
- domain: 'authentication',
6718
- userMessage: 'Session restoration failed',
6719
- code: 'SESSION_INVALID',
6720
- details: { error }
6721
- });
6722
- }
6723
- }
6724
- else {
6725
- console.log('[PersSDK] No valid tokens found');
7551
+ async restoreSession() {
7552
+ const hasToken = await this.auth.hasValidAuth();
7553
+ if (!hasToken) {
7554
+ return null;
7555
+ }
7556
+ // Check auth type - only restore session for user and business accounts
7557
+ const authProvider = this.apiClient.getConfig().authProvider;
7558
+ if (authProvider?.getAuthType) {
7559
+ const authType = await authProvider.getAuthType();
7560
+ if (authType === persShared.AccountOwnerType.TENANT) {
7561
+ // Admin sessions don't support getCurrentUser(), skip restoration
7562
+ // Tokens are valid and will be used for API calls
7563
+ return null;
6726
7564
  }
6727
7565
  }
7566
+ try {
7567
+ // Fetch user data to validate tokens and restore session
7568
+ const userData = await this.auth.getCurrentUser();
7569
+ // Emit event through proper event emitter
7570
+ this._events.emitSuccess({
7571
+ type: 'session_restored',
7572
+ domain: 'authentication',
7573
+ userMessage: 'Session restored successfully',
7574
+ details: { userId: userData.id }
7575
+ });
7576
+ return userData;
7577
+ }
6728
7578
  catch (error) {
6729
- console.warn('[PersSDK] Error during session restoration:', error);
7579
+ // Tokens exist but are invalid (expired, revoked, etc.)
7580
+ await this.auth.clearAuth();
7581
+ // Emit restoration failed event
7582
+ this._events.emitError({
7583
+ type: 'session_restoration_failed',
7584
+ domain: 'authentication',
7585
+ userMessage: 'Session restoration failed',
7586
+ code: 'SESSION_INVALID',
7587
+ details: { error }
7588
+ });
7589
+ throw error;
6730
7590
  }
6731
7591
  }
6732
7592
  /**
@@ -6815,6 +7675,9 @@ class PersSDK {
6815
7675
  * @see {@link AuthManager} for detailed documentation
6816
7676
  */
6817
7677
  get auth() {
7678
+ if (!this._auth) {
7679
+ this._auth = new AuthManager(this.apiClient, this._events);
7680
+ }
6818
7681
  return this._auth;
6819
7682
  }
6820
7683
  /**
@@ -6828,6 +7691,9 @@ class PersSDK {
6828
7691
  * ```
6829
7692
  */
6830
7693
  get users() {
7694
+ if (!this._users) {
7695
+ this._users = new UserManager(this.apiClient, this._events);
7696
+ }
6831
7697
  return this._users;
6832
7698
  }
6833
7699
  /**
@@ -6841,6 +7707,9 @@ class PersSDK {
6841
7707
  * ```
6842
7708
  */
6843
7709
  get userStatus() {
7710
+ if (!this._userStatus) {
7711
+ this._userStatus = new UserStatusManager(this.apiClient);
7712
+ }
6844
7713
  return this._userStatus;
6845
7714
  }
6846
7715
  /**
@@ -6854,6 +7723,9 @@ class PersSDK {
6854
7723
  * ```
6855
7724
  */
6856
7725
  get tokens() {
7726
+ if (!this._tokens) {
7727
+ this._tokens = new TokenManager(this.apiClient);
7728
+ }
6857
7729
  return this._tokens;
6858
7730
  }
6859
7731
  /**
@@ -6867,6 +7739,9 @@ class PersSDK {
6867
7739
  * ```
6868
7740
  */
6869
7741
  get businesses() {
7742
+ if (!this._businesses) {
7743
+ this._businesses = new BusinessManager(this.apiClient, this._events);
7744
+ }
6870
7745
  return this._businesses;
6871
7746
  }
6872
7747
  /**
@@ -6880,6 +7755,9 @@ class PersSDK {
6880
7755
  * ```
6881
7756
  */
6882
7757
  get campaigns() {
7758
+ if (!this._campaigns) {
7759
+ this._campaigns = new CampaignManager(this.apiClient, this._events);
7760
+ }
6883
7761
  return this._campaigns;
6884
7762
  }
6885
7763
  /**
@@ -6893,6 +7771,9 @@ class PersSDK {
6893
7771
  * ```
6894
7772
  */
6895
7773
  get redemptions() {
7774
+ if (!this._redemptions) {
7775
+ this._redemptions = new RedemptionManager(this.apiClient, this._events);
7776
+ }
6896
7777
  return this._redemptions;
6897
7778
  }
6898
7779
  /**
@@ -6906,6 +7787,9 @@ class PersSDK {
6906
7787
  * ```
6907
7788
  */
6908
7789
  get transactions() {
7790
+ if (!this._transactions) {
7791
+ this._transactions = new TransactionManager(this.apiClient, this._events);
7792
+ }
6909
7793
  return this._transactions;
6910
7794
  }
6911
7795
  /**
@@ -6919,6 +7803,9 @@ class PersSDK {
6919
7803
  * ```
6920
7804
  */
6921
7805
  get purchases() {
7806
+ if (!this._purchases) {
7807
+ this._purchases = new PurchaseManager(this.apiClient);
7808
+ }
6922
7809
  return this._purchases;
6923
7810
  }
6924
7811
  /**
@@ -6932,6 +7819,9 @@ class PersSDK {
6932
7819
  * ```
6933
7820
  */
6934
7821
  get files() {
7822
+ if (!this._files) {
7823
+ this._files = new FileManager(this.apiClient);
7824
+ }
6935
7825
  return this._files;
6936
7826
  }
6937
7827
  /**
@@ -6945,6 +7835,9 @@ class PersSDK {
6945
7835
  * ```
6946
7836
  */
6947
7837
  get tenants() {
7838
+ if (!this._tenants) {
7839
+ this._tenants = new TenantManager(this.apiClient);
7840
+ }
6948
7841
  return this._tenants;
6949
7842
  }
6950
7843
  /**
@@ -6969,6 +7862,9 @@ class PersSDK {
6969
7862
  * ```
6970
7863
  */
6971
7864
  get apiKeys() {
7865
+ if (!this._apiKeys) {
7866
+ this._apiKeys = new ApiKeyManager(this.apiClient);
7867
+ }
6972
7868
  return this._apiKeys;
6973
7869
  }
6974
7870
  /**
@@ -6980,6 +7876,9 @@ class PersSDK {
6980
7876
  * ```
6981
7877
  */
6982
7878
  get analytics() {
7879
+ if (!this._analytics) {
7880
+ this._analytics = new AnalyticsManager(this.apiClient);
7881
+ }
6983
7882
  return this._analytics;
6984
7883
  }
6985
7884
  /**
@@ -6991,8 +7890,45 @@ class PersSDK {
6991
7890
  * ```
6992
7891
  */
6993
7892
  get donations() {
7893
+ if (!this._donations) {
7894
+ this._donations = new DonationManager(this.apiClient);
7895
+ }
6994
7896
  return this._donations;
6995
7897
  }
7898
+ /**
7899
+ * TriggerSource manager - High-level trigger source operations (Admin Only)
7900
+ *
7901
+ * Provides CRUD operations for managing trigger sources (QR codes, NFC tags,
7902
+ * GPS geofences, API webhooks). TriggerSources are standalone entities that
7903
+ * can be assigned to campaigns via the campaigns manager.
7904
+ *
7905
+ * @returns TriggerSourceManager instance
7906
+ *
7907
+ * @example TriggerSource Operations
7908
+ * ```typescript
7909
+ * // Create a QR code trigger source
7910
+ * const qrSource = await sdk.triggerSources.create({
7911
+ * name: 'Store Entrance QR',
7912
+ * type: 'QR_CODE',
7913
+ * description: 'QR code at main entrance'
7914
+ * });
7915
+ *
7916
+ * // Get all trigger sources
7917
+ * const sources = await sdk.triggerSources.getAll();
7918
+ *
7919
+ * // Update trigger source
7920
+ * await sdk.triggerSources.update(sourceId, { name: 'Updated Name' });
7921
+ *
7922
+ * // Assign to campaign (via campaigns manager)
7923
+ * await sdk.campaigns.assignTriggerSource(campaignId, qrSource.id);
7924
+ * ```
7925
+ */
7926
+ get triggerSources() {
7927
+ if (!this._triggerSources) {
7928
+ this._triggerSources = new TriggerSourceManager(this.apiClient, this._events);
7929
+ }
7930
+ return this._triggerSources;
7931
+ }
6996
7932
  /**
6997
7933
  * Gets the API client for direct PERS API requests
6998
7934
  *
@@ -7074,10 +8010,13 @@ exports.StaticJwtAuthProvider = StaticJwtAuthProvider;
7074
8010
  exports.TenantManager = TenantManager;
7075
8011
  exports.TokenManager = TokenManager;
7076
8012
  exports.TransactionManager = TransactionManager;
8013
+ exports.TriggerSourceApi = TriggerSourceApi;
8014
+ exports.TriggerSourceManager = TriggerSourceManager;
8015
+ exports.TriggerSourceService = TriggerSourceService;
7077
8016
  exports.UserManager = UserManager;
7078
8017
  exports.UserStatusManager = UserStatusManager;
7079
8018
  exports.WebDPoPCryptoProvider = WebDPoPCryptoProvider;
7080
8019
  exports.buildApiRoot = buildApiRoot;
7081
8020
  exports.createPersSDK = createPersSDK;
7082
8021
  exports.mergeWithDefaults = mergeWithDefaults;
7083
- //# sourceMappingURL=pers-sdk-D5lE9ZFW.cjs.map
8022
+ //# sourceMappingURL=pers-sdk-Di_R6AiT.cjs.map