@explorins/pers-sdk 1.6.45 → 1.6.47
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/README.md +185 -0
- package/dist/analytics.cjs +12 -0
- package/dist/analytics.cjs.map +1 -1
- package/dist/analytics.js +1 -1
- package/dist/business/api/business-membership-api.d.ts +186 -0
- package/dist/business/api/business-membership-api.d.ts.map +1 -0
- package/dist/business/index.d.ts +2 -0
- package/dist/business/index.d.ts.map +1 -1
- package/dist/business/services/business-membership-service.d.ts +186 -0
- package/dist/business/services/business-membership-service.d.ts.map +1 -0
- package/dist/business.cjs +727 -9
- package/dist/business.cjs.map +1 -1
- package/dist/business.js +711 -2
- package/dist/business.js.map +1 -1
- package/dist/campaign/api/campaign-api.d.ts +7 -10
- package/dist/campaign/api/campaign-api.d.ts.map +1 -1
- package/dist/campaign/services/campaign-service.d.ts +18 -7
- package/dist/campaign/services/campaign-service.d.ts.map +1 -1
- package/dist/campaign.cjs +13 -1
- package/dist/campaign.cjs.map +1 -1
- package/dist/campaign.js +2 -2
- package/dist/chunks/{campaign-service-CJPXgFBe.js → campaign-service-CKwkiOLx.js} +29 -39
- package/dist/chunks/campaign-service-CKwkiOLx.js.map +1 -0
- package/dist/chunks/{campaign-service-B1tQMNqA.cjs → campaign-service-D-v9ZlUB.cjs} +29 -39
- package/dist/chunks/campaign-service-D-v9ZlUB.cjs.map +1 -0
- package/dist/chunks/{pers-sdk-DzS7mkm7.cjs → pers-sdk-DULFjOW2.cjs} +862 -97
- package/dist/chunks/pers-sdk-DULFjOW2.cjs.map +1 -0
- package/dist/chunks/{pers-sdk-VGEG59g3.js → pers-sdk-VmeBqUEP.js} +858 -97
- package/dist/chunks/pers-sdk-VmeBqUEP.js.map +1 -0
- package/dist/chunks/transaction-request.builder-DltmruUC.js +296 -0
- package/dist/chunks/transaction-request.builder-DltmruUC.js.map +1 -0
- package/dist/chunks/transaction-request.builder-DrqTWcyC.cjs +303 -0
- package/dist/chunks/transaction-request.builder-DrqTWcyC.cjs.map +1 -0
- package/dist/chunks/{user-service-D1Rn4U8u.cjs → user-service-B89wBOV1.cjs} +60 -10
- package/dist/chunks/user-service-B89wBOV1.cjs.map +1 -0
- package/dist/chunks/{user-service-D6mTa_WZ.js → user-service-doT5vsBD.js} +60 -10
- package/dist/chunks/user-service-doT5vsBD.js.map +1 -0
- package/dist/chunks/{web3-chain-service-BLFxB5TA.cjs → web3-chain-service-6vsVHPjl.cjs} +116 -16
- package/dist/chunks/web3-chain-service-6vsVHPjl.cjs.map +1 -0
- package/dist/chunks/{web3-chain-service-JRSwxr-s.js → web3-chain-service-BcUeeujC.js} +111 -17
- package/dist/chunks/web3-chain-service-BcUeeujC.js.map +1 -0
- package/dist/core/auth/api/auth-api.d.ts +35 -0
- package/dist/core/auth/api/auth-api.d.ts.map +1 -1
- package/dist/core/auth/auth-provider.interface.d.ts +7 -1
- package/dist/core/auth/auth-provider.interface.d.ts.map +1 -1
- package/dist/core/auth/services/auth-service.d.ts +26 -1
- package/dist/core/auth/services/auth-service.d.ts.map +1 -1
- package/dist/core/auth/token-storage.d.ts +3 -2
- package/dist/core/auth/token-storage.d.ts.map +1 -1
- package/dist/core/errors/index.d.ts +75 -6
- package/dist/core/errors/index.d.ts.map +1 -1
- package/dist/core/events/event-emitter.d.ts +106 -0
- package/dist/core/events/event-emitter.d.ts.map +1 -0
- package/dist/core/events/event-types.d.ts +127 -0
- package/dist/core/events/event-types.d.ts.map +1 -0
- package/dist/core/events/index.d.ts +22 -0
- package/dist/core/events/index.d.ts.map +1 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/pers-api-client.d.ts +12 -0
- package/dist/core/pers-api-client.d.ts.map +1 -1
- package/dist/core/version.d.ts +15 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/core.cjs +19 -6
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +6 -6
- package/dist/donation.cjs +12 -0
- package/dist/donation.cjs.map +1 -1
- package/dist/donation.js +1 -1
- package/dist/index.cjs +43 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7 -6
- package/dist/index.js.map +1 -1
- package/dist/managers/auth-manager.d.ts +77 -4
- package/dist/managers/auth-manager.d.ts.map +1 -1
- package/dist/managers/business-manager.d.ts +192 -4
- package/dist/managers/business-manager.d.ts.map +1 -1
- package/dist/managers/campaign-manager.d.ts +48 -65
- package/dist/managers/campaign-manager.d.ts.map +1 -1
- package/dist/managers/redemption-manager.d.ts +3 -1
- package/dist/managers/redemption-manager.d.ts.map +1 -1
- package/dist/managers/transaction-manager.d.ts +4 -2
- package/dist/managers/transaction-manager.d.ts.map +1 -1
- package/dist/managers/user-manager.d.ts +57 -1
- package/dist/managers/user-manager.d.ts.map +1 -1
- package/dist/managers/web3-manager.d.ts.map +1 -1
- package/dist/package.json +2 -2
- package/dist/payment.cjs +12 -0
- package/dist/payment.cjs.map +1 -1
- package/dist/payment.js +1 -1
- package/dist/pers-sdk.d.ts +49 -0
- package/dist/pers-sdk.d.ts.map +1 -1
- package/dist/redemption.cjs +12 -0
- package/dist/redemption.cjs.map +1 -1
- package/dist/redemption.js +1 -1
- package/dist/shared/interfaces/pers-shared-lib.interfaces.d.ts +2 -1
- package/dist/shared/interfaces/pers-shared-lib.interfaces.d.ts.map +1 -1
- package/dist/tenant.cjs +12 -0
- package/dist/tenant.cjs.map +1 -1
- package/dist/tenant.js +1 -1
- package/dist/token.cjs +12 -0
- package/dist/token.cjs.map +1 -1
- package/dist/token.js +1 -1
- package/dist/transaction/models/index.d.ts +2 -0
- package/dist/transaction/models/index.d.ts.map +1 -1
- package/dist/transaction/models/transaction-request.builder.d.ts +256 -0
- package/dist/transaction/models/transaction-request.builder.d.ts.map +1 -0
- package/dist/transaction.cjs +7 -0
- package/dist/transaction.cjs.map +1 -1
- package/dist/transaction.js +1 -0
- package/dist/transaction.js.map +1 -1
- package/dist/user/api/user-api.d.ts +28 -7
- package/dist/user/api/user-api.d.ts.map +1 -1
- package/dist/user/services/user-service.d.ts +21 -0
- package/dist/user/services/user-service.d.ts.map +1 -1
- package/dist/user-status.cjs +12 -0
- package/dist/user-status.cjs.map +1 -1
- package/dist/user-status.js +1 -1
- package/dist/user.cjs +13 -1
- package/dist/user.cjs.map +1 -1
- package/dist/user.js +2 -2
- package/dist/web3-chain.cjs +13 -1
- package/dist/web3-chain.cjs.map +1 -1
- package/dist/web3-chain.js +2 -2
- package/package.json +2 -2
- package/dist/chunks/business-service-8Xd3d5oY.js +0 -238
- package/dist/chunks/business-service-8Xd3d5oY.js.map +0 -1
- package/dist/chunks/business-service-P9o4cwQL.cjs +0 -241
- package/dist/chunks/business-service-P9o4cwQL.cjs.map +0 -1
- package/dist/chunks/campaign-service-B1tQMNqA.cjs.map +0 -1
- package/dist/chunks/campaign-service-CJPXgFBe.js.map +0 -1
- package/dist/chunks/pers-sdk-DzS7mkm7.cjs.map +0 -1
- package/dist/chunks/pers-sdk-VGEG59g3.js.map +0 -1
- package/dist/chunks/user-service-D1Rn4U8u.cjs.map +0 -1
- package/dist/chunks/user-service-D6mTa_WZ.js.map +0 -1
- package/dist/chunks/web3-chain-service-BLFxB5TA.cjs.map +0 -1
- package/dist/chunks/web3-chain-service-JRSwxr-s.js.map +0 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var persShared = require('@explorins/pers-shared');
|
|
4
|
-
var web3ChainService = require('./web3-chain-service-
|
|
5
|
-
var userService = require('./user-service-
|
|
4
|
+
var web3ChainService = require('./web3-chain-service-6vsVHPjl.cjs');
|
|
5
|
+
var userService = require('./user-service-B89wBOV1.cjs');
|
|
6
6
|
var userStatus = require('../user-status.cjs');
|
|
7
7
|
var tokenService = require('./token-service-BWScn8Qa.cjs');
|
|
8
|
-
var
|
|
9
|
-
var campaignService = require('./campaign-service-
|
|
8
|
+
var business = require('../business.cjs');
|
|
9
|
+
var campaignService = require('./campaign-service-D-v9ZlUB.cjs');
|
|
10
10
|
var redemptionService = require('./redemption-service-7qbeQxEM.cjs');
|
|
11
11
|
var transactionService = require('./transaction-service-CXjTHCFu.cjs');
|
|
12
12
|
var paymentService = require('./payment-service-B4qx0qiE.cjs');
|
|
@@ -61,6 +61,11 @@ function mergeWithDefaults(config) {
|
|
|
61
61
|
/**
|
|
62
62
|
* Platform-Agnostic Auth API Client
|
|
63
63
|
* Handles authentication operations using the PERS backend
|
|
64
|
+
*
|
|
65
|
+
* Supports the universal token endpoint:
|
|
66
|
+
* - User authentication (default)
|
|
67
|
+
* - Business authentication with context selection
|
|
68
|
+
* - Admin/Tenant authentication
|
|
64
69
|
*/
|
|
65
70
|
class AuthApi {
|
|
66
71
|
constructor(apiClient) {
|
|
@@ -87,6 +92,36 @@ class AuthApi {
|
|
|
87
92
|
};
|
|
88
93
|
return this.apiClient.post(`${this.basePath}/token`, body, { bypassAuth: true });
|
|
89
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Login as business with JWT
|
|
97
|
+
*
|
|
98
|
+
* Authenticates a user in a business context with role included in JWT.
|
|
99
|
+
*
|
|
100
|
+
* @param jwt - Authentication token (passkey or Firebase JWT)
|
|
101
|
+
* @param options - Business authentication options
|
|
102
|
+
* @param options.businessId - The business ID to authenticate as
|
|
103
|
+
* - If user has single business membership, auto-selected
|
|
104
|
+
* - If user has multiple memberships without businessId, throws MULTIPLE_CONTEXT_SELECTION_REQUIRED
|
|
105
|
+
* @returns Session response with business context and role in JWT
|
|
106
|
+
* @throws MultipleContextSelectionError when businessId is required but not provided
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* // Single business membership - auto-selects
|
|
111
|
+
* const response = await authApi.loginBusiness(jwt);
|
|
112
|
+
*
|
|
113
|
+
* // Multiple memberships - explicit selection
|
|
114
|
+
* const response = await authApi.loginBusiness(jwt, { businessId: 'biz-123' });
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
async loginBusiness(jwt, options) {
|
|
118
|
+
const body = {
|
|
119
|
+
authToken: jwt,
|
|
120
|
+
authType: persShared.AccountOwnerType.BUSINESS,
|
|
121
|
+
context: options?.businessId ? { businessId: options.businessId } : undefined
|
|
122
|
+
};
|
|
123
|
+
return this.apiClient.post(`${this.basePath}/token`, body, { bypassAuth: true });
|
|
124
|
+
}
|
|
90
125
|
/**
|
|
91
126
|
* Login user with raw data (no external authentication)
|
|
92
127
|
*/
|
|
@@ -174,6 +209,37 @@ class AuthService {
|
|
|
174
209
|
}
|
|
175
210
|
return response;
|
|
176
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Login as business with JWT
|
|
214
|
+
*
|
|
215
|
+
* Authenticates a user in a business context. The returned JWT contains
|
|
216
|
+
* the user's role within that business.
|
|
217
|
+
*
|
|
218
|
+
* @param jwt - Authentication token (passkey or Firebase JWT)
|
|
219
|
+
* @param options - Business authentication options
|
|
220
|
+
* @param options.businessId - The business ID to authenticate as
|
|
221
|
+
* - If user has single business membership, auto-selected
|
|
222
|
+
* - If user has multiple memberships without businessId, throws MULTIPLE_CONTEXT_SELECTION_REQUIRED
|
|
223
|
+
* @returns Session response with business context and role baked into JWT
|
|
224
|
+
* @throws MultipleContextSelectionRequiredError when businessId is required but not provided
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* // Auto-select if single membership
|
|
229
|
+
* const response = await authService.loginBusiness(jwt);
|
|
230
|
+
*
|
|
231
|
+
* // Explicit business selection
|
|
232
|
+
* const response = await authService.loginBusiness(jwt, { businessId: 'biz-123' });
|
|
233
|
+
* console.log('Business:', response.business?.displayName);
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
async loginBusiness(jwt, options) {
|
|
237
|
+
const response = await this.authApi.loginBusiness(jwt, options);
|
|
238
|
+
if (this.authProvider && response.accessToken) {
|
|
239
|
+
await this.storeTokens(response.accessToken, response.refreshToken, 'business', jwt);
|
|
240
|
+
}
|
|
241
|
+
return response;
|
|
242
|
+
}
|
|
177
243
|
/**
|
|
178
244
|
* Login user with raw data (no external auth)
|
|
179
245
|
*/
|
|
@@ -743,6 +809,21 @@ class DefaultAuthProvider {
|
|
|
743
809
|
}
|
|
744
810
|
}
|
|
745
811
|
|
|
812
|
+
/**
|
|
813
|
+
* SDK Version Information
|
|
814
|
+
*
|
|
815
|
+
* Exported for consumers who need version info.
|
|
816
|
+
* Used internally for X-SDK-Version header.
|
|
817
|
+
*
|
|
818
|
+
* @module @explorins/pers-sdk/core
|
|
819
|
+
*/
|
|
820
|
+
/** SDK package name */
|
|
821
|
+
const SDK_NAME = '@explorins/pers-sdk';
|
|
822
|
+
/** SDK version - update on each release (should match package.json) */
|
|
823
|
+
const SDK_VERSION = '1.6.48';
|
|
824
|
+
/** Full SDK identifier for headers */
|
|
825
|
+
const SDK_USER_AGENT = `${SDK_NAME}/${SDK_VERSION}`;
|
|
826
|
+
|
|
746
827
|
// packages/pers-sdk/src/core/pers-api-client.ts
|
|
747
828
|
/**
|
|
748
829
|
* PERS API Client - Platform-agnostic HTTP client with authentication
|
|
@@ -883,6 +964,7 @@ class PersApiClient {
|
|
|
883
964
|
const backendError = web3ChainService.ErrorUtils.extractBackendErrorDetails(error);
|
|
884
965
|
// If this IS a refresh request that failed with 401, don't retry to avoid infinite loop
|
|
885
966
|
if (options?.isRefreshRequest) {
|
|
967
|
+
this.emitErrorEvent(backendError, errorMessage, endpoint, method, status, error);
|
|
886
968
|
throw new web3ChainService.AuthenticationError(backendError.userMessage || backendError.message || 'Refresh token expired', endpoint, method, backendError.code, backendError.userMessage, backendError.title);
|
|
887
969
|
}
|
|
888
970
|
// For regular requests: try refresh once, then fail
|
|
@@ -900,11 +982,47 @@ class PersApiClient {
|
|
|
900
982
|
}
|
|
901
983
|
// Auth failure - let AuthService handle cleanup and notify app
|
|
902
984
|
await this.authService.handleAuthFailure();
|
|
985
|
+
this.emitErrorEvent(backendError, errorMessage, endpoint, method, status, error);
|
|
903
986
|
throw new web3ChainService.AuthenticationError(backendError.userMessage || backendError.message || 'Authentication required', endpoint, method, backendError.code, backendError.userMessage, backendError.title);
|
|
904
987
|
}
|
|
905
|
-
|
|
988
|
+
// Extract backend error details for non-401 errors
|
|
989
|
+
const errorDetails = web3ChainService.ErrorUtils.extractBackendErrorDetails(error);
|
|
990
|
+
this.emitErrorEvent(errorDetails, errorMessage, endpoint, method, status, error);
|
|
991
|
+
throw new web3ChainService.PersApiError(errorMessage, endpoint, method, status || undefined, web3ChainService.ErrorUtils.isRetryable(error), errorDetails);
|
|
906
992
|
}
|
|
907
993
|
}
|
|
994
|
+
/**
|
|
995
|
+
* Emit error event if events emitter is available
|
|
996
|
+
* @internal
|
|
997
|
+
*/
|
|
998
|
+
emitErrorEvent(errorDetails, errorMessage, endpoint, method, status, error) {
|
|
999
|
+
console.log('[PersApiClient] emitErrorEvent called', {
|
|
1000
|
+
hasEvents: !!this._events,
|
|
1001
|
+
instanceId: this._events?.instanceId ?? 'none',
|
|
1002
|
+
subscriberCount: this._events?.subscriberCount ?? 0,
|
|
1003
|
+
domain: errorDetails.domain,
|
|
1004
|
+
userMessage: errorDetails.userMessage || errorMessage
|
|
1005
|
+
});
|
|
1006
|
+
this._events?.emitError({
|
|
1007
|
+
domain: errorDetails.domain || 'external',
|
|
1008
|
+
type: errorDetails.code || 'API_ERROR',
|
|
1009
|
+
userMessage: errorDetails.userMessage || errorMessage,
|
|
1010
|
+
code: errorDetails.code,
|
|
1011
|
+
details: {
|
|
1012
|
+
endpoint,
|
|
1013
|
+
method,
|
|
1014
|
+
status: status || undefined,
|
|
1015
|
+
retryable: web3ChainService.ErrorUtils.isRetryable(error)
|
|
1016
|
+
}
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Set event emitter for error event emission
|
|
1021
|
+
* @internal
|
|
1022
|
+
*/
|
|
1023
|
+
setEvents(events) {
|
|
1024
|
+
this._events = events;
|
|
1025
|
+
}
|
|
908
1026
|
/**
|
|
909
1027
|
* Performs an authenticated GET request
|
|
910
1028
|
*
|
|
@@ -950,6 +1068,7 @@ class PersApiClient {
|
|
|
950
1068
|
async getHeaders(includeAuth = true, method, url) {
|
|
951
1069
|
const headers = {
|
|
952
1070
|
'Content-Type': 'application/json',
|
|
1071
|
+
'X-SDK-Version': SDK_USER_AGENT,
|
|
953
1072
|
};
|
|
954
1073
|
if (this.mergedConfig.authProvider) {
|
|
955
1074
|
let token = null;
|
|
@@ -1156,12 +1275,231 @@ function warnIfProblematicEnvironment(feature) {
|
|
|
1156
1275
|
}
|
|
1157
1276
|
}
|
|
1158
1277
|
|
|
1278
|
+
/**
|
|
1279
|
+
* PERS SDK Event Emitter
|
|
1280
|
+
*
|
|
1281
|
+
* Simplified global event stream.
|
|
1282
|
+
* Platform-agnostic, zero dependencies.
|
|
1283
|
+
*
|
|
1284
|
+
* @module @explorins/pers-sdk/events
|
|
1285
|
+
*/
|
|
1286
|
+
/**
|
|
1287
|
+
* Generates a unique event ID
|
|
1288
|
+
*/
|
|
1289
|
+
function generateEventId() {
|
|
1290
|
+
return `evt_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* Simplified event emitter - single global stream
|
|
1294
|
+
*
|
|
1295
|
+
* All events flow through one subscription point.
|
|
1296
|
+
* Optional filtering at subscription level.
|
|
1297
|
+
*
|
|
1298
|
+
* @example Basic Usage
|
|
1299
|
+
* ```typescript
|
|
1300
|
+
* // Subscribe to ALL events - one handler
|
|
1301
|
+
* const unsubscribe = sdk.events.subscribe((event) => {
|
|
1302
|
+
* showNotification(event.userMessage, event.level);
|
|
1303
|
+
* });
|
|
1304
|
+
*
|
|
1305
|
+
* // With filter - only transaction errors
|
|
1306
|
+
* sdk.events.subscribe((event) => {
|
|
1307
|
+
* showErrorToast(event.userMessage);
|
|
1308
|
+
* }, { domains: ['transaction'], levels: ['error'] });
|
|
1309
|
+
*
|
|
1310
|
+
* // Multiple domains (whitelist)
|
|
1311
|
+
* sdk.events.subscribe((event) => {
|
|
1312
|
+
* showNotification(event.userMessage);
|
|
1313
|
+
* }, { domains: ['transaction', 'campaign', 'redemption'] });
|
|
1314
|
+
*
|
|
1315
|
+
* // Exclude domains (blacklist)
|
|
1316
|
+
* sdk.events.subscribe((event) => {
|
|
1317
|
+
* showNotification(event.userMessage);
|
|
1318
|
+
* }, { excludeDomains: ['validation'] });
|
|
1319
|
+
*
|
|
1320
|
+
* // Cleanup
|
|
1321
|
+
* unsubscribe();
|
|
1322
|
+
* ```
|
|
1323
|
+
*/
|
|
1324
|
+
let emitterInstanceCounter = 0;
|
|
1325
|
+
class PersEventEmitter {
|
|
1326
|
+
constructor() {
|
|
1327
|
+
this.handlers = new Set();
|
|
1328
|
+
this._instanceId = ++emitterInstanceCounter;
|
|
1329
|
+
console.log(`[PersEventEmitter] Instance #${this._instanceId} created`);
|
|
1330
|
+
}
|
|
1331
|
+
get instanceId() {
|
|
1332
|
+
return this._instanceId;
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
* Subscribe to events
|
|
1336
|
+
*
|
|
1337
|
+
* @param handler - Callback for matching events
|
|
1338
|
+
* @param filter - Optional filter by domain and/or level
|
|
1339
|
+
* @returns Unsubscribe function
|
|
1340
|
+
*
|
|
1341
|
+
* @example All events
|
|
1342
|
+
* ```typescript
|
|
1343
|
+
* const unsub = sdk.events.subscribe((event) => {
|
|
1344
|
+
* console.log(`[${event.domain}] ${event.type}: ${event.userMessage}`);
|
|
1345
|
+
* });
|
|
1346
|
+
* ```
|
|
1347
|
+
*
|
|
1348
|
+
* @example Only errors
|
|
1349
|
+
* ```typescript
|
|
1350
|
+
* sdk.events.subscribe((event) => {
|
|
1351
|
+
* logToSentry(event);
|
|
1352
|
+
* }, { levels: ['error'] });
|
|
1353
|
+
* ```
|
|
1354
|
+
*
|
|
1355
|
+
* @example Only transaction successes
|
|
1356
|
+
* ```typescript
|
|
1357
|
+
* sdk.events.subscribe((event) => {
|
|
1358
|
+
* playSuccessSound();
|
|
1359
|
+
* confetti();
|
|
1360
|
+
* }, { domains: ['transaction'], levels: ['success'] });
|
|
1361
|
+
* ```
|
|
1362
|
+
*/
|
|
1363
|
+
subscribe(handler, filter) {
|
|
1364
|
+
const filteredHandler = { handler, filter };
|
|
1365
|
+
this.handlers.add(filteredHandler);
|
|
1366
|
+
return () => this.handlers.delete(filteredHandler);
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Subscribe and auto-unsubscribe after first matching event
|
|
1370
|
+
*
|
|
1371
|
+
* @param handler - Callback for the first matching event
|
|
1372
|
+
* @param filter - Optional filter by domain and/or level
|
|
1373
|
+
* @returns Unsubscribe function
|
|
1374
|
+
*/
|
|
1375
|
+
once(handler, filter) {
|
|
1376
|
+
const filteredHandler = {
|
|
1377
|
+
handler: (event) => {
|
|
1378
|
+
this.handlers.delete(filteredHandler);
|
|
1379
|
+
handler(event);
|
|
1380
|
+
},
|
|
1381
|
+
filter
|
|
1382
|
+
};
|
|
1383
|
+
this.handlers.add(filteredHandler);
|
|
1384
|
+
return () => this.handlers.delete(filteredHandler);
|
|
1385
|
+
}
|
|
1386
|
+
/**
|
|
1387
|
+
* Emit a success event
|
|
1388
|
+
*
|
|
1389
|
+
* Domain is restricted to business domains only (Domain type).
|
|
1390
|
+
*
|
|
1391
|
+
* @param event - Success event data (id and timestamp auto-generated)
|
|
1392
|
+
* @returns The complete event object
|
|
1393
|
+
*
|
|
1394
|
+
* @example
|
|
1395
|
+
* ```typescript
|
|
1396
|
+
* sdk.events.emitSuccess({
|
|
1397
|
+
* domain: 'transaction', // Only business domains allowed
|
|
1398
|
+
* type: 'CONFIRMED',
|
|
1399
|
+
* userMessage: 'Transaction confirmed!'
|
|
1400
|
+
* });
|
|
1401
|
+
* ```
|
|
1402
|
+
*/
|
|
1403
|
+
emitSuccess(event) {
|
|
1404
|
+
const fullEvent = {
|
|
1405
|
+
...event,
|
|
1406
|
+
level: 'success',
|
|
1407
|
+
id: generateEventId(),
|
|
1408
|
+
timestamp: Date.now()
|
|
1409
|
+
};
|
|
1410
|
+
this.notifyHandlers(fullEvent);
|
|
1411
|
+
return fullEvent;
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Emit an error event
|
|
1415
|
+
*
|
|
1416
|
+
* Domain can be any domain including technical (ErrorDomain type).
|
|
1417
|
+
*
|
|
1418
|
+
* @param event - Error event data (id and timestamp auto-generated)
|
|
1419
|
+
* @returns The complete event object
|
|
1420
|
+
*
|
|
1421
|
+
* @example
|
|
1422
|
+
* ```typescript
|
|
1423
|
+
* sdk.events.emitError({
|
|
1424
|
+
* domain: 'validation', // Technical domains allowed
|
|
1425
|
+
* type: 'INVALID_INPUT',
|
|
1426
|
+
* userMessage: 'Please check your input'
|
|
1427
|
+
* });
|
|
1428
|
+
* ```
|
|
1429
|
+
*/
|
|
1430
|
+
emitError(event) {
|
|
1431
|
+
const fullEvent = {
|
|
1432
|
+
...event,
|
|
1433
|
+
level: 'error',
|
|
1434
|
+
id: generateEventId(),
|
|
1435
|
+
timestamp: Date.now()
|
|
1436
|
+
};
|
|
1437
|
+
this.notifyHandlers(fullEvent);
|
|
1438
|
+
return fullEvent;
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Check if event matches filter
|
|
1442
|
+
*/
|
|
1443
|
+
matchesFilter(event, filter) {
|
|
1444
|
+
// Level filtering
|
|
1445
|
+
if (filter.levels && !filter.levels.includes(event.level))
|
|
1446
|
+
return false;
|
|
1447
|
+
// Domain exclusion (blacklist) - checked first
|
|
1448
|
+
if (filter.excludeDomains && filter.excludeDomains.includes(event.domain))
|
|
1449
|
+
return false;
|
|
1450
|
+
// Domain inclusion (whitelist)
|
|
1451
|
+
if (filter.domains && !filter.domains.includes(event.domain))
|
|
1452
|
+
return false;
|
|
1453
|
+
return true;
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Notify all handlers of an event (applying filters)
|
|
1457
|
+
*/
|
|
1458
|
+
notifyHandlers(event) {
|
|
1459
|
+
for (const { handler, filter } of this.handlers) {
|
|
1460
|
+
// Apply filter if present
|
|
1461
|
+
if (filter && !this.matchesFilter(event, filter)) {
|
|
1462
|
+
continue;
|
|
1463
|
+
}
|
|
1464
|
+
try {
|
|
1465
|
+
const result = handler(event);
|
|
1466
|
+
// Catch async handler errors too
|
|
1467
|
+
if (result && typeof result.catch === 'function') {
|
|
1468
|
+
result.catch(error => {
|
|
1469
|
+
console.error('[PersEventEmitter] Async handler error:', error);
|
|
1470
|
+
});
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
catch (error) {
|
|
1474
|
+
console.error('[PersEventEmitter] Handler error:', error);
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
/**
|
|
1479
|
+
* Remove all handlers
|
|
1480
|
+
*/
|
|
1481
|
+
clear() {
|
|
1482
|
+
this.handlers.clear();
|
|
1483
|
+
}
|
|
1484
|
+
/**
|
|
1485
|
+
* Get count of active subscriptions
|
|
1486
|
+
*/
|
|
1487
|
+
get subscriberCount() {
|
|
1488
|
+
return this.handlers.size;
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1159
1492
|
/**
|
|
1160
1493
|
* Authentication Manager - Clean, high-level interface for authentication operations
|
|
1161
1494
|
*
|
|
1162
1495
|
* Provides a simplified API for common authentication tasks while maintaining
|
|
1163
1496
|
* access to the underlying API client for advanced use cases.
|
|
1164
1497
|
*
|
|
1498
|
+
* Supports the universal token endpoint (POST /auth/token):
|
|
1499
|
+
* - User authentication (default)
|
|
1500
|
+
* - Business authentication with role in JWT
|
|
1501
|
+
* - Admin/Tenant authentication
|
|
1502
|
+
*
|
|
1165
1503
|
* @group Managers
|
|
1166
1504
|
* @category Authentication
|
|
1167
1505
|
*
|
|
@@ -1170,6 +1508,10 @@ function warnIfProblematicEnvironment(feature) {
|
|
|
1170
1508
|
* // Login with external JWT
|
|
1171
1509
|
* const authResult = await sdk.auth.loginWithToken(firebaseJWT, 'user');
|
|
1172
1510
|
*
|
|
1511
|
+
* // Login as business (with role in JWT)
|
|
1512
|
+
* const bizResult = await sdk.auth.loginAsBusiness(jwt, { businessId: 'biz-123' });
|
|
1513
|
+
* console.log('Business:', bizResult.business?.displayName);
|
|
1514
|
+
*
|
|
1173
1515
|
* // Check authentication
|
|
1174
1516
|
* if (await sdk.auth.isAuthenticated()) {
|
|
1175
1517
|
* const user = await sdk.auth.getCurrentUser();
|
|
@@ -1181,8 +1523,9 @@ function warnIfProblematicEnvironment(feature) {
|
|
|
1181
1523
|
* ```
|
|
1182
1524
|
*/
|
|
1183
1525
|
class AuthManager {
|
|
1184
|
-
constructor(apiClient) {
|
|
1526
|
+
constructor(apiClient, events) {
|
|
1185
1527
|
this.apiClient = apiClient;
|
|
1528
|
+
this.events = events;
|
|
1186
1529
|
}
|
|
1187
1530
|
/**
|
|
1188
1531
|
* Login with JWT token
|
|
@@ -1211,8 +1554,78 @@ class AuthManager {
|
|
|
1211
1554
|
const result = userType === 'admin'
|
|
1212
1555
|
? await authService.loginTenantAdmin(jwtToken)
|
|
1213
1556
|
: await authService.loginUser(jwtToken);
|
|
1557
|
+
this.events?.emitSuccess({
|
|
1558
|
+
domain: 'authentication',
|
|
1559
|
+
type: 'LOGIN_SUCCESS',
|
|
1560
|
+
userMessage: 'Successfully logged in'
|
|
1561
|
+
});
|
|
1214
1562
|
return result;
|
|
1215
1563
|
}
|
|
1564
|
+
/**
|
|
1565
|
+
* Login as business with JWT token
|
|
1566
|
+
*
|
|
1567
|
+
* Authenticates a user in a business context. The returned JWT contains
|
|
1568
|
+
* the user's role (OWNER, ADMIN, EDITOR, VIEWER) within that business.
|
|
1569
|
+
*
|
|
1570
|
+
* **Auto-Selection Behavior:**
|
|
1571
|
+
* - If user has a single business membership, it's auto-selected
|
|
1572
|
+
* - If user has multiple memberships and no businessId is provided,
|
|
1573
|
+
* throws `MULTIPLE_CONTEXT_SELECTION_REQUIRED` error with available options
|
|
1574
|
+
*
|
|
1575
|
+
* @param jwtToken - JWT token from auth provider (passkey, Firebase, etc.)
|
|
1576
|
+
* @param options - Business authentication options
|
|
1577
|
+
* @param options.businessId - The business ID to authenticate as (required for multi-business users)
|
|
1578
|
+
* @returns Promise resolving to authentication response with business context and role in JWT
|
|
1579
|
+
* @throws Error with code `MULTIPLE_CONTEXT_SELECTION_REQUIRED` when businessId is needed
|
|
1580
|
+
*
|
|
1581
|
+
* @example Single Business Membership
|
|
1582
|
+
* ```typescript
|
|
1583
|
+
* // Auto-selects the user's only business
|
|
1584
|
+
* const result = await sdk.auth.loginAsBusiness(jwt);
|
|
1585
|
+
* console.log('Business:', result.business?.displayName);
|
|
1586
|
+
* ```
|
|
1587
|
+
*
|
|
1588
|
+
* @example Multiple Business Memberships
|
|
1589
|
+
* ```typescript
|
|
1590
|
+
* try {
|
|
1591
|
+
* const result = await sdk.auth.loginAsBusiness(jwt);
|
|
1592
|
+
* } catch (error) {
|
|
1593
|
+
* if (error.code === 'MULTIPLE_CONTEXT_SELECTION_REQUIRED') {
|
|
1594
|
+
* // Show business selector UI
|
|
1595
|
+
* const selectedId = await showBusinessSelector(error.availableOptions);
|
|
1596
|
+
* const result = await sdk.auth.loginAsBusiness(jwt, { businessId: selectedId });
|
|
1597
|
+
* }
|
|
1598
|
+
* }
|
|
1599
|
+
* ```
|
|
1600
|
+
*
|
|
1601
|
+
* @example Direct Business Selection
|
|
1602
|
+
* ```typescript
|
|
1603
|
+
* const result = await sdk.auth.loginAsBusiness(jwt, { businessId: 'biz-123' });
|
|
1604
|
+
* console.log('Authenticated as:', result.business?.displayName);
|
|
1605
|
+
* ```
|
|
1606
|
+
*/
|
|
1607
|
+
async loginAsBusiness(jwtToken, options) {
|
|
1608
|
+
const authService = this.apiClient.getAuthService();
|
|
1609
|
+
return authService.loginBusiness(jwtToken, options);
|
|
1610
|
+
}
|
|
1611
|
+
/**
|
|
1612
|
+
* Get current business context
|
|
1613
|
+
*
|
|
1614
|
+
* Retrieves the current business context if authenticated as business.
|
|
1615
|
+
* Requires prior business authentication via {@link loginAsBusiness}.
|
|
1616
|
+
*
|
|
1617
|
+
* @returns Promise resolving to current business data
|
|
1618
|
+
* @throws {PersApiError} When not authenticated as business
|
|
1619
|
+
*
|
|
1620
|
+
* @example
|
|
1621
|
+
* ```typescript
|
|
1622
|
+
* const business = await sdk.auth.getCurrentBusiness();
|
|
1623
|
+
* console.log('Current business:', business.displayName);
|
|
1624
|
+
* ```
|
|
1625
|
+
*/
|
|
1626
|
+
async getCurrentBusiness() {
|
|
1627
|
+
return this.apiClient.get('/businesses/me');
|
|
1628
|
+
}
|
|
1216
1629
|
/**
|
|
1217
1630
|
* Login with raw user data
|
|
1218
1631
|
*
|
|
@@ -1414,8 +1827,9 @@ class AuthManager {
|
|
|
1414
1827
|
* ```
|
|
1415
1828
|
*/
|
|
1416
1829
|
class UserManager {
|
|
1417
|
-
constructor(apiClient) {
|
|
1830
|
+
constructor(apiClient, events) {
|
|
1418
1831
|
this.apiClient = apiClient;
|
|
1832
|
+
this.events = events;
|
|
1419
1833
|
const userApi = new userService.UserApi(apiClient);
|
|
1420
1834
|
this.userService = new userService.UserService(userApi);
|
|
1421
1835
|
}
|
|
@@ -1471,7 +1885,14 @@ class UserManager {
|
|
|
1471
1885
|
* ```
|
|
1472
1886
|
*/
|
|
1473
1887
|
async updateCurrentUser(userData) {
|
|
1474
|
-
|
|
1888
|
+
const result = await this.userService.updateRemoteUser(userData);
|
|
1889
|
+
this.events?.emitSuccess({
|
|
1890
|
+
domain: 'user',
|
|
1891
|
+
type: 'PROFILE_UPDATED',
|
|
1892
|
+
userMessage: 'Profile updated successfully',
|
|
1893
|
+
details: { userId: result.id }
|
|
1894
|
+
});
|
|
1895
|
+
return result;
|
|
1475
1896
|
}
|
|
1476
1897
|
/**
|
|
1477
1898
|
* Get user by unique identifier
|
|
@@ -1568,6 +1989,64 @@ class UserManager {
|
|
|
1568
1989
|
async getAllUsers() {
|
|
1569
1990
|
return this.userService.getAllRemoteUsers();
|
|
1570
1991
|
}
|
|
1992
|
+
/**
|
|
1993
|
+
* Business/Admin: Create or update a user
|
|
1994
|
+
*
|
|
1995
|
+
* Creates a new user or updates an existing one. This method requires
|
|
1996
|
+
* business authentication (with canManageUsers permission) or admin authentication.
|
|
1997
|
+
*
|
|
1998
|
+
* @param userData - User data for creation/update
|
|
1999
|
+
* @returns Promise resolving to created or updated user
|
|
2000
|
+
* @throws {PersApiError} When not authenticated or insufficient permissions
|
|
2001
|
+
*
|
|
2002
|
+
* @example Create New User
|
|
2003
|
+
* ```typescript
|
|
2004
|
+
* // Business or Admin operation - create a new user
|
|
2005
|
+
* const newUser = await sdk.users.createOrUpdateUser({
|
|
2006
|
+
* identifierEmail: 'newuser@example.com',
|
|
2007
|
+
* firstName: 'John',
|
|
2008
|
+
* lastName: 'Doe',
|
|
2009
|
+
* externalId: 'external-123'
|
|
2010
|
+
* });
|
|
2011
|
+
* console.log('User created:', newUser.id);
|
|
2012
|
+
* ```
|
|
2013
|
+
*
|
|
2014
|
+
* @example Update Existing User
|
|
2015
|
+
* ```typescript
|
|
2016
|
+
* // If user with same identifier exists, it will be updated
|
|
2017
|
+
* const updated = await sdk.users.createOrUpdateUser({
|
|
2018
|
+
* identifierEmail: 'existing@example.com',
|
|
2019
|
+
* firstName: 'Updated Name'
|
|
2020
|
+
* });
|
|
2021
|
+
* ```
|
|
2022
|
+
*/
|
|
2023
|
+
async createOrUpdateUser(userData) {
|
|
2024
|
+
return this.userService.createOrUpdateUser(userData);
|
|
2025
|
+
}
|
|
2026
|
+
/**
|
|
2027
|
+
* Admin: Bulk create or update users
|
|
2028
|
+
*
|
|
2029
|
+
* Creates or updates multiple users in a single operation. This method
|
|
2030
|
+
* requires admin authentication - business users cannot perform bulk operations.
|
|
2031
|
+
*
|
|
2032
|
+
* @param users - Array of user data for creation/update
|
|
2033
|
+
* @returns Promise resolving to array of created/updated users
|
|
2034
|
+
* @throws {PersApiError} When not authenticated as admin
|
|
2035
|
+
*
|
|
2036
|
+
* @example Bulk User Creation
|
|
2037
|
+
* ```typescript
|
|
2038
|
+
* // Admin-only operation - bulk create users
|
|
2039
|
+
* const users = await sdk.users.createOrUpdateUsers([
|
|
2040
|
+
* { identifierEmail: 'user1@example.com', firstName: 'User', lastName: 'One' },
|
|
2041
|
+
* { identifierEmail: 'user2@example.com', firstName: 'User', lastName: 'Two' },
|
|
2042
|
+
* { identifierEmail: 'user3@example.com', firstName: 'User', lastName: 'Three' }
|
|
2043
|
+
* ]);
|
|
2044
|
+
* console.log(`Created ${users.length} users`);
|
|
2045
|
+
* ```
|
|
2046
|
+
*/
|
|
2047
|
+
async createOrUpdateUsers(users) {
|
|
2048
|
+
return this.userService.createOrUpdateUsers(users);
|
|
2049
|
+
}
|
|
1571
2050
|
/**
|
|
1572
2051
|
* Admin: Update user data
|
|
1573
2052
|
*
|
|
@@ -2072,10 +2551,14 @@ class TokenManager {
|
|
|
2072
2551
|
* ```
|
|
2073
2552
|
*/
|
|
2074
2553
|
class BusinessManager {
|
|
2075
|
-
constructor(apiClient) {
|
|
2554
|
+
constructor(apiClient, events) {
|
|
2076
2555
|
this.apiClient = apiClient;
|
|
2077
|
-
this.
|
|
2078
|
-
this.
|
|
2556
|
+
this.events = events;
|
|
2557
|
+
this.businessApi = new business.BusinessApi(apiClient);
|
|
2558
|
+
this.businessService = new business.BusinessService(this.businessApi);
|
|
2559
|
+
this.membershipApi = new business.BusinessMembershipApi(apiClient);
|
|
2560
|
+
this.membershipService = new business.BusinessMembershipService(this.membershipApi);
|
|
2561
|
+
this.userApi = new userService.UserApi(apiClient);
|
|
2079
2562
|
}
|
|
2080
2563
|
/**
|
|
2081
2564
|
* Get all active businesses
|
|
@@ -2155,7 +2638,7 @@ class BusinessManager {
|
|
|
2155
2638
|
*
|
|
2156
2639
|
* // Use for transaction verification
|
|
2157
2640
|
* if (business.isActive) {
|
|
2158
|
-
* console.log('
|
|
2641
|
+
* console.log('Verified business partner');
|
|
2159
2642
|
* }
|
|
2160
2643
|
* ```
|
|
2161
2644
|
*/
|
|
@@ -2284,7 +2767,14 @@ class BusinessManager {
|
|
|
2284
2767
|
* ```
|
|
2285
2768
|
*/
|
|
2286
2769
|
async createBusiness(displayName) {
|
|
2287
|
-
|
|
2770
|
+
const result = await this.businessService.createBusinessByDisplayName(displayName);
|
|
2771
|
+
this.events?.emitSuccess({
|
|
2772
|
+
domain: 'business',
|
|
2773
|
+
type: 'BUSINESS_CREATED',
|
|
2774
|
+
userMessage: 'Business created successfully',
|
|
2775
|
+
details: { businessId: result.id, displayName: result.displayName }
|
|
2776
|
+
});
|
|
2777
|
+
return result;
|
|
2288
2778
|
}
|
|
2289
2779
|
/**
|
|
2290
2780
|
* Admin: Update business
|
|
@@ -2312,7 +2802,14 @@ class BusinessManager {
|
|
|
2312
2802
|
* ```
|
|
2313
2803
|
*/
|
|
2314
2804
|
async updateBusiness(businessId, businessData) {
|
|
2315
|
-
|
|
2805
|
+
const result = await this.businessService.updateBusiness(businessId, businessData);
|
|
2806
|
+
this.events?.emitSuccess({
|
|
2807
|
+
domain: 'business',
|
|
2808
|
+
type: 'BUSINESS_UPDATED',
|
|
2809
|
+
userMessage: 'Business updated successfully',
|
|
2810
|
+
details: { businessId: result.id, displayName: result.displayName }
|
|
2811
|
+
});
|
|
2812
|
+
return result;
|
|
2316
2813
|
}
|
|
2317
2814
|
/**
|
|
2318
2815
|
* Admin: Toggle business active status
|
|
@@ -2370,6 +2867,209 @@ class BusinessManager {
|
|
|
2370
2867
|
getBusinessService() {
|
|
2371
2868
|
return this.businessService;
|
|
2372
2869
|
}
|
|
2870
|
+
// ==========================================
|
|
2871
|
+
// BUSINESS MEMBERSHIP MANAGEMENT
|
|
2872
|
+
// ==========================================
|
|
2873
|
+
/**
|
|
2874
|
+
* Get all members of a business
|
|
2875
|
+
*
|
|
2876
|
+
* Retrieves all users who have access to the specified business with their roles.
|
|
2877
|
+
* Any member of the business can view the member list.
|
|
2878
|
+
*
|
|
2879
|
+
* @param businessId - The business UUID
|
|
2880
|
+
* @returns Promise resolving to array of business memberships
|
|
2881
|
+
* @throws {PersApiError} 401 - Not authenticated
|
|
2882
|
+
* @throws {PersApiError} 403 - Not a member of this business
|
|
2883
|
+
*
|
|
2884
|
+
* @example
|
|
2885
|
+
* ```typescript
|
|
2886
|
+
* const members = await sdk.business.getMembers('business-123');
|
|
2887
|
+
*
|
|
2888
|
+
* console.log('Business Members:');
|
|
2889
|
+
* members.forEach(member => {
|
|
2890
|
+
* console.log(`- User ${member.userId}: ${member.role}`);
|
|
2891
|
+
* });
|
|
2892
|
+
*
|
|
2893
|
+
* // Count members by role
|
|
2894
|
+
* const admins = members.filter(m => m.role === 'ADMIN' || m.role === 'OWNER');
|
|
2895
|
+
* console.log(`Administrators: ${admins.length}`);
|
|
2896
|
+
* ```
|
|
2897
|
+
*/
|
|
2898
|
+
async getMembers(businessId) {
|
|
2899
|
+
return this.membershipService.getMembers(businessId);
|
|
2900
|
+
}
|
|
2901
|
+
/**
|
|
2902
|
+
* Get members filtered by role
|
|
2903
|
+
*
|
|
2904
|
+
* @param businessId - The business UUID
|
|
2905
|
+
* @param role - The role to filter by
|
|
2906
|
+
* @returns Promise resolving to array of memberships with the specified role
|
|
2907
|
+
*
|
|
2908
|
+
* @example
|
|
2909
|
+
* ```typescript
|
|
2910
|
+
* const owners = await sdk.business.getMembersByRole('business-123', 'OWNER');
|
|
2911
|
+
* console.log(`Business has ${owners.length} owner(s)`);
|
|
2912
|
+
* ```
|
|
2913
|
+
*/
|
|
2914
|
+
async getMembersByRole(businessId, role) {
|
|
2915
|
+
return this.membershipService.getMembersByRole(businessId, role);
|
|
2916
|
+
}
|
|
2917
|
+
/**
|
|
2918
|
+
* Add a new member to a business
|
|
2919
|
+
*
|
|
2920
|
+
* Adds a user as a member of the business with the specified role.
|
|
2921
|
+
* Requires ADMIN role or higher.
|
|
2922
|
+
*
|
|
2923
|
+
* @param businessId - The business UUID
|
|
2924
|
+
* @param userId - The user UUID to add
|
|
2925
|
+
* @param role - The role to assign (defaults to VIEWER)
|
|
2926
|
+
* @returns Promise resolving to the created membership
|
|
2927
|
+
* @throws {PersApiError} 401 - Not authenticated
|
|
2928
|
+
* @throws {PersApiError} 403 - Insufficient role (requires ADMIN)
|
|
2929
|
+
* @throws {PersApiError} 404 - User not found
|
|
2930
|
+
* @throws {PersApiError} 409 - User is already a member
|
|
2931
|
+
*
|
|
2932
|
+
* @example
|
|
2933
|
+
* ```typescript
|
|
2934
|
+
* // Add a new editor to the business
|
|
2935
|
+
* const newMember = await sdk.business.addMember(
|
|
2936
|
+
* 'business-123',
|
|
2937
|
+
* 'user-456',
|
|
2938
|
+
* 'EDITOR'
|
|
2939
|
+
* );
|
|
2940
|
+
*
|
|
2941
|
+
* console.log(`Added ${newMember.userId} as ${newMember.role}`);
|
|
2942
|
+
* ```
|
|
2943
|
+
*/
|
|
2944
|
+
async addMember(businessId, userId, role = persShared.MembershipRole.VIEWER) {
|
|
2945
|
+
return this.membershipService.addMember(businessId, userId, role);
|
|
2946
|
+
}
|
|
2947
|
+
/**
|
|
2948
|
+
* Update a member's role
|
|
2949
|
+
*
|
|
2950
|
+
* Changes the role of an existing business member.
|
|
2951
|
+
* Requires ADMIN role or higher. Cannot demote the last OWNER.
|
|
2952
|
+
* Can only assign roles up to your own level (ADMIN cannot create OWNER).
|
|
2953
|
+
*
|
|
2954
|
+
* @param businessId - The business UUID
|
|
2955
|
+
* @param userId - The user UUID to update
|
|
2956
|
+
* @param newRole - The new role to assign
|
|
2957
|
+
* @returns Promise resolving to the updated membership
|
|
2958
|
+
* @throws {PersApiError} 401 - Not authenticated
|
|
2959
|
+
* @throws {PersApiError} 403 - Insufficient role (requires ADMIN)
|
|
2960
|
+
* @throws {PersApiError} 404 - Membership not found
|
|
2961
|
+
* @throws {PersApiError} 400 - Cannot demote last OWNER
|
|
2962
|
+
*
|
|
2963
|
+
* @example
|
|
2964
|
+
* ```typescript
|
|
2965
|
+
* // Promote an editor to admin
|
|
2966
|
+
* const updated = await sdk.business.updateMemberRole(
|
|
2967
|
+
* 'business-123',
|
|
2968
|
+
* 'user-456',
|
|
2969
|
+
* 'ADMIN'
|
|
2970
|
+
* );
|
|
2971
|
+
*
|
|
2972
|
+
* console.log(`${updated.userId} is now ${updated.role}`);
|
|
2973
|
+
* ```
|
|
2974
|
+
*/
|
|
2975
|
+
async updateMemberRole(businessId, userId, newRole) {
|
|
2976
|
+
const result = await this.membershipService.updateMemberRole(businessId, userId, newRole);
|
|
2977
|
+
this.events?.emitSuccess({
|
|
2978
|
+
domain: 'business',
|
|
2979
|
+
type: 'MEMBERSHIP_UPDATED',
|
|
2980
|
+
userMessage: 'Membership role updated',
|
|
2981
|
+
details: { businessId, userId, role: newRole }
|
|
2982
|
+
});
|
|
2983
|
+
return result;
|
|
2984
|
+
}
|
|
2985
|
+
/**
|
|
2986
|
+
* Remove a member from a business
|
|
2987
|
+
*
|
|
2988
|
+
* Removes a user's access to the business.
|
|
2989
|
+
* Requires ADMIN role or higher. Cannot remove the last OWNER.
|
|
2990
|
+
*
|
|
2991
|
+
* @param businessId - The business UUID
|
|
2992
|
+
* @param userId - The user UUID to remove
|
|
2993
|
+
* @returns Promise resolving to success confirmation
|
|
2994
|
+
* @throws {PersApiError} 401 - Not authenticated
|
|
2995
|
+
* @throws {PersApiError} 403 - Insufficient role (requires ADMIN)
|
|
2996
|
+
* @throws {PersApiError} 404 - Membership not found
|
|
2997
|
+
* @throws {PersApiError} 400 - Cannot remove last OWNER
|
|
2998
|
+
*
|
|
2999
|
+
* @example
|
|
3000
|
+
* ```typescript
|
|
3001
|
+
* const result = await sdk.business.removeMember('business-123', 'user-456');
|
|
3002
|
+
*
|
|
3003
|
+
* if (result.success) {
|
|
3004
|
+
* console.log('Member removed successfully');
|
|
3005
|
+
* }
|
|
3006
|
+
* ```
|
|
3007
|
+
*/
|
|
3008
|
+
async removeMember(businessId, userId) {
|
|
3009
|
+
return this.membershipService.removeMember(businessId, userId);
|
|
3010
|
+
}
|
|
3011
|
+
/**
|
|
3012
|
+
* Get permission flags for a role
|
|
3013
|
+
*
|
|
3014
|
+
* Returns an object with boolean flags indicating what actions
|
|
3015
|
+
* a user with the given role can perform. Useful for UI rendering.
|
|
3016
|
+
*
|
|
3017
|
+
* @param role - The membership role (or null if not a member)
|
|
3018
|
+
* @returns Object with permission flags
|
|
3019
|
+
*
|
|
3020
|
+
* @example
|
|
3021
|
+
* ```typescript
|
|
3022
|
+
* const permissions = sdk.business.getPermissions('EDITOR');
|
|
3023
|
+
* // { canViewMembers: true, canManageMembers: false, canEditContent: true, canDeleteBusiness: false }
|
|
3024
|
+
*
|
|
3025
|
+
* if (permissions.canManageMembers) {
|
|
3026
|
+
* showAddMemberButton();
|
|
3027
|
+
* }
|
|
3028
|
+
* ```
|
|
3029
|
+
*/
|
|
3030
|
+
getPermissions(role) {
|
|
3031
|
+
return this.membershipService.getPermissions(role);
|
|
3032
|
+
}
|
|
3033
|
+
/**
|
|
3034
|
+
* Add a member to a business by email address
|
|
3035
|
+
*
|
|
3036
|
+
* Convenience method that creates or retrieves a user by email and adds them
|
|
3037
|
+
* as a member of the business. If the user doesn't exist, they will be created.
|
|
3038
|
+
* Requires ADMIN role or higher.
|
|
3039
|
+
*
|
|
3040
|
+
* @param businessId - The business UUID
|
|
3041
|
+
* @param email - The email address of the user to add
|
|
3042
|
+
* @param role - The role to assign (defaults to VIEWER)
|
|
3043
|
+
* @returns Promise resolving to the created membership
|
|
3044
|
+
* @throws {PersApiError} 401 - Not authenticated
|
|
3045
|
+
* @throws {PersApiError} 403 - Insufficient role (requires ADMIN)
|
|
3046
|
+
* @throws {PersApiError} 409 - User is already a member
|
|
3047
|
+
*
|
|
3048
|
+
* @example
|
|
3049
|
+
* ```typescript
|
|
3050
|
+
* // Add a new editor by email - user is created if they don't exist
|
|
3051
|
+
* const membership = await sdk.business.addMemberByEmail(
|
|
3052
|
+
* 'business-123',
|
|
3053
|
+
* 'newuser@example.com',
|
|
3054
|
+
* 'EDITOR'
|
|
3055
|
+
* );
|
|
3056
|
+
*
|
|
3057
|
+
* console.log(`Added user ${membership.userId} as ${membership.role}`);
|
|
3058
|
+
* ```
|
|
3059
|
+
*/
|
|
3060
|
+
async addMemberByEmail(businessId, email, role = persShared.MembershipRole.VIEWER) {
|
|
3061
|
+
// POST /users is an upsert - creates user if not exists, returns existing if found
|
|
3062
|
+
const user = await this.userApi.createOrUpdateUser({ email });
|
|
3063
|
+
return this.membershipService.addMember(businessId, user.id, role);
|
|
3064
|
+
}
|
|
3065
|
+
/**
|
|
3066
|
+
* Get the membership service for advanced operations
|
|
3067
|
+
*
|
|
3068
|
+
* @returns BusinessMembershipService instance
|
|
3069
|
+
*/
|
|
3070
|
+
getMembershipService() {
|
|
3071
|
+
return this.membershipService;
|
|
3072
|
+
}
|
|
2373
3073
|
}
|
|
2374
3074
|
|
|
2375
3075
|
/**
|
|
@@ -2385,9 +3085,9 @@ class BusinessManager {
|
|
|
2385
3085
|
*
|
|
2386
3086
|
* @example Basic Campaign Operations
|
|
2387
3087
|
* ```typescript
|
|
2388
|
-
* // Get all available campaigns
|
|
2389
|
-
* const
|
|
2390
|
-
* console.log(`${
|
|
3088
|
+
* // Get all available campaigns (paginated)
|
|
3089
|
+
* const result = await sdk.campaigns.getCampaigns({ page: 1, limit: 20 });
|
|
3090
|
+
* console.log(`${result.data.length} of ${result.total} campaigns`);
|
|
2391
3091
|
*
|
|
2392
3092
|
* // Get specific campaign details
|
|
2393
3093
|
* const campaign = await sdk.campaigns.getCampaignById('summer-promo-2024');
|
|
@@ -2413,7 +3113,8 @@ class BusinessManager {
|
|
|
2413
3113
|
* });
|
|
2414
3114
|
*
|
|
2415
3115
|
* // Check if user can claim specific campaign
|
|
2416
|
-
* const
|
|
3116
|
+
* const campaigns = await sdk.campaigns.getCampaigns({ active: true });
|
|
3117
|
+
* const eligibleCampaigns = campaigns.data.filter(c =>
|
|
2417
3118
|
* !userClaims.some(claim => claim.campaignId === c.id)
|
|
2418
3119
|
* );
|
|
2419
3120
|
* ```
|
|
@@ -2438,47 +3139,12 @@ class BusinessManager {
|
|
|
2438
3139
|
* ```
|
|
2439
3140
|
*/
|
|
2440
3141
|
class CampaignManager {
|
|
2441
|
-
constructor(apiClient) {
|
|
3142
|
+
constructor(apiClient, events) {
|
|
2442
3143
|
this.apiClient = apiClient;
|
|
3144
|
+
this.events = events;
|
|
2443
3145
|
const campaignApi = new campaignService.CampaignApi(apiClient);
|
|
2444
3146
|
this.campaignService = new campaignService.CampaignService(campaignApi);
|
|
2445
3147
|
}
|
|
2446
|
-
/**
|
|
2447
|
-
* Get all active campaigns
|
|
2448
|
-
*
|
|
2449
|
-
* Retrieves all currently active campaigns that users can discover and claim.
|
|
2450
|
-
* Active campaigns are live promotional offers with valid date ranges and
|
|
2451
|
-
* available rewards. Includes campaign details, eligibility requirements, and reward information.
|
|
2452
|
-
*
|
|
2453
|
-
* @returns Promise resolving to array of active campaign data
|
|
2454
|
-
*
|
|
2455
|
-
* @example
|
|
2456
|
-
* ```typescript
|
|
2457
|
-
* const activeCampaigns = await sdk.campaigns.getActiveCampaigns();
|
|
2458
|
-
*
|
|
2459
|
-
* console.log('Available Campaigns:');
|
|
2460
|
-
* activeCampaigns.forEach(campaign => {
|
|
2461
|
-
* console.log(`\n📢 ${campaign.title}`);
|
|
2462
|
-
* console.log(` ${campaign.description}`);
|
|
2463
|
-
* console.log(` Valid: ${campaign.startDate} to ${campaign.endDate}`);
|
|
2464
|
-
* console.log(` Rewards: ${campaign.tokenUnits?.length || 0} types`);
|
|
2465
|
-
*
|
|
2466
|
-
* if (campaign.businessEngagements?.length) {
|
|
2467
|
-
* console.log(` Partner businesses: ${campaign.businessEngagements.length}`);
|
|
2468
|
-
* }
|
|
2469
|
-
* });
|
|
2470
|
-
*
|
|
2471
|
-
* // Filter campaigns by type or business
|
|
2472
|
-
* const hotelCampaigns = activeCampaigns.filter(c =>
|
|
2473
|
-
* c.businessEngagements?.some(be =>
|
|
2474
|
-
* be.business?.businessType?.name?.includes('Hotel')
|
|
2475
|
-
* )
|
|
2476
|
-
* );
|
|
2477
|
-
* ```
|
|
2478
|
-
*/
|
|
2479
|
-
async getActiveCampaigns() {
|
|
2480
|
-
return this.campaignService.getActiveCampaigns();
|
|
2481
|
-
}
|
|
2482
3148
|
/**
|
|
2483
3149
|
* Get campaign by ID
|
|
2484
3150
|
*
|
|
@@ -2576,7 +3242,14 @@ class CampaignManager {
|
|
|
2576
3242
|
* ```
|
|
2577
3243
|
*/
|
|
2578
3244
|
async claimCampaign(claimRequest) {
|
|
2579
|
-
|
|
3245
|
+
const result = await this.campaignService.claimCampaign(claimRequest);
|
|
3246
|
+
this.events?.emitSuccess({
|
|
3247
|
+
domain: 'campaign',
|
|
3248
|
+
type: 'CLAIM_SUCCESS',
|
|
3249
|
+
userMessage: 'Campaign reward claimed successfully',
|
|
3250
|
+
details: { campaignId: claimRequest.campaignId }
|
|
3251
|
+
});
|
|
3252
|
+
return result;
|
|
2580
3253
|
}
|
|
2581
3254
|
/**
|
|
2582
3255
|
* Get user's campaign claims
|
|
@@ -2618,40 +3291,46 @@ class CampaignManager {
|
|
|
2618
3291
|
return this.campaignService.getClaimsForLoggedUser();
|
|
2619
3292
|
}
|
|
2620
3293
|
/**
|
|
2621
|
-
*
|
|
3294
|
+
* Get campaigns with pagination support
|
|
2622
3295
|
*
|
|
2623
|
-
*
|
|
2624
|
-
*
|
|
2625
|
-
* management, reporting, and lifecycle operations.
|
|
3296
|
+
* Returns campaigns with pagination metadata for efficient data loading.
|
|
3297
|
+
* Intelligent access: Public gets active only, Business gets own campaigns, Admin gets all.
|
|
2626
3298
|
*
|
|
2627
|
-
* @param
|
|
2628
|
-
* @
|
|
2629
|
-
* @
|
|
3299
|
+
* @param options - Pagination and filter options
|
|
3300
|
+
* @param options.active - Filter by active status (true/false/undefined for all)
|
|
3301
|
+
* @param options.businessId - Filter by business engagement
|
|
3302
|
+
* @param options.page - Page number (1-based, default: 1)
|
|
3303
|
+
* @param options.limit - Items per page (default: 50)
|
|
3304
|
+
* @param options.sortBy - Sort field ('name', 'createdAt', 'startDate')
|
|
3305
|
+
* @param options.sortOrder - Sort direction ('ASC' or 'DESC')
|
|
3306
|
+
* @returns Promise resolving to paginated campaigns with metadata
|
|
2630
3307
|
*
|
|
2631
3308
|
* @example
|
|
2632
3309
|
* ```typescript
|
|
2633
|
-
* //
|
|
2634
|
-
* const
|
|
2635
|
-
*
|
|
2636
|
-
*
|
|
2637
|
-
*
|
|
2638
|
-
*
|
|
2639
|
-
*
|
|
2640
|
-
*
|
|
2641
|
-
*
|
|
2642
|
-
*
|
|
2643
|
-
*
|
|
2644
|
-
*
|
|
2645
|
-
*
|
|
2646
|
-
*
|
|
2647
|
-
*
|
|
2648
|
-
*
|
|
2649
|
-
*
|
|
2650
|
-
*
|
|
3310
|
+
* // Get first page of campaigns
|
|
3311
|
+
* const result = await sdk.campaigns.getCampaigns({ page: 1, limit: 10 });
|
|
3312
|
+
* console.log(`Showing ${result.data.length} of ${result.total} campaigns`);
|
|
3313
|
+
* console.log(`Has more pages: ${result.hasMore}`);
|
|
3314
|
+
*
|
|
3315
|
+
* // Get campaigns for a specific business
|
|
3316
|
+
* const businessCampaigns = await sdk.campaigns.getCampaigns({
|
|
3317
|
+
* businessId: 'business-123',
|
|
3318
|
+
* page: 1,
|
|
3319
|
+
* limit: 20
|
|
3320
|
+
* });
|
|
3321
|
+
*
|
|
3322
|
+
* // Get active campaigns sorted by creation date
|
|
3323
|
+
* const activeCampaigns = await sdk.campaigns.getCampaigns({
|
|
3324
|
+
* active: true,
|
|
3325
|
+
* sortBy: 'createdAt',
|
|
3326
|
+
* sortOrder: 'DESC',
|
|
3327
|
+
* page: 1,
|
|
3328
|
+
* limit: 25
|
|
3329
|
+
* });
|
|
2651
3330
|
* ```
|
|
2652
3331
|
*/
|
|
2653
|
-
async
|
|
2654
|
-
return this.campaignService.getCampaigns(
|
|
3332
|
+
async getCampaigns(options) {
|
|
3333
|
+
return this.campaignService.getCampaigns(options);
|
|
2655
3334
|
}
|
|
2656
3335
|
/**
|
|
2657
3336
|
* Admin: Create new campaign
|
|
@@ -3170,8 +3849,9 @@ class CampaignManager {
|
|
|
3170
3849
|
* ```
|
|
3171
3850
|
*/
|
|
3172
3851
|
class RedemptionManager {
|
|
3173
|
-
constructor(apiClient) {
|
|
3852
|
+
constructor(apiClient, events) {
|
|
3174
3853
|
this.apiClient = apiClient;
|
|
3854
|
+
this.events = events;
|
|
3175
3855
|
const redemptionApi = new redemptionService.RedemptionApi(apiClient);
|
|
3176
3856
|
this.redemptionService = new redemptionService.RedemptionService(redemptionApi);
|
|
3177
3857
|
}
|
|
@@ -3335,7 +4015,14 @@ class RedemptionManager {
|
|
|
3335
4015
|
* ```
|
|
3336
4016
|
*/
|
|
3337
4017
|
async redeem(redemptionId) {
|
|
3338
|
-
|
|
4018
|
+
const result = await this.redemptionService.redeemRedemption(redemptionId);
|
|
4019
|
+
this.events?.emitSuccess({
|
|
4020
|
+
domain: 'redemption',
|
|
4021
|
+
type: 'REDEEM_SUCCESS',
|
|
4022
|
+
userMessage: 'Reward redeemed successfully',
|
|
4023
|
+
details: { redemptionId }
|
|
4024
|
+
});
|
|
4025
|
+
return result;
|
|
3339
4026
|
}
|
|
3340
4027
|
/**
|
|
3341
4028
|
* Get user's redemption history
|
|
@@ -3699,8 +4386,9 @@ class RedemptionManager {
|
|
|
3699
4386
|
* ```
|
|
3700
4387
|
*/
|
|
3701
4388
|
class TransactionManager {
|
|
3702
|
-
constructor(apiClient) {
|
|
4389
|
+
constructor(apiClient, events) {
|
|
3703
4390
|
this.apiClient = apiClient;
|
|
4391
|
+
this.events = events;
|
|
3704
4392
|
const transactionApi = new transactionService.TransactionApi(apiClient);
|
|
3705
4393
|
this.transactionService = new transactionService.TransactionService(transactionApi);
|
|
3706
4394
|
}
|
|
@@ -3836,7 +4524,14 @@ class TransactionManager {
|
|
|
3836
4524
|
* ```
|
|
3837
4525
|
*/
|
|
3838
4526
|
async createTransaction(transactionData) {
|
|
3839
|
-
|
|
4527
|
+
const result = await this.transactionService.createTransaction(transactionData);
|
|
4528
|
+
this.events?.emitSuccess({
|
|
4529
|
+
domain: 'transaction',
|
|
4530
|
+
type: 'TRANSACTION_CREATED',
|
|
4531
|
+
userMessage: 'Transaction created successfully',
|
|
4532
|
+
details: { transactionId: result.transaction?.id }
|
|
4533
|
+
});
|
|
4534
|
+
return result;
|
|
3840
4535
|
}
|
|
3841
4536
|
/**
|
|
3842
4537
|
* Get user's transaction history
|
|
@@ -3853,7 +4548,7 @@ class TransactionManager {
|
|
|
3853
4548
|
* ```typescript
|
|
3854
4549
|
* const allTransactions = await sdk.transactions.getUserTransactionHistory('ALL');
|
|
3855
4550
|
*
|
|
3856
|
-
* console.log(
|
|
4551
|
+
* console.log(` Transaction History (${allTransactions.length} transactions):`);
|
|
3857
4552
|
*
|
|
3858
4553
|
* allTransactions.forEach((transaction, index) => {
|
|
3859
4554
|
* const date = new Date(transaction.createdAt).toLocaleDateString();
|
|
@@ -4141,7 +4836,14 @@ class TransactionManager {
|
|
|
4141
4836
|
* @returns Promise resolving to the submission result
|
|
4142
4837
|
*/
|
|
4143
4838
|
async submitSignedTransaction(signedTxData) {
|
|
4144
|
-
|
|
4839
|
+
const result = await this.transactionService.submitSignedTransaction(signedTxData);
|
|
4840
|
+
this.events?.emitSuccess({
|
|
4841
|
+
domain: 'transaction',
|
|
4842
|
+
type: 'TRANSACTION_SUBMITTED',
|
|
4843
|
+
userMessage: 'Transaction submitted successfully',
|
|
4844
|
+
details: { transactionId: result.transaction?.id }
|
|
4845
|
+
});
|
|
4846
|
+
return result;
|
|
4145
4847
|
}
|
|
4146
4848
|
/**
|
|
4147
4849
|
* Query transactions by sender
|
|
@@ -5837,6 +6539,13 @@ class DonationManager {
|
|
|
5837
6539
|
* ```
|
|
5838
6540
|
*/
|
|
5839
6541
|
class Web3Manager {
|
|
6542
|
+
// TODO: Add PersEventEmitter support for blockchain events
|
|
6543
|
+
// When ready, add:
|
|
6544
|
+
// 1. constructor param: private events?: PersEventEmitter
|
|
6545
|
+
// 2. Subscribe to contract events (Transfer, Approval, etc.)
|
|
6546
|
+
// 3. Emit via: this.events?.emitSuccess({ domain: 'web3', type: 'NFT_TRANSFERRED', ... })
|
|
6547
|
+
// 4. Filter to only user's address (not all transfers)
|
|
6548
|
+
// 5. Add cleanup for event listeners on SDK destroy
|
|
5840
6549
|
constructor(apiClient) {
|
|
5841
6550
|
this.apiClient = apiClient;
|
|
5842
6551
|
// Initialize Web3 Chain service
|
|
@@ -6160,15 +6869,18 @@ class PersSDK {
|
|
|
6160
6869
|
*/
|
|
6161
6870
|
constructor(httpClient, config) {
|
|
6162
6871
|
this.apiClient = new PersApiClient(httpClient, config);
|
|
6163
|
-
// Initialize
|
|
6164
|
-
this.
|
|
6165
|
-
this.
|
|
6872
|
+
// Initialize event emitter and wire to API client for error events
|
|
6873
|
+
this._events = new PersEventEmitter();
|
|
6874
|
+
this.apiClient.setEvents(this._events);
|
|
6875
|
+
// Initialize domain managers (pass events to managers that emit success events)
|
|
6876
|
+
this._auth = new AuthManager(this.apiClient, this._events);
|
|
6877
|
+
this._users = new UserManager(this.apiClient, this._events);
|
|
6166
6878
|
this._userStatus = new UserStatusManager(this.apiClient);
|
|
6167
6879
|
this._tokens = new TokenManager(this.apiClient);
|
|
6168
|
-
this._businesses = new BusinessManager(this.apiClient);
|
|
6169
|
-
this._campaigns = new CampaignManager(this.apiClient);
|
|
6170
|
-
this._redemptions = new RedemptionManager(this.apiClient);
|
|
6171
|
-
this._transactions = new TransactionManager(this.apiClient);
|
|
6880
|
+
this._businesses = new BusinessManager(this.apiClient, this._events);
|
|
6881
|
+
this._campaigns = new CampaignManager(this.apiClient, this._events);
|
|
6882
|
+
this._redemptions = new RedemptionManager(this.apiClient, this._events);
|
|
6883
|
+
this._transactions = new TransactionManager(this.apiClient, this._events);
|
|
6172
6884
|
this._purchases = new PurchaseManager(this.apiClient);
|
|
6173
6885
|
this._files = new FileManager(this.apiClient);
|
|
6174
6886
|
this._tenants = new TenantManager(this.apiClient);
|
|
@@ -6177,6 +6889,55 @@ class PersSDK {
|
|
|
6177
6889
|
this._donations = new DonationManager(this.apiClient);
|
|
6178
6890
|
this._web3 = new Web3Manager(this.apiClient);
|
|
6179
6891
|
}
|
|
6892
|
+
/**
|
|
6893
|
+
* Event emitter - Subscribe to SDK-wide events
|
|
6894
|
+
*
|
|
6895
|
+
* Provides a platform-agnostic event system for subscribing to transaction,
|
|
6896
|
+
* authentication, campaign, and system events. Use this to display
|
|
6897
|
+
* notifications, update UI, or trigger side effects in your application.
|
|
6898
|
+
*
|
|
6899
|
+
* All events have a `userMessage` field ready for display.
|
|
6900
|
+
*
|
|
6901
|
+
* @returns PersEventEmitter instance
|
|
6902
|
+
*
|
|
6903
|
+
* @example Basic Usage - Show All Notifications
|
|
6904
|
+
* ```typescript
|
|
6905
|
+
* const unsubscribe = sdk.events.subscribe((event) => {
|
|
6906
|
+
* // userMessage is always present and UI-ready
|
|
6907
|
+
* showNotification(event.userMessage, event.level);
|
|
6908
|
+
* });
|
|
6909
|
+
*
|
|
6910
|
+
* // Later: cleanup
|
|
6911
|
+
* unsubscribe();
|
|
6912
|
+
* ```
|
|
6913
|
+
*
|
|
6914
|
+
* @example Filter by Domain and Level
|
|
6915
|
+
* ```typescript
|
|
6916
|
+
* sdk.events.subscribe((event) => {
|
|
6917
|
+
* if (event.level === 'success' && event.domain === 'transaction') {
|
|
6918
|
+
* playSuccessSound();
|
|
6919
|
+
* confetti();
|
|
6920
|
+
* }
|
|
6921
|
+
*
|
|
6922
|
+
* if (event.level === 'error') {
|
|
6923
|
+
* logToSentry(event);
|
|
6924
|
+
* }
|
|
6925
|
+
* });
|
|
6926
|
+
* ```
|
|
6927
|
+
*
|
|
6928
|
+
* @example One-time Event
|
|
6929
|
+
* ```typescript
|
|
6930
|
+
* // Auto-unsubscribe after first event
|
|
6931
|
+
* sdk.events.once((event) => {
|
|
6932
|
+
* console.log('First event received:', event.type);
|
|
6933
|
+
* });
|
|
6934
|
+
* ```
|
|
6935
|
+
*
|
|
6936
|
+
* @see {@link PersEventEmitter} for detailed documentation
|
|
6937
|
+
*/
|
|
6938
|
+
get events() {
|
|
6939
|
+
return this._events;
|
|
6940
|
+
}
|
|
6180
6941
|
/**
|
|
6181
6942
|
* Authentication manager - High-level authentication operations
|
|
6182
6943
|
*
|
|
@@ -6476,9 +7237,13 @@ exports.IndexedDBTokenStorage = IndexedDBTokenStorage;
|
|
|
6476
7237
|
exports.LocalStorageTokenStorage = LocalStorageTokenStorage;
|
|
6477
7238
|
exports.MemoryTokenStorage = MemoryTokenStorage;
|
|
6478
7239
|
exports.PersApiClient = PersApiClient;
|
|
7240
|
+
exports.PersEventEmitter = PersEventEmitter;
|
|
6479
7241
|
exports.PersSDK = PersSDK;
|
|
6480
7242
|
exports.PurchaseManager = PurchaseManager;
|
|
6481
7243
|
exports.RedemptionManager = RedemptionManager;
|
|
7244
|
+
exports.SDK_NAME = SDK_NAME;
|
|
7245
|
+
exports.SDK_USER_AGENT = SDK_USER_AGENT;
|
|
7246
|
+
exports.SDK_VERSION = SDK_VERSION;
|
|
6482
7247
|
exports.TenantManager = TenantManager;
|
|
6483
7248
|
exports.TokenManager = TokenManager;
|
|
6484
7249
|
exports.TransactionManager = TransactionManager;
|
|
@@ -6492,4 +7257,4 @@ exports.detectEnvironment = detectEnvironment;
|
|
|
6492
7257
|
exports.environment = environment;
|
|
6493
7258
|
exports.mergeWithDefaults = mergeWithDefaults;
|
|
6494
7259
|
exports.warnIfProblematicEnvironment = warnIfProblematicEnvironment;
|
|
6495
|
-
//# sourceMappingURL=pers-sdk-
|
|
7260
|
+
//# sourceMappingURL=pers-sdk-DULFjOW2.cjs.map
|