@explorins/pers-sdk-react-native 2.2.1 → 2.2.2
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/index.js
CHANGED
|
@@ -3152,6 +3152,8 @@ exports.WebhookSource = void 0;
|
|
|
3152
3152
|
WebhookSource["USER"] = "USER";
|
|
3153
3153
|
WebhookSource["BUSINESS"] = "BUSINESS";
|
|
3154
3154
|
WebhookSource["TENANT"] = "TENANT";
|
|
3155
|
+
// System-level internal invocation (e.g., token metadata webhook fetch)
|
|
3156
|
+
WebhookSource["INTERNAL"] = "INTERNAL";
|
|
3155
3157
|
// External verified sources
|
|
3156
3158
|
WebhookSource["STRIPE"] = "STRIPE";
|
|
3157
3159
|
// Allow any external traffic (no verification)
|
|
@@ -3557,7 +3559,8 @@ function isValidTransactionRelation(value) {
|
|
|
3557
3559
|
const VALID_CAMPAIGN_RELATIONS = [
|
|
3558
3560
|
'triggerSources',
|
|
3559
3561
|
'businesses',
|
|
3560
|
-
'claimCount'
|
|
3562
|
+
'claimCount',
|
|
3563
|
+
'ownerBusiness'
|
|
3561
3564
|
];
|
|
3562
3565
|
/**
|
|
3563
3566
|
* Type guard to validate campaign include relation at runtime
|
|
@@ -3595,7 +3598,8 @@ function isValidCampaignClaimRelation(value) {
|
|
|
3595
3598
|
* Used for runtime validation
|
|
3596
3599
|
*/
|
|
3597
3600
|
const VALID_REDEMPTION_RELATIONS = [
|
|
3598
|
-
'redeemCount'
|
|
3601
|
+
'redeemCount',
|
|
3602
|
+
'ownerBusiness'
|
|
3599
3603
|
];
|
|
3600
3604
|
/**
|
|
3601
3605
|
* Type guard to validate redemption include relation at runtime
|
|
@@ -3653,6 +3657,26 @@ function isValidUserRelation(value) {
|
|
|
3653
3657
|
return VALID_USER_RELATIONS.includes(value);
|
|
3654
3658
|
}
|
|
3655
3659
|
|
|
3660
|
+
/**
|
|
3661
|
+
* Array of all valid token metadata include relations
|
|
3662
|
+
* Used for runtime validation
|
|
3663
|
+
*/
|
|
3664
|
+
const VALID_TOKEN_METADATA_RELATIONS = [
|
|
3665
|
+
'ownerBusiness',
|
|
3666
|
+
'mintCount',
|
|
3667
|
+
'burnCount',
|
|
3668
|
+
'token'
|
|
3669
|
+
];
|
|
3670
|
+
/**
|
|
3671
|
+
* Type guard to validate token metadata include relation at runtime
|
|
3672
|
+
*
|
|
3673
|
+
* @param value - String to validate
|
|
3674
|
+
* @returns True if value is a valid TokenMetadataIncludeRelation
|
|
3675
|
+
*/
|
|
3676
|
+
function isValidTokenMetadataRelation(value) {
|
|
3677
|
+
return VALID_TOKEN_METADATA_RELATIONS.includes(value);
|
|
3678
|
+
}
|
|
3679
|
+
|
|
3656
3680
|
/**
|
|
3657
3681
|
* Normalizes filter options to use new field names while accepting deprecated ones.
|
|
3658
3682
|
* Use at controller level to support both old and new API contracts.
|
|
@@ -5166,30 +5190,30 @@ class TokenApi {
|
|
|
5166
5190
|
return this.apiClient.get(url);
|
|
5167
5191
|
}
|
|
5168
5192
|
/**
|
|
5169
|
-
* Get all token metadata with filtering and
|
|
5193
|
+
* Get all token metadata with filtering, pagination, and include relations
|
|
5170
5194
|
*
|
|
5171
5195
|
* Useful for displaying rewards (ERC1155) or stamps (ERC721) in tables.
|
|
5172
5196
|
* Non-admin users always get active metadata only.
|
|
5173
5197
|
*
|
|
5174
|
-
* @param options - Filter and
|
|
5198
|
+
* @param options - Filter, pagination, and include options
|
|
5175
5199
|
* @returns Paginated response with token metadata
|
|
5176
5200
|
*
|
|
5177
|
-
* @example Get all active rewards
|
|
5201
|
+
* @example Get all active rewards with mint/burn counts
|
|
5178
5202
|
* ```typescript
|
|
5179
5203
|
* const rewards = await tokenApi.getTokenMetadata({
|
|
5180
5204
|
* tokenType: 'ERC1155',
|
|
5181
5205
|
* active: true,
|
|
5182
|
-
* limit: 10
|
|
5206
|
+
* limit: 10,
|
|
5207
|
+
* include: ['mintCount', 'burnCount', 'token']
|
|
5183
5208
|
* });
|
|
5184
5209
|
* ```
|
|
5185
5210
|
*
|
|
5186
|
-
* @example Get stamps with
|
|
5211
|
+
* @example Get stamps with owner business included
|
|
5187
5212
|
* ```typescript
|
|
5188
5213
|
* const stamps = await tokenApi.getTokenMetadata({
|
|
5189
5214
|
* tokenType: 'ERC721',
|
|
5190
5215
|
* search: 'gold',
|
|
5191
|
-
*
|
|
5192
|
-
* sortOrder: 'ASC'
|
|
5216
|
+
* include: ['ownerBusiness', 'token']
|
|
5193
5217
|
* });
|
|
5194
5218
|
* ```
|
|
5195
5219
|
*/
|
|
@@ -5214,6 +5238,14 @@ class TokenApi {
|
|
|
5214
5238
|
params.set('tags', tagsArray.join(','));
|
|
5215
5239
|
}
|
|
5216
5240
|
}
|
|
5241
|
+
// Filter by owner business
|
|
5242
|
+
if (options?.ownerBusinessId) {
|
|
5243
|
+
params.set('ownerBusinessId', options.ownerBusinessId);
|
|
5244
|
+
}
|
|
5245
|
+
// Include relations (ownerBusiness, mintCount, burnCount, token)
|
|
5246
|
+
if (options?.include && options.include.length > 0) {
|
|
5247
|
+
params.set('include', options.include.join(','));
|
|
5248
|
+
}
|
|
5217
5249
|
const response = await this.apiClient.get(`${this.basePath}/metadata?${params.toString()}`);
|
|
5218
5250
|
return normalizeToPaginated(response);
|
|
5219
5251
|
}
|
|
@@ -5273,6 +5305,30 @@ class TokenApi {
|
|
|
5273
5305
|
async createTokenType(tokenType) {
|
|
5274
5306
|
return this.apiClient.post(`${this.basePath}/types`, tokenType);
|
|
5275
5307
|
}
|
|
5308
|
+
/**
|
|
5309
|
+
* ADMIN: Delete token metadata (soft delete)
|
|
5310
|
+
*
|
|
5311
|
+
* Soft deletes token metadata by setting deletedAt timestamp.
|
|
5312
|
+
* Will fail with 409 Conflict if metadata is in use by active campaigns or redemptions.
|
|
5313
|
+
*
|
|
5314
|
+
* @param metadataId - ID of the token metadata to delete
|
|
5315
|
+
* @throws {PersApiError} 409 Conflict if metadata is in use
|
|
5316
|
+
*
|
|
5317
|
+
* @example
|
|
5318
|
+
* ```typescript
|
|
5319
|
+
* try {
|
|
5320
|
+
* await tokenApi.deleteTokenMetadata('metadata-123');
|
|
5321
|
+
* console.log('Metadata deleted');
|
|
5322
|
+
* } catch (error) {
|
|
5323
|
+
* if (error.statusCode === 409) {
|
|
5324
|
+
* console.log('Cannot delete: metadata is in use');
|
|
5325
|
+
* }
|
|
5326
|
+
* }
|
|
5327
|
+
* ```
|
|
5328
|
+
*/
|
|
5329
|
+
async deleteTokenMetadata(metadataId) {
|
|
5330
|
+
return this.apiClient.delete(`${this.basePath}/metadata/${metadataId}`);
|
|
5331
|
+
}
|
|
5276
5332
|
}
|
|
5277
5333
|
|
|
5278
5334
|
/**
|
|
@@ -5327,35 +5383,57 @@ class TokenService {
|
|
|
5327
5383
|
return this.tokenApi.getTokenByContractAddress(contractAddress, contractTokenId);
|
|
5328
5384
|
}
|
|
5329
5385
|
/**
|
|
5330
|
-
* Get all token metadata with filtering and
|
|
5386
|
+
* Get all token metadata with filtering, pagination, and include relations
|
|
5331
5387
|
*
|
|
5332
5388
|
* Useful for displaying rewards (ERC1155) or stamps (ERC721) in tables.
|
|
5333
5389
|
* Non-admin users always get active metadata only.
|
|
5334
5390
|
*
|
|
5335
|
-
* @param options - Filter and
|
|
5391
|
+
* @param options - Filter, pagination, and include options
|
|
5336
5392
|
* @returns Paginated response with token metadata
|
|
5393
|
+
*
|
|
5394
|
+
* @example Get rewards with counts
|
|
5395
|
+
* ```typescript
|
|
5396
|
+
* const rewards = await tokenService.getTokenMetadata({
|
|
5397
|
+
* tokenType: 'ERC1155',
|
|
5398
|
+
* include: ['mintCount', 'burnCount', 'token']
|
|
5399
|
+
* });
|
|
5400
|
+
* ```
|
|
5337
5401
|
*/
|
|
5338
5402
|
async getTokenMetadata(options) {
|
|
5339
5403
|
return this.tokenApi.getTokenMetadata(options);
|
|
5340
5404
|
}
|
|
5341
5405
|
/**
|
|
5342
|
-
* Get rewards (ERC1155 token metadata) with filtering and
|
|
5406
|
+
* Get rewards (ERC1155 token metadata) with filtering, pagination, and include relations
|
|
5343
5407
|
*
|
|
5344
5408
|
* Convenience method for fetching reward metadata.
|
|
5345
5409
|
*
|
|
5346
|
-
* @param options - Filter and
|
|
5410
|
+
* @param options - Filter, pagination, and include options (tokenType is set automatically)
|
|
5347
5411
|
* @returns Paginated response with reward metadata
|
|
5412
|
+
*
|
|
5413
|
+
* @example Get rewards with mint/burn counts and token info
|
|
5414
|
+
* ```typescript
|
|
5415
|
+
* const rewards = await tokenService.getRewards({
|
|
5416
|
+
* include: ['mintCount', 'burnCount', 'token', 'ownerBusiness']
|
|
5417
|
+
* });
|
|
5418
|
+
* ```
|
|
5348
5419
|
*/
|
|
5349
5420
|
async getRewards(options) {
|
|
5350
5421
|
return this.tokenApi.getTokenMetadata({ ...options, tokenType: NativeTokenTypes.ERC1155 });
|
|
5351
5422
|
}
|
|
5352
5423
|
/**
|
|
5353
|
-
* Get stamps (ERC721 token metadata) with filtering and
|
|
5424
|
+
* Get stamps (ERC721 token metadata) with filtering, pagination, and include relations
|
|
5354
5425
|
*
|
|
5355
5426
|
* Convenience method for fetching stamp metadata.
|
|
5356
5427
|
*
|
|
5357
|
-
* @param options - Filter and
|
|
5428
|
+
* @param options - Filter, pagination, and include options (tokenType is set automatically)
|
|
5358
5429
|
* @returns Paginated response with stamp metadata
|
|
5430
|
+
*
|
|
5431
|
+
* @example Get stamps with mint/burn counts and token info
|
|
5432
|
+
* ```typescript
|
|
5433
|
+
* const stamps = await tokenService.getStamps({
|
|
5434
|
+
* include: ['mintCount', 'burnCount', 'token', 'ownerBusiness']
|
|
5435
|
+
* });
|
|
5436
|
+
* ```
|
|
5359
5437
|
*/
|
|
5360
5438
|
async getStamps(options) {
|
|
5361
5439
|
return this.tokenApi.getTokenMetadata({ ...options, tokenType: NativeTokenTypes.ERC721 });
|
|
@@ -5412,6 +5490,17 @@ class TokenService {
|
|
|
5412
5490
|
async createTokenType(tokenType) {
|
|
5413
5491
|
return this.tokenApi.createTokenType(tokenType);
|
|
5414
5492
|
}
|
|
5493
|
+
/**
|
|
5494
|
+
* ADMIN: Delete token metadata (soft delete)
|
|
5495
|
+
*
|
|
5496
|
+
* Soft deletes token metadata. Will fail if metadata is in use.
|
|
5497
|
+
*
|
|
5498
|
+
* @param metadataId - ID of the token metadata to delete
|
|
5499
|
+
* @throws {PersApiError} 409 Conflict if metadata is in use by campaigns/redemptions
|
|
5500
|
+
*/
|
|
5501
|
+
async deleteTokenMetadata(metadataId) {
|
|
5502
|
+
return this.tokenApi.deleteTokenMetadata(metadataId);
|
|
5503
|
+
}
|
|
5415
5504
|
}
|
|
5416
5505
|
|
|
5417
5506
|
/**
|
|
@@ -5514,6 +5603,10 @@ class BusinessApi {
|
|
|
5514
5603
|
*
|
|
5515
5604
|
* // Filter by business type
|
|
5516
5605
|
* const hotels = await businessApi.getBusinesses({ businessTypeId: 1 });
|
|
5606
|
+
*
|
|
5607
|
+
* // Filter by location (geocoding)
|
|
5608
|
+
* const dohaBusinesses = await businessApi.getBusinesses({ city: 'Doha', countryCode: 'QA' });
|
|
5609
|
+
* const westBay = await businessApi.getBusinesses({ neighborhood: 'West Bay' });
|
|
5517
5610
|
* ```
|
|
5518
5611
|
*/
|
|
5519
5612
|
async getBusinesses(options) {
|
|
@@ -5536,6 +5629,22 @@ class BusinessApi {
|
|
|
5536
5629
|
if (options?.businessTypeId !== undefined) {
|
|
5537
5630
|
params.set('businessTypeId', String(options.businessTypeId));
|
|
5538
5631
|
}
|
|
5632
|
+
// Location filter options (geocoding)
|
|
5633
|
+
if (options?.city) {
|
|
5634
|
+
params.set('city', options.city);
|
|
5635
|
+
}
|
|
5636
|
+
if (options?.countryCode) {
|
|
5637
|
+
params.set('countryCode', options.countryCode);
|
|
5638
|
+
}
|
|
5639
|
+
if (options?.country) {
|
|
5640
|
+
params.set('country', options.country);
|
|
5641
|
+
}
|
|
5642
|
+
if (options?.neighborhood) {
|
|
5643
|
+
params.set('neighborhood', options.neighborhood);
|
|
5644
|
+
}
|
|
5645
|
+
if (options?.district) {
|
|
5646
|
+
params.set('district', options.district);
|
|
5647
|
+
}
|
|
5539
5648
|
const response = await this.apiClient.get(`${this.basePath}?${params.toString()}`);
|
|
5540
5649
|
return normalizeToPaginated(response);
|
|
5541
5650
|
}
|
|
@@ -7237,6 +7346,12 @@ class RedemptionService {
|
|
|
7237
7346
|
async updateRedemptionType(data) {
|
|
7238
7347
|
return this.redemptionApi.updateRedemptionType(data);
|
|
7239
7348
|
}
|
|
7349
|
+
/**
|
|
7350
|
+
* ADMIN: Delete redemption
|
|
7351
|
+
*/
|
|
7352
|
+
async deleteRedemption(id) {
|
|
7353
|
+
return this.redemptionApi.deleteRedemption(id);
|
|
7354
|
+
}
|
|
7240
7355
|
/**
|
|
7241
7356
|
* ADMIN: Delete redemption type
|
|
7242
7357
|
*/
|
|
@@ -9172,7 +9287,7 @@ class TriggerSourceApi {
|
|
|
9172
9287
|
/**
|
|
9173
9288
|
* PUBLIC: Get trigger sources with optional filters and pagination
|
|
9174
9289
|
*
|
|
9175
|
-
* @param options - Filter and pagination options
|
|
9290
|
+
* @param options - Filter and pagination options (includes location filters)
|
|
9176
9291
|
* @returns Paginated list of trigger sources
|
|
9177
9292
|
*
|
|
9178
9293
|
* @example
|
|
@@ -9186,6 +9301,12 @@ class TriggerSourceApi {
|
|
|
9186
9301
|
* page: 1,
|
|
9187
9302
|
* limit: 20
|
|
9188
9303
|
* });
|
|
9304
|
+
*
|
|
9305
|
+
* // Filter by location (geocoding)
|
|
9306
|
+
* const dubaiSources = await triggerSourceApi.getTriggerSources({
|
|
9307
|
+
* city: 'Dubai',
|
|
9308
|
+
* countryCode: 'AE'
|
|
9309
|
+
* });
|
|
9189
9310
|
* ```
|
|
9190
9311
|
*/
|
|
9191
9312
|
async getTriggerSources(options) {
|
|
@@ -9198,6 +9319,19 @@ class TriggerSourceApi {
|
|
|
9198
9319
|
params.set('campaignId', options.campaignId);
|
|
9199
9320
|
if (options?.active !== undefined)
|
|
9200
9321
|
params.set('active', String(options.active));
|
|
9322
|
+
if (options?.includeDeleted)
|
|
9323
|
+
params.set('includeDeleted', String(options.includeDeleted));
|
|
9324
|
+
// Location filter options (geocoding)
|
|
9325
|
+
if (options?.city)
|
|
9326
|
+
params.set('city', options.city);
|
|
9327
|
+
if (options?.countryCode)
|
|
9328
|
+
params.set('countryCode', options.countryCode);
|
|
9329
|
+
if (options?.country)
|
|
9330
|
+
params.set('country', options.country);
|
|
9331
|
+
if (options?.neighborhood)
|
|
9332
|
+
params.set('neighborhood', options.neighborhood);
|
|
9333
|
+
if (options?.district)
|
|
9334
|
+
params.set('district', options.district);
|
|
9201
9335
|
const response = await this.apiClient.get(`/trigger-sources?${params.toString()}`);
|
|
9202
9336
|
return normalizeToPaginated(response);
|
|
9203
9337
|
}
|
|
@@ -9782,6 +9916,9 @@ class AuthService {
|
|
|
9782
9916
|
* Extracts context (tenantId/businessId) from the current refresh token to ensure
|
|
9783
9917
|
* the recovered session maintains the same context.
|
|
9784
9918
|
*
|
|
9919
|
+
* This is a PUBLIC method that can be called by TokenRefreshManager when internal
|
|
9920
|
+
* refresh fails, to try external (provider token) recovery before giving up.
|
|
9921
|
+
*
|
|
9785
9922
|
* @returns true if session was successfully recovered
|
|
9786
9923
|
*/
|
|
9787
9924
|
async attemptProviderTokenRecovery() {
|
|
@@ -9934,6 +10071,8 @@ class TokenRefreshManager {
|
|
|
9934
10071
|
// Retry configuration for transient failures
|
|
9935
10072
|
this.MAX_RETRY_ATTEMPTS = 3;
|
|
9936
10073
|
this.RETRY_DELAY_MS = 1000;
|
|
10074
|
+
// Active refresh promise for deduplication
|
|
10075
|
+
this.activeRefreshPromise = null;
|
|
9937
10076
|
}
|
|
9938
10077
|
/**
|
|
9939
10078
|
* Ensures the access token is valid, refreshing if needed.
|
|
@@ -10034,11 +10173,27 @@ class TokenRefreshManager {
|
|
|
10034
10173
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
10035
10174
|
}
|
|
10036
10175
|
/**
|
|
10037
|
-
*
|
|
10176
|
+
* Attempt token refresh: internal first, then provider token fallback.
|
|
10177
|
+
* DEDUPLICATES concurrent calls - all callers share the same promise.
|
|
10038
10178
|
*/
|
|
10039
10179
|
async attemptInternalRefresh() {
|
|
10040
|
-
|
|
10041
|
-
|
|
10180
|
+
if (this.activeRefreshPromise) {
|
|
10181
|
+
return this.activeRefreshPromise;
|
|
10182
|
+
}
|
|
10183
|
+
this.activeRefreshPromise = (async () => {
|
|
10184
|
+
const result = await this.attemptRefreshWithRetry();
|
|
10185
|
+
if (result.success)
|
|
10186
|
+
return result;
|
|
10187
|
+
// Internal failed - try provider token recovery
|
|
10188
|
+
const recovered = await this.authService.attemptProviderTokenRecovery();
|
|
10189
|
+
return recovered ? { success: true, retryable: false } : result;
|
|
10190
|
+
})();
|
|
10191
|
+
try {
|
|
10192
|
+
return await this.activeRefreshPromise;
|
|
10193
|
+
}
|
|
10194
|
+
finally {
|
|
10195
|
+
this.activeRefreshPromise = null;
|
|
10196
|
+
}
|
|
10042
10197
|
}
|
|
10043
10198
|
}
|
|
10044
10199
|
|
|
@@ -10844,7 +10999,7 @@ class DefaultAuthProvider {
|
|
|
10844
10999
|
/** SDK package name */
|
|
10845
11000
|
const SDK_NAME = "@explorins/pers-sdk";
|
|
10846
11001
|
/** SDK version - injected from package.json at build time */
|
|
10847
|
-
const SDK_VERSION = "2.1.
|
|
11002
|
+
const SDK_VERSION = "2.1.39";
|
|
10848
11003
|
/** Full SDK identifier for headers */
|
|
10849
11004
|
const SDK_USER_AGENT = `${SDK_NAME}/${SDK_VERSION}`;
|
|
10850
11005
|
|
|
@@ -10954,12 +11109,16 @@ class PersApiClient {
|
|
|
10954
11109
|
}
|
|
10955
11110
|
const { retryCount = 0, responseType = 'json', bypassAuth = false } = options || {};
|
|
10956
11111
|
const url = `${this.apiRoot}${endpoint}`;
|
|
10957
|
-
//
|
|
11112
|
+
// TOKEN VALIDATION: Ensure token is valid before request
|
|
11113
|
+
// This blocks the request until token validation completes - prevents 401s from expired tokens
|
|
10958
11114
|
if (!bypassAuth && this.mergedConfig.authProvider && retryCount === 0) {
|
|
10959
|
-
|
|
10960
|
-
|
|
10961
|
-
|
|
10962
|
-
|
|
11115
|
+
try {
|
|
11116
|
+
await this.ensureValidToken();
|
|
11117
|
+
}
|
|
11118
|
+
catch (error) {
|
|
11119
|
+
console.debug('[PersApiClient] Token validation failed:', error);
|
|
11120
|
+
// Continue with request - it will fail with 401 and trigger retry logic
|
|
11121
|
+
}
|
|
10963
11122
|
}
|
|
10964
11123
|
const requestOptions = {
|
|
10965
11124
|
headers: await this.getHeaders(!bypassAuth, method, url),
|
|
@@ -10987,49 +11146,63 @@ class PersApiClient {
|
|
|
10987
11146
|
return result;
|
|
10988
11147
|
}
|
|
10989
11148
|
catch (error) {
|
|
10990
|
-
// Error handling - proactive token refresh should prevent most 401s
|
|
10991
11149
|
const status = ErrorUtils.getStatus(error);
|
|
10992
11150
|
const errorMessage = ErrorUtils.getMessage(error);
|
|
10993
|
-
// Handle 401 errors
|
|
11151
|
+
// Handle 401 Unauthorized errors
|
|
10994
11152
|
if (status === 401) {
|
|
10995
11153
|
const backendError = ErrorUtils.extractBackendErrorDetails(error);
|
|
10996
|
-
//
|
|
10997
|
-
//
|
|
10998
|
-
//
|
|
11154
|
+
// ===========================================
|
|
11155
|
+
// FATAL AUTH ERRORS → Immediate logout
|
|
11156
|
+
// ===========================================
|
|
11157
|
+
// Fatal codes: REFRESH_TOKEN_EXPIRED, TOKEN_REVOKED, INVALID_REFRESH_TOKEN, etc.
|
|
10999
11158
|
if (this.authService.isFatalAuthError(backendError.code)) {
|
|
11000
|
-
|
|
11159
|
+
console.warn(`[PersApiClient] Fatal auth error: ${backendError.code}`);
|
|
11001
11160
|
await this.authService.handleAuthFailure();
|
|
11002
11161
|
this.emitErrorEvent(backendError, errorMessage, endpoint, method, status, error);
|
|
11003
11162
|
throw new AuthenticationError(errorMessage, endpoint, method, backendError);
|
|
11004
11163
|
}
|
|
11005
|
-
//
|
|
11164
|
+
// ===========================================
|
|
11165
|
+
// REFRESH REQUEST FAILED → Logout (prevents infinite loop)
|
|
11166
|
+
// ===========================================
|
|
11006
11167
|
if (options?.isRefreshRequest) {
|
|
11007
|
-
|
|
11168
|
+
console.warn('[PersApiClient] Refresh request itself failed with 401');
|
|
11008
11169
|
await this.authService.handleAuthFailure();
|
|
11009
11170
|
this.emitErrorEvent(backendError, errorMessage, endpoint, method, status, error);
|
|
11010
11171
|
throw new AuthenticationError(errorMessage, endpoint, method, backendError);
|
|
11011
11172
|
}
|
|
11012
|
-
//
|
|
11173
|
+
// ===========================================
|
|
11174
|
+
// RETRYABLE 401 (TOKEN_EXPIRED) → Try refresh, then retry
|
|
11175
|
+
// ===========================================
|
|
11013
11176
|
if (retryCount === 0 && this.mergedConfig.authProvider) {
|
|
11014
|
-
|
|
11015
|
-
|
|
11016
|
-
|
|
11017
|
-
|
|
11018
|
-
|
|
11019
|
-
|
|
11020
|
-
|
|
11021
|
-
|
|
11022
|
-
|
|
11023
|
-
|
|
11024
|
-
|
|
11025
|
-
|
|
11177
|
+
const refreshResult = await this.refreshManager.attemptInternalRefresh();
|
|
11178
|
+
if (refreshResult.success) {
|
|
11179
|
+
// Refresh succeeded → retry request with new token
|
|
11180
|
+
this._events?.emitSuccess({
|
|
11181
|
+
type: 'token_refreshed',
|
|
11182
|
+
domain: 'authentication',
|
|
11183
|
+
userMessage: 'Authentication token refreshed',
|
|
11184
|
+
});
|
|
11185
|
+
return await this.request(method, endpoint, body, { ...options, retryCount: 1 });
|
|
11186
|
+
}
|
|
11187
|
+
// Refresh failed - check if it's a definitive failure
|
|
11188
|
+
if (!refreshResult.retryable) {
|
|
11189
|
+
// Non-retryable failure (e.g., refresh token expired) → logout
|
|
11190
|
+
console.warn('[PersApiClient] Refresh failed with non-retryable error, logging out');
|
|
11191
|
+
await this.authService.handleAuthFailure();
|
|
11026
11192
|
}
|
|
11027
|
-
|
|
11028
|
-
//
|
|
11193
|
+
else {
|
|
11194
|
+
// Retryable failure (network error, etc.) → DON'T logout, let app retry later
|
|
11195
|
+
console.warn('[PersApiClient] Refresh failed with retryable error, NOT logging out');
|
|
11029
11196
|
}
|
|
11197
|
+
this.emitErrorEvent(backendError, errorMessage, endpoint, method, status, error);
|
|
11198
|
+
throw new AuthenticationError(errorMessage, endpoint, method, backendError);
|
|
11030
11199
|
}
|
|
11031
|
-
//
|
|
11032
|
-
|
|
11200
|
+
// ===========================================
|
|
11201
|
+
// RETRY FAILED (retryCount > 0) → Something wrong, but DON'T logout
|
|
11202
|
+
// ===========================================
|
|
11203
|
+
// We already refreshed successfully, but retry still got 401
|
|
11204
|
+
// This is unexpected - don't logout, let app investigate
|
|
11205
|
+
console.warn('[PersApiClient] Retry with new token still got 401 - not logging out');
|
|
11033
11206
|
this.emitErrorEvent(backendError, errorMessage, endpoint, method, status, error);
|
|
11034
11207
|
throw new AuthenticationError(errorMessage, endpoint, method, backendError);
|
|
11035
11208
|
}
|
|
@@ -12694,16 +12867,17 @@ class TokenManager {
|
|
|
12694
12867
|
return this.tokenService.getTokenByContractAddress(contractAddress, contractTokenId);
|
|
12695
12868
|
}
|
|
12696
12869
|
/**
|
|
12697
|
-
* Get all token metadata with filtering and
|
|
12870
|
+
* Get all token metadata with filtering, pagination, and include relations
|
|
12698
12871
|
*
|
|
12699
|
-
* Retrieves token metadata (rewards/stamps) with server-side filtering
|
|
12872
|
+
* Retrieves token metadata (rewards/stamps) with server-side filtering, pagination,
|
|
12873
|
+
* and optional include relations for additional data.
|
|
12700
12874
|
* Useful for displaying rewards (ERC1155) or stamps (ERC721) in admin tables.
|
|
12701
12875
|
* Non-admin users always get active metadata only.
|
|
12702
12876
|
*
|
|
12703
|
-
* @param options - Filter and
|
|
12877
|
+
* @param options - Filter, pagination, and include options
|
|
12704
12878
|
* @returns Promise resolving to paginated token metadata
|
|
12705
12879
|
*
|
|
12706
|
-
* @example Get paginated rewards
|
|
12880
|
+
* @example Get paginated rewards with counts
|
|
12707
12881
|
* ```typescript
|
|
12708
12882
|
* const rewards = await sdk.tokens.getTokenMetadata({
|
|
12709
12883
|
* tokenType: 'ERC1155',
|
|
@@ -12711,19 +12885,26 @@ class TokenManager {
|
|
|
12711
12885
|
* page: 1,
|
|
12712
12886
|
* limit: 10,
|
|
12713
12887
|
* sortBy: 'name',
|
|
12714
|
-
* sortOrder: 'ASC'
|
|
12888
|
+
* sortOrder: 'ASC',
|
|
12889
|
+
* include: ['mintCount', 'burnCount', 'token']
|
|
12715
12890
|
* });
|
|
12716
12891
|
*
|
|
12717
|
-
*
|
|
12718
|
-
*
|
|
12892
|
+
* rewards.data.forEach(r => {
|
|
12893
|
+
* console.log(`${r.name}: ${r.mintCount} minted, ${r.burnCount} burned`);
|
|
12894
|
+
* console.log(`Contract: ${r.included?.token?.contractAddress}`);
|
|
12895
|
+
* });
|
|
12719
12896
|
* ```
|
|
12720
12897
|
*
|
|
12721
|
-
* @example Get stamps with
|
|
12898
|
+
* @example Get stamps with owner business
|
|
12722
12899
|
* ```typescript
|
|
12723
12900
|
* const stamps = await sdk.tokens.getTokenMetadata({
|
|
12724
12901
|
* tokenType: 'ERC721',
|
|
12725
12902
|
* search: 'gold',
|
|
12726
|
-
*
|
|
12903
|
+
* include: ['ownerBusiness', 'token']
|
|
12904
|
+
* });
|
|
12905
|
+
*
|
|
12906
|
+
* stamps.data.forEach(s => {
|
|
12907
|
+
* console.log(`${s.name} owned by ${s.included?.ownerBusiness?.displayName}`);
|
|
12727
12908
|
* });
|
|
12728
12909
|
* ```
|
|
12729
12910
|
*/
|
|
@@ -12731,31 +12912,27 @@ class TokenManager {
|
|
|
12731
12912
|
return this.tokenService.getTokenMetadata(options);
|
|
12732
12913
|
}
|
|
12733
12914
|
/**
|
|
12734
|
-
* Get rewards (ERC1155 token metadata) with filtering and
|
|
12915
|
+
* Get rewards (ERC1155 token metadata) with filtering, pagination, and include relations
|
|
12735
12916
|
*
|
|
12736
12917
|
* Convenience method for fetching reward metadata. Rewards are ERC1155 tokens
|
|
12737
12918
|
* that represent collectible items, vouchers, or other redeemable rewards.
|
|
12738
12919
|
*
|
|
12739
|
-
* @param options - Filter and
|
|
12920
|
+
* @param options - Filter, pagination, and include options (tokenType is set automatically)
|
|
12740
12921
|
* @returns Promise resolving to paginated reward metadata
|
|
12741
12922
|
*
|
|
12742
|
-
* @example Get active rewards
|
|
12923
|
+
* @example Get active rewards with mint counts
|
|
12743
12924
|
* ```typescript
|
|
12744
12925
|
* const rewards = await sdk.tokens.getRewards({
|
|
12745
12926
|
* active: true,
|
|
12746
|
-
* limit: 10
|
|
12927
|
+
* limit: 10,
|
|
12928
|
+
* include: ['mintCount', 'burnCount', 'token', 'ownerBusiness']
|
|
12747
12929
|
* });
|
|
12748
12930
|
*
|
|
12749
|
-
*
|
|
12750
|
-
*
|
|
12751
|
-
*
|
|
12752
|
-
*
|
|
12753
|
-
*
|
|
12754
|
-
* ```typescript
|
|
12755
|
-
* const discountRewards = await sdk.tokens.getRewards({
|
|
12756
|
-
* search: 'discount',
|
|
12757
|
-
* sortBy: 'name',
|
|
12758
|
-
* sortOrder: 'ASC'
|
|
12931
|
+
* rewards.data.forEach(r => {
|
|
12932
|
+
* console.log(`${r.name}: ${r.mintCount ?? 0} minted`);
|
|
12933
|
+
* if (r.included?.token) {
|
|
12934
|
+
* console.log(` Chain: ${r.included.token.chainId}, Contract: ${r.included.token.contractAddress}`);
|
|
12935
|
+
* }
|
|
12759
12936
|
* });
|
|
12760
12937
|
* ```
|
|
12761
12938
|
*/
|
|
@@ -12763,31 +12940,27 @@ class TokenManager {
|
|
|
12763
12940
|
return this.tokenService.getRewards(options);
|
|
12764
12941
|
}
|
|
12765
12942
|
/**
|
|
12766
|
-
* Get stamps (ERC721 token metadata) with filtering and
|
|
12943
|
+
* Get stamps (ERC721 token metadata) with filtering, pagination, and include relations
|
|
12767
12944
|
*
|
|
12768
12945
|
* Convenience method for fetching stamp metadata. Stamps are ERC721 tokens
|
|
12769
12946
|
* that represent achievements, badges, or collectible status markers.
|
|
12770
12947
|
*
|
|
12771
|
-
* @param options - Filter and
|
|
12948
|
+
* @param options - Filter, pagination, and include options (tokenType is set automatically)
|
|
12772
12949
|
* @returns Promise resolving to paginated stamp metadata
|
|
12773
12950
|
*
|
|
12774
|
-
* @example Get active stamps
|
|
12951
|
+
* @example Get active stamps with all includes
|
|
12775
12952
|
* ```typescript
|
|
12776
12953
|
* const stamps = await sdk.tokens.getStamps({
|
|
12777
12954
|
* active: true,
|
|
12778
|
-
* limit: 10
|
|
12955
|
+
* limit: 10,
|
|
12956
|
+
* include: ['mintCount', 'burnCount', 'token', 'ownerBusiness']
|
|
12779
12957
|
* });
|
|
12780
12958
|
*
|
|
12781
|
-
*
|
|
12782
|
-
*
|
|
12783
|
-
*
|
|
12784
|
-
*
|
|
12785
|
-
*
|
|
12786
|
-
* ```typescript
|
|
12787
|
-
* const goldStamps = await sdk.tokens.getStamps({
|
|
12788
|
-
* tags: ['gold', 'premium'],
|
|
12789
|
-
* sortBy: 'createdAt',
|
|
12790
|
-
* sortOrder: 'DESC'
|
|
12959
|
+
* stamps.data.forEach(s => {
|
|
12960
|
+
* console.log(`${s.name}: ${s.mintCount ?? 0} minted`);
|
|
12961
|
+
* if (s.included?.ownerBusiness) {
|
|
12962
|
+
* console.log(` Owner: ${s.included.ownerBusiness.displayName}`);
|
|
12963
|
+
* }
|
|
12791
12964
|
* });
|
|
12792
12965
|
* ```
|
|
12793
12966
|
*/
|
|
@@ -12885,6 +13058,32 @@ class TokenManager {
|
|
|
12885
13058
|
async toggleTokenActive(tokenId) {
|
|
12886
13059
|
return this.tokenService.toggleTokenActive(tokenId);
|
|
12887
13060
|
}
|
|
13061
|
+
/**
|
|
13062
|
+
* Admin: Delete token metadata (soft delete)
|
|
13063
|
+
*
|
|
13064
|
+
* Soft deletes token metadata by setting deletedAt timestamp.
|
|
13065
|
+
* Requires administrator privileges. Will fail with 409 Conflict
|
|
13066
|
+
* if metadata is currently in use by active campaigns or redemptions.
|
|
13067
|
+
*
|
|
13068
|
+
* @param metadataId - ID of the token metadata to delete
|
|
13069
|
+
* @throws {PersApiError} When not authenticated as admin
|
|
13070
|
+
* @throws {PersApiError} 409 Conflict if metadata is in use
|
|
13071
|
+
*
|
|
13072
|
+
* @example
|
|
13073
|
+
* ```typescript
|
|
13074
|
+
* try {
|
|
13075
|
+
* await sdk.tokens.deleteTokenMetadata('metadata-123');
|
|
13076
|
+
* console.log('Token metadata deleted');
|
|
13077
|
+
* } catch (error) {
|
|
13078
|
+
* if (error.statusCode === 409) {
|
|
13079
|
+
* console.log('Cannot delete: metadata is used by campaigns/redemptions');
|
|
13080
|
+
* }
|
|
13081
|
+
* }
|
|
13082
|
+
* ```
|
|
13083
|
+
*/
|
|
13084
|
+
async deleteTokenMetadata(metadataId) {
|
|
13085
|
+
return this.tokenService.deleteTokenMetadata(metadataId);
|
|
13086
|
+
}
|
|
12888
13087
|
/**
|
|
12889
13088
|
* Get the full token SDK for advanced operations
|
|
12890
13089
|
*
|
|
@@ -15278,6 +15477,21 @@ class RedemptionManager {
|
|
|
15278
15477
|
async deleteRedemptionType(id) {
|
|
15279
15478
|
return this.redemptionService.deleteRedemptionType(id);
|
|
15280
15479
|
}
|
|
15480
|
+
/**
|
|
15481
|
+
* Delete a redemption (soft delete)
|
|
15482
|
+
*
|
|
15483
|
+
* @param id - Redemption ID to delete
|
|
15484
|
+
* @returns Promise resolving to true if deleted successfully
|
|
15485
|
+
*
|
|
15486
|
+
* @example
|
|
15487
|
+
* ```typescript
|
|
15488
|
+
* const success = await sdk.redemptions.deleteRedemption('redemption-123');
|
|
15489
|
+
* console.log('Deleted:', success);
|
|
15490
|
+
* ```
|
|
15491
|
+
*/
|
|
15492
|
+
async deleteRedemption(id) {
|
|
15493
|
+
return this.redemptionService.deleteRedemption(id);
|
|
15494
|
+
}
|
|
15281
15495
|
/**
|
|
15282
15496
|
* Get the full redemption service for advanced operations
|
|
15283
15497
|
*
|
|
@@ -46730,6 +46944,7 @@ exports.VALID_CAMPAIGN_RELATIONS = VALID_CAMPAIGN_RELATIONS;
|
|
|
46730
46944
|
exports.VALID_REDEMPTION_REDEEM_RELATIONS = VALID_REDEMPTION_REDEEM_RELATIONS;
|
|
46731
46945
|
exports.VALID_REDEMPTION_RELATIONS = VALID_REDEMPTION_RELATIONS;
|
|
46732
46946
|
exports.VALID_RELATIONS = VALID_RELATIONS;
|
|
46947
|
+
exports.VALID_TOKEN_METADATA_RELATIONS = VALID_TOKEN_METADATA_RELATIONS;
|
|
46733
46948
|
exports.VALID_TRANSACTION_RELATIONS = VALID_TRANSACTION_RELATIONS;
|
|
46734
46949
|
exports.VALID_USER_RELATIONS = VALID_USER_RELATIONS;
|
|
46735
46950
|
exports.WalletEventsManager = WalletEventsManager;
|
|
@@ -46781,6 +46996,7 @@ exports.isValidCampaignRelation = isValidCampaignRelation;
|
|
|
46781
46996
|
exports.isValidRedemptionRedeemRelation = isValidRedemptionRedeemRelation;
|
|
46782
46997
|
exports.isValidRedemptionRelation = isValidRedemptionRelation;
|
|
46783
46998
|
exports.isValidRelation = isValidRelation;
|
|
46999
|
+
exports.isValidTokenMetadataRelation = isValidTokenMetadataRelation;
|
|
46784
47000
|
exports.isValidTransactionRelation = isValidTransactionRelation;
|
|
46785
47001
|
exports.isValidUserRelation = isValidUserRelation;
|
|
46786
47002
|
exports.mergeWithDefaults = mergeWithDefaults;
|