@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.
- package/dist/analytics/api/analytics-api.d.ts +175 -1
- package/dist/analytics/api/analytics-api.d.ts.map +1 -1
- package/dist/analytics/models/index.d.ts +2 -5
- package/dist/analytics/models/index.d.ts.map +1 -1
- package/dist/analytics/services/analytics-service.d.ts +32 -1
- package/dist/analytics/services/analytics-service.d.ts.map +1 -1
- package/dist/analytics.cjs +9 -44
- package/dist/analytics.cjs.map +1 -1
- package/dist/analytics.js +2 -45
- package/dist/analytics.js.map +1 -1
- package/dist/campaign/api/campaign-api.d.ts +59 -4
- package/dist/campaign/api/campaign-api.d.ts.map +1 -1
- package/dist/campaign/services/campaign-service.d.ts +49 -7
- package/dist/campaign/services/campaign-service.d.ts.map +1 -1
- package/dist/campaign.cjs +150 -14
- package/dist/campaign.cjs.map +1 -1
- package/dist/campaign.js +150 -14
- package/dist/campaign.js.map +1 -1
- package/dist/chunks/analytics-service-B9IfG6ox.js +271 -0
- package/dist/chunks/analytics-service-B9IfG6ox.js.map +1 -0
- package/dist/chunks/analytics-service-DwkeBB08.cjs +274 -0
- package/dist/chunks/analytics-service-DwkeBB08.cjs.map +1 -0
- package/dist/chunks/{pers-sdk-DnLw822h.js → pers-sdk-CAM0iQyK.js} +1203 -267
- package/dist/chunks/pers-sdk-CAM0iQyK.js.map +1 -0
- package/dist/chunks/{pers-sdk-D5lE9ZFW.cjs → pers-sdk-Di_R6AiT.cjs} +1207 -268
- package/dist/chunks/pers-sdk-Di_R6AiT.cjs.map +1 -0
- package/dist/chunks/{redemption-service-D-hBqh42.js → redemption-service-CQtTLdic.js} +32 -10
- package/dist/chunks/redemption-service-CQtTLdic.js.map +1 -0
- package/dist/chunks/{redemption-service-rMB6T2W5.cjs → redemption-service-DsH7sRdv.cjs} +32 -10
- package/dist/chunks/redemption-service-DsH7sRdv.cjs.map +1 -0
- package/dist/chunks/{transaction-request.builder-C1vVVFto.js → transaction-request.builder-C8ahJYwi.js} +122 -70
- package/dist/chunks/transaction-request.builder-C8ahJYwi.js.map +1 -0
- package/dist/chunks/{transaction-request.builder-BpgtuMMq.cjs → transaction-request.builder-CkYd5bl6.cjs} +122 -70
- package/dist/chunks/transaction-request.builder-CkYd5bl6.cjs.map +1 -0
- package/dist/core/auth/auth-provider.interface.d.ts +1 -0
- package/dist/core/auth/auth-provider.interface.d.ts.map +1 -1
- package/dist/core/auth/default-auth-provider.d.ts +2 -0
- package/dist/core/auth/default-auth-provider.d.ts.map +1 -1
- package/dist/core/auth/refresh-manager.d.ts +2 -0
- package/dist/core/auth/refresh-manager.d.ts.map +1 -1
- package/dist/core/auth/services/auth-service.d.ts.map +1 -1
- package/dist/core/auth/token-storage.d.ts +2 -1
- package/dist/core/auth/token-storage.d.ts.map +1 -1
- package/dist/core/pers-api-client.d.ts.map +1 -1
- package/dist/core/pers-config.d.ts +0 -18
- package/dist/core/pers-config.d.ts.map +1 -1
- package/dist/core.cjs +5 -4
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +4 -4
- package/dist/index.cjs +13 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/managers/analytics-manager.d.ts +165 -2
- package/dist/managers/analytics-manager.d.ts.map +1 -1
- package/dist/managers/campaign-manager.d.ts +180 -30
- package/dist/managers/campaign-manager.d.ts.map +1 -1
- package/dist/managers/index.d.ts +1 -0
- package/dist/managers/index.d.ts.map +1 -1
- package/dist/managers/redemption-manager.d.ts +52 -2
- package/dist/managers/redemption-manager.d.ts.map +1 -1
- package/dist/managers/transaction-manager.d.ts +66 -131
- package/dist/managers/transaction-manager.d.ts.map +1 -1
- package/dist/managers/trigger-source-manager.d.ts +194 -0
- package/dist/managers/trigger-source-manager.d.ts.map +1 -0
- package/dist/managers/user-manager.d.ts +38 -7
- package/dist/managers/user-manager.d.ts.map +1 -1
- package/dist/node.cjs +4 -4
- package/dist/node.js +4 -4
- package/dist/package.json +2 -2
- package/dist/pers-sdk.d.ts +68 -23
- package/dist/pers-sdk.d.ts.map +1 -1
- package/dist/redemption/api/redemption-api.d.ts +8 -4
- package/dist/redemption/api/redemption-api.d.ts.map +1 -1
- package/dist/redemption/services/redemption-service.d.ts +7 -3
- package/dist/redemption/services/redemption-service.d.ts.map +1 -1
- package/dist/redemption.cjs +1 -1
- package/dist/redemption.js +1 -1
- package/dist/transaction/api/transaction-api.d.ts +37 -42
- package/dist/transaction/api/transaction-api.d.ts.map +1 -1
- package/dist/transaction/models/index.d.ts +21 -0
- package/dist/transaction/models/index.d.ts.map +1 -1
- package/dist/transaction/services/transaction-service.d.ts +10 -15
- package/dist/transaction/services/transaction-service.d.ts.map +1 -1
- package/dist/transaction.cjs +1 -1
- package/dist/transaction.js +1 -1
- package/dist/trigger-source/api/trigger-source-api.d.ts +86 -0
- package/dist/trigger-source/api/trigger-source-api.d.ts.map +1 -0
- package/dist/trigger-source/index.d.ts +9 -0
- package/dist/trigger-source/index.d.ts.map +1 -0
- package/dist/trigger-source/services/trigger-source-service.d.ts +42 -0
- package/dist/trigger-source/services/trigger-source-service.d.ts.map +1 -0
- package/dist/user/api/user-api.d.ts +26 -1
- package/dist/user/api/user-api.d.ts.map +1 -1
- package/dist/user/services/user-service.d.ts +3 -1
- package/dist/user/services/user-service.d.ts.map +1 -1
- package/dist/user.cjs +34 -4
- package/dist/user.cjs.map +1 -1
- package/dist/user.js +34 -4
- package/dist/user.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunks/pers-sdk-D5lE9ZFW.cjs.map +0 -1
- package/dist/chunks/pers-sdk-DnLw822h.js.map +0 -1
- package/dist/chunks/redemption-service-D-hBqh42.js.map +0 -1
- package/dist/chunks/redemption-service-rMB6T2W5.cjs.map +0 -1
- package/dist/chunks/transaction-request.builder-BpgtuMMq.cjs.map +0 -1
- 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-
|
|
11
|
-
var transactionRequest_builder = require('./transaction-request.builder-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
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
|
-
* @
|
|
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
|
|
1986
|
-
* console.log(`Total users: ${
|
|
2105
|
+
* const result = await sdk.users.getAllUsers();
|
|
2106
|
+
* console.log(`Total users: ${result.pagination.total}`);
|
|
1987
2107
|
*
|
|
1988
|
-
*
|
|
1989
|
-
* console.log(`${user.
|
|
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
|
|
3458
|
-
*
|
|
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
|
-
* @
|
|
3619
|
+
* @param options - Pagination options
|
|
3620
|
+
* @returns Promise resolving to paginated list of campaign triggers
|
|
3462
3621
|
*
|
|
3463
3622
|
* @example
|
|
3464
3623
|
* ```typescript
|
|
3465
|
-
*
|
|
3466
|
-
*
|
|
3467
|
-
*
|
|
3468
|
-
*
|
|
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:
|
|
3731
|
+
* Admin: Assign a trigger to a campaign
|
|
3481
3732
|
*
|
|
3482
|
-
* Associates a
|
|
3483
|
-
*
|
|
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
|
|
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
|
-
* '
|
|
3495
|
-
* '
|
|
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
|
-
|
|
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
|
|
4420
|
-
* const allTransactions = await sdk.transactions.
|
|
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
|
-
*
|
|
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
|
-
*
|
|
4463
|
-
*
|
|
4873
|
+
* // Access enriched sender data
|
|
4874
|
+
* if (transaction.included?.sender) {
|
|
4875
|
+
* console.log('Sender:', transaction.included.sender);
|
|
4464
4876
|
* }
|
|
4465
4877
|
*
|
|
4466
|
-
* //
|
|
4467
|
-
* if (transaction.
|
|
4468
|
-
* console.log('
|
|
4469
|
-
*
|
|
4470
|
-
*
|
|
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
|
|
4580
|
-
*
|
|
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
|
|
4584
|
-
* @
|
|
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
|
|
5003
|
+
* const result = await sdk.transactions.getUserTransactionHistory();
|
|
4590
5004
|
*
|
|
4591
|
-
* console.log(`
|
|
5005
|
+
* console.log(`Transaction History (${result.data.length} of ${result.pagination.total} transactions)`);
|
|
4592
5006
|
*
|
|
4593
|
-
*
|
|
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
|
|
5015
|
+
* @example Filter by Role and Status
|
|
4610
5016
|
* ```typescript
|
|
4611
|
-
* // Get only
|
|
4612
|
-
* const
|
|
4613
|
-
*
|
|
4614
|
-
*
|
|
4615
|
-
*
|
|
4616
|
-
*
|
|
4617
|
-
*
|
|
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
|
-
*
|
|
4630
|
-
*
|
|
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
|
-
* //
|
|
4675
|
-
* const
|
|
4676
|
-
*
|
|
4677
|
-
*
|
|
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
|
-
*
|
|
4692
|
-
*
|
|
4693
|
-
*
|
|
4694
|
-
*
|
|
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
|
|
4722
|
-
return this.transactionService.
|
|
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
|
|
6266
|
-
this.analyticsService = new
|
|
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
|
|
6792
|
+
* Get campaign claim analytics with aggregation
|
|
6453
6793
|
*
|
|
6454
|
-
*
|
|
6455
|
-
*
|
|
6456
|
-
*
|
|
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
|
-
* @
|
|
6798
|
+
* @param request - Analytics request with filters, groupBy, and metrics
|
|
6799
|
+
* @returns Promise resolving to campaign claim analytics data
|
|
6459
6800
|
*
|
|
6460
|
-
* @example
|
|
6801
|
+
* @example Claims per campaign
|
|
6461
6802
|
* ```typescript
|
|
6462
|
-
* const
|
|
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
|
-
*
|
|
6465
|
-
*
|
|
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
|
|
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
|
-
*
|
|
6684
|
-
*
|
|
6685
|
-
*
|
|
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
|
-
* @
|
|
6690
|
-
* @
|
|
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
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
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
|
-
|
|
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-
|
|
8022
|
+
//# sourceMappingURL=pers-sdk-Di_R6AiT.cjs.map
|