@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
|
@@ -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-
|
|
9
|
-
import { a as TransactionService, T as TransactionApi } from './transaction-request.builder-
|
|
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 '
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
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
|
-
* @
|
|
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
|
|
1984
|
-
* console.log(`Total users: ${
|
|
2103
|
+
* const result = await sdk.users.getAllUsers();
|
|
2104
|
+
* console.log(`Total users: ${result.pagination.total}`);
|
|
1985
2105
|
*
|
|
1986
|
-
*
|
|
1987
|
-
* console.log(`${user.
|
|
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
|
|
3456
|
-
*
|
|
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
|
-
* @
|
|
3617
|
+
* @param options - Pagination options
|
|
3618
|
+
* @returns Promise resolving to paginated list of campaign triggers
|
|
3460
3619
|
*
|
|
3461
3620
|
* @example
|
|
3462
3621
|
* ```typescript
|
|
3463
|
-
*
|
|
3464
|
-
*
|
|
3465
|
-
*
|
|
3466
|
-
*
|
|
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:
|
|
3729
|
+
* Admin: Assign a trigger to a campaign
|
|
3479
3730
|
*
|
|
3480
|
-
* Associates a
|
|
3481
|
-
*
|
|
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
|
|
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
|
-
* '
|
|
3493
|
-
* '
|
|
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
|
-
|
|
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
|
|
4418
|
-
* const allTransactions = await sdk.transactions.
|
|
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
|
-
*
|
|
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
|
-
*
|
|
4461
|
-
*
|
|
4871
|
+
* // Access enriched sender data
|
|
4872
|
+
* if (transaction.included?.sender) {
|
|
4873
|
+
* console.log('Sender:', transaction.included.sender);
|
|
4462
4874
|
* }
|
|
4463
4875
|
*
|
|
4464
|
-
* //
|
|
4465
|
-
* if (transaction.
|
|
4466
|
-
* console.log('
|
|
4467
|
-
*
|
|
4468
|
-
*
|
|
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
|
|
4578
|
-
*
|
|
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
|
|
4582
|
-
* @
|
|
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
|
|
5001
|
+
* const result = await sdk.transactions.getUserTransactionHistory();
|
|
4588
5002
|
*
|
|
4589
|
-
* console.log(`
|
|
5003
|
+
* console.log(`Transaction History (${result.data.length} of ${result.pagination.total} transactions)`);
|
|
4590
5004
|
*
|
|
4591
|
-
*
|
|
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
|
|
5013
|
+
* @example Filter by Role and Status
|
|
4608
5014
|
* ```typescript
|
|
4609
|
-
* // Get only
|
|
4610
|
-
* const
|
|
4611
|
-
*
|
|
4612
|
-
*
|
|
4613
|
-
*
|
|
4614
|
-
*
|
|
4615
|
-
*
|
|
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
|
-
*
|
|
4628
|
-
*
|
|
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
|
-
* //
|
|
4673
|
-
* const
|
|
4674
|
-
*
|
|
4675
|
-
*
|
|
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
|
-
*
|
|
4690
|
-
*
|
|
4691
|
-
*
|
|
4692
|
-
*
|
|
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
|
|
4720
|
-
return this.transactionService.
|
|
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
|
|
6790
|
+
* Get campaign claim analytics with aggregation
|
|
6451
6791
|
*
|
|
6452
|
-
*
|
|
6453
|
-
*
|
|
6454
|
-
*
|
|
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
|
-
* @
|
|
6796
|
+
* @param request - Analytics request with filters, groupBy, and metrics
|
|
6797
|
+
* @returns Promise resolving to campaign claim analytics data
|
|
6457
6798
|
*
|
|
6458
|
-
* @example
|
|
6799
|
+
* @example Claims per campaign
|
|
6459
6800
|
* ```typescript
|
|
6460
|
-
* const
|
|
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
|
-
*
|
|
6463
|
-
*
|
|
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
|
|
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
|
-
*
|
|
6682
|
-
*
|
|
6683
|
-
*
|
|
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
|
-
* @
|
|
6688
|
-
* @
|
|
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
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
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
|
-
|
|
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,
|
|
7044
|
-
//# sourceMappingURL=pers-sdk-
|
|
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
|