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