@explorins/pers-sdk-react-native 1.5.21 → 1.5.23

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.
@@ -2,7 +2,7 @@ import type { RedemptionCreateRequestDTO, RedemptionDTO, RedemptionRedeemDTO, Re
2
2
  export declare const useRedemptions: () => {
3
3
  getActiveRedemptions: () => Promise<RedemptionDTO[]>;
4
4
  getUserRedemptions: () => Promise<RedemptionRedeemDTO[]>;
5
- redeemOffer: (redemptionId: string) => Promise<RedemptionRedeemRequestResponseDTO>;
5
+ redeem: (redemptionId: string) => Promise<RedemptionRedeemRequestResponseDTO>;
6
6
  getRedemptionTypes: () => Promise<RedemptionTypeDTO[]>;
7
7
  createRedemption: (redemptionData: RedemptionCreateRequestDTO) => Promise<RedemptionDTO>;
8
8
  getAllRedemptions: (active?: boolean) => Promise<RedemptionDTO[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"useRedemptions.d.ts","sourceRoot":"","sources":["../../src/hooks/useRedemptions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,0BAA0B,EAC1B,aAAa,EACb,mBAAmB,EACnB,kCAAkC,EAClC,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAEhC,eAAO,MAAM,cAAc;gCAI0B,QAAQ,aAAa,EAAE,CAAC;8BAe1B,QAAQ,mBAAmB,EAAE,CAAC;gCAmB1B,MAAM,KAAG,QAAQ,kCAAkC,CAAC;8BAsFxD,QAAQ,iBAAiB,EAAE,CAAC;uCA/BjB,0BAA0B,KAAG,QAAQ,aAAa,CAAC;iCAgBzD,OAAO,KAAG,QAAQ,aAAa,EAAE,CAAC;qCA8B9B,MAAM,kBAAkB,0BAA0B,KAAG,QAAQ,aAAa,CAAC;2CAerE,MAAM,KAAG,QAAQ,aAAa,CAAC;;CA0BhG,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC"}
1
+ {"version":3,"file":"useRedemptions.d.ts","sourceRoot":"","sources":["../../src/hooks/useRedemptions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,0BAA0B,EAC1B,aAAa,EACb,mBAAmB,EACnB,kCAAkC,EAClC,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAEhC,eAAO,MAAM,cAAc;gCAI0B,QAAQ,aAAa,EAAE,CAAC;8BAe1B,QAAQ,mBAAmB,EAAE,CAAC;2BAmB/B,MAAM,KAAG,QAAQ,kCAAkC,CAAC;8BAsFnD,QAAQ,iBAAiB,EAAE,CAAC;uCA/BjB,0BAA0B,KAAG,QAAQ,aAAa,CAAC;iCAgBzD,OAAO,KAAG,QAAQ,aAAa,EAAE,CAAC;qCA8B9B,MAAM,kBAAkB,0BAA0B,KAAG,QAAQ,aAAa,CAAC;2CAerE,MAAM,KAAG,QAAQ,aAAa,CAAC;;CA0BhG,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC"}
@@ -36,16 +36,16 @@ export const useRedemptions = () => {
36
36
  throw error;
37
37
  }
38
38
  }, [sdk, isInitialized, isAuthenticated]);
39
- const redeemOffer = useCallback(async (redemptionId) => {
39
+ const redeem = useCallback(async (redemptionId) => {
40
40
  if (!isInitialized || !sdk) {
41
41
  throw new Error('SDK not initialized. Call initialize() first.');
42
42
  }
43
43
  if (!isAuthenticated) {
44
- throw new Error('SDK not authenticated. redeemOffer requires authentication.');
44
+ throw new Error('SDK not authenticated. redeem requires authentication.');
45
45
  }
46
46
  try {
47
47
  console.log('Redeeming redemption:', redemptionId);
48
- const result = await sdk.redemptions.redeemOffer(redemptionId);
48
+ const result = await sdk.redemptions.redeem(redemptionId);
49
49
  // Check if result has signing fields and sign transaction if required and signer is available
50
50
  console.log('Redemption processed successfully:', result);
51
51
  const txToken = result.senderTransaction?.actionable?.authToken;
@@ -162,7 +162,7 @@ export const useRedemptions = () => {
162
162
  return {
163
163
  getActiveRedemptions,
164
164
  getUserRedemptions,
165
- redeemOffer,
165
+ redeem,
166
166
  getRedemptionTypes,
167
167
  createRedemption,
168
168
  getAllRedemptions,
package/dist/index.js CHANGED
@@ -22632,17 +22632,21 @@ class ErrorUtils {
22632
22632
  if (typeof error !== 'object' || error === null)
22633
22633
  return false;
22634
22634
  const err = error;
22635
- const apiError = err?.error || err?.response?.data || err;
22636
- const status = err?.status || err?.response?.status || err?.statusCode;
22637
- // Explicit token expired messages
22635
+ // Check for explicit token expired indicators
22636
+ if (err?.code === 'TOKEN_EXPIRED' || err?.errorCode === 'TOKEN_EXPIRED') {
22637
+ return true;
22638
+ }
22639
+ // Check in response data
22640
+ const apiError = err?.response?.data || err;
22638
22641
  if (apiError?.code === 'TOKEN_EXPIRED' || apiError?.errorCode === 'TOKEN_EXPIRED') {
22639
22642
  return true;
22640
22643
  }
22641
- // Any 401 Unauthorized error should be treated as token expiration for auth flows
22644
+ // Any 401 error is treated as token expiration
22645
+ const status = err?.status || err?.statusCode || err?.response?.status;
22642
22646
  if (status === 401) {
22643
22647
  return true;
22644
22648
  }
22645
- // Check for token-related messages in other error formats
22649
+ // Check for token-related messages
22646
22650
  const message = apiError?.message || err?.message || '';
22647
22651
  if (message && typeof message === 'string') {
22648
22652
  const lowerMessage = message.toLowerCase();
@@ -22659,8 +22663,9 @@ class ErrorUtils {
22659
22663
  if (typeof error !== 'object' || error === null)
22660
22664
  return 'Unknown error';
22661
22665
  const err = error;
22662
- const apiError = err?.error || err?.response?.data || err;
22663
- return apiError?.message || apiError?.detail || err?.message || 'Request failed';
22666
+ // Try structured error first
22667
+ const apiError = err?.response?.data || err;
22668
+ return apiError?.message || apiError?.detail || apiError?.userMessage || err?.message || 'Request failed';
22664
22669
  }
22665
22670
  /**
22666
22671
  * Fast status code extraction
@@ -22669,6 +22674,7 @@ class ErrorUtils {
22669
22674
  if (typeof error !== 'object' || error === null)
22670
22675
  return null;
22671
22676
  const err = error;
22677
+ // Direct properties first
22672
22678
  return err?.status || err?.statusCode || err?.response?.status || null;
22673
22679
  }
22674
22680
  /**
@@ -22678,11 +22684,14 @@ class ErrorUtils {
22678
22684
  if (typeof error !== 'object' || error === null)
22679
22685
  return false;
22680
22686
  const err = error;
22681
- // Check explicit retryable property first (fastest)
22687
+ // Check explicit retryable property
22688
+ const apiError = err?.response?.data || err;
22689
+ if (typeof apiError?.retryable === 'boolean')
22690
+ return apiError.retryable;
22682
22691
  if (typeof err?.retryable === 'boolean')
22683
22692
  return err.retryable;
22684
- // Fast status-based check
22685
- const status = ErrorUtils.getStatus(error);
22693
+ // Status-based check
22694
+ const status = this.getStatus(error);
22686
22695
  return status === null || status >= 500 || status === 429;
22687
22696
  }
22688
22697
  /**
@@ -22694,6 +22703,11 @@ class ErrorUtils {
22694
22703
  // Try to extract structured error response from HTTP error
22695
22704
  if (error && typeof error === 'object') {
22696
22705
  const httpError = error;
22706
+ // Use centralized parsing for React Native HTTP client format
22707
+ const parsedError = this.parseHttpClientError(error);
22708
+ if (parsedError && typeof parsedError === 'object') {
22709
+ return parsedError;
22710
+ }
22697
22711
  // Check if error has response data (common in HTTP clients)
22698
22712
  if (httpError.response?.data) {
22699
22713
  return httpError.response.data;
@@ -22729,6 +22743,38 @@ class ErrorUtils {
22729
22743
  };
22730
22744
  }
22731
22745
  }
22746
+ /**
22747
+ * Parse React Native HTTP client error format
22748
+ * Handles format: "HTTP 401: Unauthorized - {json}"
22749
+ */
22750
+ static parseHttpClientError(error) {
22751
+ try {
22752
+ if (typeof error === 'object' && error !== null) {
22753
+ const err = error;
22754
+ const message = err?.message || '';
22755
+ if (typeof message === 'string' && message.includes('HTTP') && message.includes(' - ')) {
22756
+ // Extract JSON part after " - "
22757
+ const jsonStart = message.lastIndexOf(' - ');
22758
+ if (jsonStart !== -1) {
22759
+ const jsonStr = message.substring(jsonStart + 3);
22760
+ if (jsonStr.trim()) {
22761
+ try {
22762
+ return JSON.parse(jsonStr);
22763
+ }
22764
+ catch {
22765
+ // If JSON parsing fails, return the raw string as message
22766
+ return { message: jsonStr };
22767
+ }
22768
+ }
22769
+ }
22770
+ }
22771
+ }
22772
+ return null;
22773
+ }
22774
+ catch {
22775
+ return null;
22776
+ }
22777
+ }
22732
22778
  /**
22733
22779
  * Check if error is from PERS API (uses @explorins/pers-shared format)
22734
22780
  */
@@ -26091,13 +26137,11 @@ class TokenRefreshManager {
26091
26137
  if (isTokenExpired(token, this.tokenRefreshMarginSeconds)) {
26092
26138
  const refreshSuccess = await this.attemptInternalRefresh();
26093
26139
  if (!refreshSuccess) {
26094
- // Failed to refresh - delegate cleanup to AuthService
26095
26140
  await this.authService.handleAuthFailure();
26096
26141
  }
26097
26142
  }
26098
26143
  }
26099
26144
  catch (error) {
26100
- // Delegate token cleanup to AuthService for consistency
26101
26145
  await this.authService.handleAuthFailure();
26102
26146
  }
26103
26147
  }
@@ -26107,7 +26151,6 @@ class TokenRefreshManager {
26107
26151
  return true;
26108
26152
  }
26109
26153
  catch (error) {
26110
- // Check if this is a 401 error and set auth failure flag
26111
26154
  const isAuthError = error && typeof error === 'object' && 'status' in error && error.status === 401;
26112
26155
  if (isAuthError) {
26113
26156
  await this.authService.handleAuthFailure();
@@ -26368,7 +26411,6 @@ class PersApiClient {
26368
26411
  async ensureInitialized() {
26369
26412
  if (this.initializationPromise) {
26370
26413
  await this.initializationPromise;
26371
- // Clear after successful initialization to prevent holding references
26372
26414
  this.initializationPromise = null;
26373
26415
  }
26374
26416
  }
@@ -26384,8 +26426,9 @@ class PersApiClient {
26384
26426
  }
26385
26427
  const { retryCount = 0, responseType = 'json', bypassAuth = false } = options || {};
26386
26428
  const url = `${this.apiRoot}${endpoint}`;
26387
- // Proactive token validation for optimal performance
26429
+ // SMART TOKEN VALIDATION: Only check if we suspect the token might be expired
26388
26430
  if (!bypassAuth && this.mergedConfig.authProvider && retryCount === 0) {
26431
+ // Fire-and-forget validation - don't block the request unless we know there's an issue
26389
26432
  this.ensureValidToken().catch(error => {
26390
26433
  console.debug('[PersApiClient] Background token validation failed:', error);
26391
26434
  });
@@ -26437,7 +26480,7 @@ class PersApiClient {
26437
26480
  }
26438
26481
  }
26439
26482
  catch (refreshError) {
26440
- // Refresh failed - let auth service handle it
26483
+ // console.error('[PersApiClient] Token refresh failed:', refreshError);
26441
26484
  }
26442
26485
  }
26443
26486
  // Auth failure - let AuthService handle cleanup and notify app
@@ -28542,7 +28585,7 @@ class CampaignManager {
28542
28585
  * console.log(`${offers.length} redemption offers available`);
28543
28586
  *
28544
28587
  * // Redeem a specific offer
28545
- * const redemptionResult = await sdk.redemptions.redeemOffer('discount-10-percent');
28588
+ * const redemptionResult = await sdk.redemptions.redeem('discount-10-percent');
28546
28589
  * console.log('Redemption successful:', redemptionResult.success);
28547
28590
  *
28548
28591
  * // Check redemption history
@@ -28686,7 +28729,7 @@ class RedemptionManager {
28686
28729
  * @example Basic Redemption
28687
28730
  * ```typescript
28688
28731
  * try {
28689
- * const result = await sdk.redemptions.redeemOffer('coffee-voucher-123');
28732
+ * const result = await sdk.redemptions.redeem('coffee-voucher-123');
28690
28733
  *
28691
28734
  * if (result.success) {
28692
28735
  * console.log('✅ Redemption Successful!');
@@ -28742,7 +28785,7 @@ class RedemptionManager {
28742
28785
  * });
28743
28786
  *
28744
28787
  * if (canAfford) {
28745
- * const result = await sdk.redemptions.redeemOffer(targetOffer.id);
28788
+ * const result = await sdk.redemptions.redeem(targetOffer.id);
28746
28789
  * console.log('Redemption processed:', result.success);
28747
28790
  * } else {
28748
28791
  * console.log('Insufficient tokens for this redemption');
@@ -28750,7 +28793,7 @@ class RedemptionManager {
28750
28793
  * }
28751
28794
  * ```
28752
28795
  */
28753
- async redeemOffer(redemptionId) {
28796
+ async redeem(redemptionId) {
28754
28797
  return this.redemptionService.redeemRedemption(redemptionId);
28755
28798
  }
28756
28799
  /**
@@ -31477,7 +31520,7 @@ class PersSDK {
31477
31520
  * @example
31478
31521
  * ```typescript
31479
31522
  * const redemptions = await sdk.redemptions.getActiveRedemptions();
31480
- * await sdk.redemptions.redeemOffer(redemptionId);
31523
+ * await sdk.redemptions.redeem(redemptionId);
31481
31524
  * const history = await sdk.redemptions.getUserRedemptions();
31482
31525
  * ```
31483
31526
  */
@@ -31828,18 +31871,18 @@ class ReactNativeHttpClient {
31828
31871
  try {
31829
31872
  const response = await fetch(fullUrl, config);
31830
31873
  if (!response.ok) {
31831
- // Try to get error details from response
31832
- let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
31874
+ // Get raw error response for ErrorUtils to handle
31875
+ let errorText = '';
31833
31876
  try {
31834
- const errorBody = await response.text();
31835
- if (errorBody) {
31836
- errorMessage += ` - ${errorBody}`;
31837
- }
31877
+ errorText = await response.text();
31838
31878
  }
31839
31879
  catch (e) {
31840
31880
  // Ignore errors when reading error body
31841
31881
  }
31842
- throw new Error(errorMessage);
31882
+ // Create simple error with HTTP status and raw response
31883
+ const httpError = new Error(`HTTP ${response.status}: ${response.statusText} - ${errorText}`);
31884
+ httpError.status = response.status;
31885
+ throw httpError;
31843
31886
  }
31844
31887
  // Handle different response types
31845
31888
  switch (options?.responseType) {
@@ -33445,16 +33488,16 @@ const useRedemptions = () => {
33445
33488
  throw error;
33446
33489
  }
33447
33490
  }, [sdk, isInitialized, isAuthenticated]);
33448
- const redeemOffer = react.useCallback(async (redemptionId) => {
33491
+ const redeem = react.useCallback(async (redemptionId) => {
33449
33492
  if (!isInitialized || !sdk) {
33450
33493
  throw new Error('SDK not initialized. Call initialize() first.');
33451
33494
  }
33452
33495
  if (!isAuthenticated) {
33453
- throw new Error('SDK not authenticated. redeemOffer requires authentication.');
33496
+ throw new Error('SDK not authenticated. redeem requires authentication.');
33454
33497
  }
33455
33498
  try {
33456
33499
  console.log('Redeeming redemption:', redemptionId);
33457
- const result = await sdk.redemptions.redeemOffer(redemptionId);
33500
+ const result = await sdk.redemptions.redeem(redemptionId);
33458
33501
  // Check if result has signing fields and sign transaction if required and signer is available
33459
33502
  console.log('Redemption processed successfully:', result);
33460
33503
  const txToken = result.senderTransaction?.actionable?.authToken;
@@ -33571,7 +33614,7 @@ const useRedemptions = () => {
33571
33614
  return {
33572
33615
  getActiveRedemptions,
33573
33616
  getUserRedemptions,
33574
- redeemOffer,
33617
+ redeem,
33575
33618
  getRedemptionTypes,
33576
33619
  createRedemption,
33577
33620
  getAllRedemptions,