@explorins/pers-sdk-react-native 2.2.0-alpha.3 → 2.2.0-alpha.5

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.
@@ -1,9 +1,21 @@
1
1
  /**
2
2
  * AsyncStorage Token Storage for React Native Mobile Platforms
3
3
  *
4
- * Bundler-agnostic AsyncStorage implementation for mobile platforms
4
+ * Bundler-agnostic AsyncStorage implementation for mobile platforms.
5
+ *
6
+ * IMPORTANT: Due to bundler conflicts between Rollup (SDK) and Metro (app),
7
+ * the consuming app MUST set global.AsyncStorageModule before using this SDK:
8
+ *
9
+ * ```javascript
10
+ * // In your app's index.js, BEFORE importing the SDK:
11
+ * import AsyncStorage from '@react-native-async-storage/async-storage';
12
+ * global.AsyncStorageModule = AsyncStorage;
13
+ * ```
5
14
  */
6
15
  import type { TokenStorage } from '@explorins/pers-sdk/core';
16
+ declare global {
17
+ var AsyncStorageModule: any;
18
+ }
7
19
  /**
8
20
  * AsyncStorage implementation for mobile platforms
9
21
  *
@@ -1 +1 @@
1
- {"version":3,"file":"async-storage-token-storage.d.ts","sourceRoot":"","sources":["../../src/storage/async-storage-token-storage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AA0F7D;;;;;GAKG;AACH,qBAAa,wBAAyB,YAAW,YAAY;IAC3D,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAA8B;gBAEtC,SAAS,GAAE,MAAuB;IAgBxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAYxC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB7B"}
1
+ {"version":3,"file":"async-storage-token-storage.d.ts","sourceRoot":"","sources":["../../src/storage/async-storage-token-storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAG7D,OAAO,CAAC,MAAM,CAAC;IACb,IAAI,kBAAkB,EAAE,GAAG,CAAC;CAC7B;AA4FD;;;;;GAKG;AACH,qBAAa,wBAAyB,YAAW,YAAY;IAC3D,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAA8B;gBAEtC,SAAS,GAAE,MAAuB;IAgBxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAYxC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB7B"}
@@ -1,52 +1,62 @@
1
1
  /**
2
2
  * AsyncStorage Token Storage for React Native Mobile Platforms
3
3
  *
4
- * Bundler-agnostic AsyncStorage implementation for mobile platforms
4
+ * Bundler-agnostic AsyncStorage implementation for mobile platforms.
5
+ *
6
+ * IMPORTANT: Due to bundler conflicts between Rollup (SDK) and Metro (app),
7
+ * the consuming app MUST set global.AsyncStorageModule before using this SDK:
8
+ *
9
+ * ```javascript
10
+ * // In your app's index.js, BEFORE importing the SDK:
11
+ * import AsyncStorage from '@react-native-async-storage/async-storage';
12
+ * global.AsyncStorageModule = AsyncStorage;
13
+ * ```
5
14
  */
6
15
  /**
7
- * Dynamically resolve AsyncStorage at runtime to avoid bundler conflicts
8
- *
9
- * When the SDK is pre-bundled (e.g., with Rollup) and then consumed by an app
10
- * that uses Metro, the static import can get resolved incorrectly due to module
11
- * hoisting and namespace collisions.
16
+ * Get AsyncStorage from the global that the app must set.
12
17
  *
13
- * By using require() at runtime, we ensure we get the actual AsyncStorage
14
- * from the app's node_modules, not a bundled/mangled version.
18
+ * This bypasses all bundler resolution issues by having the app
19
+ * explicitly provide the AsyncStorage module via a global variable.
15
20
  */
16
21
  function getAsyncStorage() {
17
- // Use require() to get the module at runtime
18
- // This bypasses any bundler transformations that might have corrupted the import
22
+ // Check if the app has set the global
23
+ if (global.AsyncStorageModule) {
24
+ const module = global.AsyncStorageModule;
25
+ // Validate it has the expected methods
26
+ if (typeof module?.getItem === 'function') {
27
+ console.log('[AsyncStorage] Using global.AsyncStorageModule (direct)');
28
+ return module;
29
+ }
30
+ else if (typeof module?.default?.getItem === 'function') {
31
+ console.log('[AsyncStorage] Using global.AsyncStorageModule.default');
32
+ return module.default;
33
+ }
34
+ }
35
+ // Fallback: try require (may not work due to bundler conflicts)
19
36
  try {
20
- // Try default export first (Metro pattern)
37
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
21
38
  const module = require('@react-native-async-storage/async-storage');
22
- // Log for debugging what we actually received
23
- const hasGetItem = typeof module?.getItem === 'function';
24
- const hasDefaultGetItem = typeof module?.default?.getItem === 'function';
25
- console.log('[AsyncStorage] Module resolution:', {
26
- hasGetItem,
27
- hasDefaultGetItem,
28
- moduleType: typeof module,
29
- keys: module ? Object.keys(module).slice(0, 10) : []
30
- });
31
- if (hasDefaultGetItem) {
39
+ if (typeof module?.default?.getItem === 'function') {
40
+ console.log('[AsyncStorage] Fallback: using require().default');
32
41
  return module.default;
33
42
  }
34
- else if (hasGetItem) {
43
+ else if (typeof module?.getItem === 'function') {
44
+ console.log('[AsyncStorage] Fallback: using require() direct');
35
45
  return module;
36
46
  }
37
- else {
38
- throw new Error('AsyncStorage module found but missing getItem method');
39
- }
40
47
  }
41
- catch (error) {
42
- console.error('[AsyncStorage] Failed to dynamically require:', error);
43
- throw new Error('Failed to load @react-native-async-storage/async-storage. ' +
44
- 'Make sure it is installed and properly linked.');
48
+ catch (e) {
49
+ // Ignore require errors
45
50
  }
51
+ // If we get here, provide a helpful error
52
+ throw new Error('AsyncStorage not available. Please add this to your app\'s index.js BEFORE importing the SDK:\n\n' +
53
+ ' import AsyncStorage from \'@react-native-async-storage/async-storage\';\n' +
54
+ ' global.AsyncStorageModule = AsyncStorage;\n\n' +
55
+ 'This is required due to bundler conflicts between Rollup and Metro.');
46
56
  }
47
57
  /**
48
58
  * Bundler-agnostic AsyncStorage wrapper
49
- * Now uses runtime require() to avoid bundler conflicts
59
+ * Uses global injection to avoid bundler conflicts
50
60
  */
51
61
  class BundlerAgnosticAsyncStorage {
52
62
  constructor() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@explorins/pers-sdk-react-native",
3
- "version": "2.2.0-alpha.3",
3
+ "version": "2.2.0-alpha.5",
4
4
  "description": "React Native SDK for PERS Platform - Tourism Loyalty System with Blockchain Transaction Signing and WebAuthn Authentication",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -38,7 +38,7 @@
38
38
  "license": "MIT",
39
39
  "dependencies": {
40
40
  "@explorins/pers-sdk": "^2.1.32",
41
- "@explorins/pers-signer": "^1.0.33",
41
+ "@explorins/pers-signer": "^1.0.34",
42
42
  "buffer": "^6.0.3",
43
43
  "ethers": "^6.15.0"
44
44
  },
@@ -1,6 +1,11 @@
1
1
  import { useCallback, useState, useRef, useEffect } from 'react';
2
2
  // import { usePersSDK } from '../providers/PersSDKProvider';
3
- import { PersSignerConfig, SigningStatus, StatusCallback, StatusUpdateData } from '@explorins/pers-signer';
3
+
4
+ // TYPE-ONLY imports from /types entry - NO native module deps, safe at any time
5
+ import type { PersSignerConfig, StatusCallback, StatusUpdateData } from '@explorins/pers-signer/types';
6
+ import type { SigningStatus as SigningStatusType } from '@explorins/pers-signer/types';
7
+ // Runtime const import - also from /types (no native deps)
8
+ import { SigningStatus as SigningStatusConst } from '@explorins/pers-signer/types';
4
9
 
5
10
  // Import actual SDK types from the React Native-specific export
6
11
  type PersSignerSDK = import('@explorins/pers-signer/react-native').PersSignerSDK;
@@ -8,21 +13,29 @@ type SubmissionResult = import('@explorins/pers-signer/react-native').Submission
8
13
  type AuthenticatedUser = import('@explorins/pers-signer/react-native').AuthenticatedUser;
9
14
  type TransactionSigningResult = import('@explorins/pers-signer/react-native').TransactionSigningResult;
10
15
 
11
- // Re-export signing status types from signer SDK for convenience
12
- export { SigningStatus };
16
+ // Re-export the type for external consumers
17
+ export type { SigningStatusType as SigningStatus };
13
18
  export type { StatusUpdateData };
14
19
 
15
20
  /**
16
21
  * Simple status callback function type for React Native consumers
17
22
  * (Simplified from the signer SDK's object-based StatusCallback interface)
18
23
  */
19
- export type OnStatusUpdateFn = (status: SigningStatus, message: string, data?: StatusUpdateData) => void;
24
+ export type OnStatusUpdateFn = (status: SigningStatusType, message: string, data?: StatusUpdateData) => void;
20
25
 
21
26
 
22
- // Lazy-loaded signer SDK factory - initialized on first use to avoid native module timing issues
27
+ // Lazy-loaded signer SDK - initialized on first use to avoid native module timing issues
23
28
  let _createPersSignerSDK: ((config: PersSignerConfig) => Promise<PersSignerSDK>) | null = null;
24
29
  let _signerInitAttempted = false;
25
30
 
31
+ /**
32
+ * Get the SigningStatus const object
33
+ * Now directly imported from /types (no native deps, always available)
34
+ */
35
+ function getSigningStatus(): typeof SigningStatusType {
36
+ return SigningStatusConst;
37
+ }
38
+
26
39
  /**
27
40
  * Lazily load the PERS Signer SDK.
28
41
  *
@@ -41,7 +54,8 @@ function getSignerSDKFactory(): ((config: PersSignerConfig) => Promise<PersSigne
41
54
 
42
55
  // Check for customer pre-initialized global (for native module timing issues)
43
56
  if (typeof global !== 'undefined' && (global as any).__PersSigner?.createPersSignerSDK) {
44
- _createPersSignerSDK = (global as any).__PersSigner.createPersSignerSDK;
57
+ const globalModule = (global as any).__PersSigner;
58
+ _createPersSignerSDK = globalModule.createPersSignerSDK;
45
59
  return _createPersSignerSDK;
46
60
  }
47
61
 
@@ -79,7 +93,7 @@ export interface TransactionSignerHook {
79
93
  signPersTransaction: (jwt: string, onStatusUpdate?: OnStatusUpdateFn) => Promise<TransactionSigningResult>;
80
94
  isSignerInitialized: boolean;
81
95
  isSignerAvailable: boolean;
82
- currentStatus: SigningStatus | null;
96
+ currentStatus: SigningStatusType | null;
83
97
  statusMessage: string | null;
84
98
  }
85
99
 
@@ -266,7 +280,7 @@ const DEFAULT_ETHERS_PROVIDER = "https://sepolia.infura.io/v3/2781b4b5242343d5b0
266
280
  export const useTransactionSigner = (): TransactionSignerHook => {
267
281
  // const { isInitialized, isAuthenticated, user } = usePersSDK();
268
282
  const [isSignerInitialized, setIsSignerInitialized] = useState(false);
269
- const [currentStatus, setCurrentStatus] = useState<SigningStatus | null>(null);
283
+ const [currentStatus, setCurrentStatus] = useState<SigningStatusType | null>(null);
270
284
  const [statusMessage, setStatusMessage] = useState<string | null>(null);
271
285
  const signerSDKRef = useRef<PersSignerSDK | null>(null);
272
286
 
@@ -398,7 +412,7 @@ export const useTransactionSigner = (): TransactionSignerHook => {
398
412
 
399
413
  // Create status callback wrapper that updates both hook state and calls user callback
400
414
  const statusCallback: StatusCallback = {
401
- onStatusUpdate: (status: SigningStatus, message: string, data?: StatusUpdateData) => {
415
+ onStatusUpdate: (status: SigningStatusType, message: string, data?: StatusUpdateData) => {
402
416
  setCurrentStatus(status);
403
417
  setStatusMessage(message);
404
418
  onStatusUpdate?.(status, message, data);
@@ -413,7 +427,8 @@ export const useTransactionSigner = (): TransactionSignerHook => {
413
427
 
414
428
  } catch (error) {
415
429
  console.error('[useTransactionSigner] JWT transaction signing failed:', error);
416
- setCurrentStatus(SigningStatus.ERROR);
430
+ const SigningStatusEnum = getSigningStatus();
431
+ if (SigningStatusEnum) setCurrentStatus(SigningStatusEnum.ERROR);
417
432
  setStatusMessage(error instanceof Error ? error.message : 'Transaction failed');
418
433
  throw error; // Re-throw to maintain error handling upstream
419
434
  }
@@ -459,7 +474,7 @@ export const useTransactionSigner = (): TransactionSignerHook => {
459
474
 
460
475
  // Create status callback wrapper
461
476
  const statusCallback: StatusCallback = {
462
- onStatusUpdate: (status: SigningStatus, message: string, data?: StatusUpdateData) => {
477
+ onStatusUpdate: (status: SigningStatusType, message: string, data?: StatusUpdateData) => {
463
478
  setCurrentStatus(status);
464
479
  setStatusMessage(message);
465
480
  onStatusUpdate?.(status, message, data);
@@ -472,7 +487,8 @@ export const useTransactionSigner = (): TransactionSignerHook => {
472
487
  return signingResult;
473
488
  } catch (error) {
474
489
  console.error('[useTransactionSigner] Sign-only transaction failed:', error);
475
- setCurrentStatus(SigningStatus.ERROR);
490
+ const SigningStatusEnum = getSigningStatus();
491
+ if (SigningStatusEnum) setCurrentStatus(SigningStatusEnum.ERROR);
476
492
  setStatusMessage(error instanceof Error ? error.message : 'Signing failed');
477
493
  throw error;
478
494
  }
@@ -1,58 +1,74 @@
1
1
  /**
2
2
  * AsyncStorage Token Storage for React Native Mobile Platforms
3
3
  *
4
- * Bundler-agnostic AsyncStorage implementation for mobile platforms
4
+ * Bundler-agnostic AsyncStorage implementation for mobile platforms.
5
+ *
6
+ * IMPORTANT: Due to bundler conflicts between Rollup (SDK) and Metro (app),
7
+ * the consuming app MUST set global.AsyncStorageModule before using this SDK:
8
+ *
9
+ * ```javascript
10
+ * // In your app's index.js, BEFORE importing the SDK:
11
+ * import AsyncStorage from '@react-native-async-storage/async-storage';
12
+ * global.AsyncStorageModule = AsyncStorage;
13
+ * ```
5
14
  */
6
15
 
7
16
  import type { TokenStorage } from '@explorins/pers-sdk/core';
8
17
 
18
+ // Declare global type for TypeScript
19
+ declare global {
20
+ var AsyncStorageModule: any;
21
+ }
22
+
9
23
  /**
10
- * Dynamically resolve AsyncStorage at runtime to avoid bundler conflicts
11
- *
12
- * When the SDK is pre-bundled (e.g., with Rollup) and then consumed by an app
13
- * that uses Metro, the static import can get resolved incorrectly due to module
14
- * hoisting and namespace collisions.
24
+ * Get AsyncStorage from the global that the app must set.
15
25
  *
16
- * By using require() at runtime, we ensure we get the actual AsyncStorage
17
- * from the app's node_modules, not a bundled/mangled version.
26
+ * This bypasses all bundler resolution issues by having the app
27
+ * explicitly provide the AsyncStorage module via a global variable.
18
28
  */
19
29
  function getAsyncStorage(): any {
20
- // Use require() to get the module at runtime
21
- // This bypasses any bundler transformations that might have corrupted the import
30
+ // Check if the app has set the global
31
+ if (global.AsyncStorageModule) {
32
+ const module = global.AsyncStorageModule;
33
+
34
+ // Validate it has the expected methods
35
+ if (typeof module?.getItem === 'function') {
36
+ console.log('[AsyncStorage] Using global.AsyncStorageModule (direct)');
37
+ return module;
38
+ } else if (typeof module?.default?.getItem === 'function') {
39
+ console.log('[AsyncStorage] Using global.AsyncStorageModule.default');
40
+ return module.default;
41
+ }
42
+ }
43
+
44
+ // Fallback: try require (may not work due to bundler conflicts)
22
45
  try {
23
- // Try default export first (Metro pattern)
46
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
24
47
  const module = require('@react-native-async-storage/async-storage');
25
48
 
26
- // Log for debugging what we actually received
27
- const hasGetItem = typeof module?.getItem === 'function';
28
- const hasDefaultGetItem = typeof module?.default?.getItem === 'function';
29
-
30
- console.log('[AsyncStorage] Module resolution:', {
31
- hasGetItem,
32
- hasDefaultGetItem,
33
- moduleType: typeof module,
34
- keys: module ? Object.keys(module).slice(0, 10) : []
35
- });
36
-
37
- if (hasDefaultGetItem) {
49
+ if (typeof module?.default?.getItem === 'function') {
50
+ console.log('[AsyncStorage] Fallback: using require().default');
38
51
  return module.default;
39
- } else if (hasGetItem) {
52
+ } else if (typeof module?.getItem === 'function') {
53
+ console.log('[AsyncStorage] Fallback: using require() direct');
40
54
  return module;
41
- } else {
42
- throw new Error('AsyncStorage module found but missing getItem method');
43
55
  }
44
- } catch (error) {
45
- console.error('[AsyncStorage] Failed to dynamically require:', error);
46
- throw new Error(
47
- 'Failed to load @react-native-async-storage/async-storage. ' +
48
- 'Make sure it is installed and properly linked.'
49
- );
56
+ } catch (e) {
57
+ // Ignore require errors
50
58
  }
59
+
60
+ // If we get here, provide a helpful error
61
+ throw new Error(
62
+ 'AsyncStorage not available. Please add this to your app\'s index.js BEFORE importing the SDK:\n\n' +
63
+ ' import AsyncStorage from \'@react-native-async-storage/async-storage\';\n' +
64
+ ' global.AsyncStorageModule = AsyncStorage;\n\n' +
65
+ 'This is required due to bundler conflicts between Rollup and Metro.'
66
+ );
51
67
  }
52
68
 
53
69
  /**
54
70
  * Bundler-agnostic AsyncStorage wrapper
55
- * Now uses runtime require() to avoid bundler conflicts
71
+ * Uses global injection to avoid bundler conflicts
56
72
  */
57
73
  class BundlerAgnosticAsyncStorage {
58
74
  private storage: any;