@explorins/pers-sdk-react-native 1.5.30 → 1.5.32

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.
Files changed (76) hide show
  1. package/README.md +9 -0
  2. package/dist/hooks/index.d.ts +2 -2
  3. package/dist/hooks/index.d.ts.map +1 -1
  4. package/dist/hooks/index.js +1 -1
  5. package/dist/hooks/useAnalytics.d.ts.map +1 -1
  6. package/dist/hooks/useAnalytics.js +0 -1
  7. package/dist/hooks/useAuth.d.ts +0 -1
  8. package/dist/hooks/useAuth.d.ts.map +1 -1
  9. package/dist/hooks/useAuth.js +5 -18
  10. package/dist/hooks/useBusiness.d.ts.map +1 -1
  11. package/dist/hooks/useBusiness.js +0 -9
  12. package/dist/hooks/useCampaigns.d.ts.map +1 -1
  13. package/dist/hooks/useCampaigns.js +0 -10
  14. package/dist/hooks/useDonations.d.ts.map +1 -1
  15. package/dist/hooks/useDonations.js +0 -1
  16. package/dist/hooks/useFiles.d.ts.map +1 -1
  17. package/dist/hooks/useFiles.js +0 -4
  18. package/dist/hooks/usePurchases.d.ts.map +1 -1
  19. package/dist/hooks/usePurchases.js +0 -3
  20. package/dist/hooks/useRedemptions.d.ts +4 -1
  21. package/dist/hooks/useRedemptions.d.ts.map +1 -1
  22. package/dist/hooks/useRedemptions.js +6 -17
  23. package/dist/hooks/useTenants.d.ts.map +1 -1
  24. package/dist/hooks/useTenants.js +0 -3
  25. package/dist/hooks/useTokens.d.ts.map +1 -1
  26. package/dist/hooks/useTokens.js +0 -6
  27. package/dist/hooks/useTransactionSigner.d.ts +13 -1
  28. package/dist/hooks/useTransactionSigner.d.ts.map +1 -1
  29. package/dist/hooks/useTransactionSigner.js +59 -2
  30. package/dist/hooks/useTransactions.d.ts +4 -1
  31. package/dist/hooks/useTransactions.d.ts.map +1 -1
  32. package/dist/hooks/useTransactions.js +9 -10
  33. package/dist/hooks/useUserStatus.d.ts.map +1 -1
  34. package/dist/hooks/useUserStatus.js +0 -3
  35. package/dist/hooks/useUsers.d.ts.map +1 -1
  36. package/dist/hooks/useUsers.js +0 -7
  37. package/dist/hooks/useWeb3.d.ts +26 -42
  38. package/dist/hooks/useWeb3.d.ts.map +1 -1
  39. package/dist/hooks/useWeb3.js +27 -53
  40. package/dist/index.d.ts +2 -1
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +330 -304
  43. package/dist/index.js.map +1 -1
  44. package/dist/providers/PersSDKProvider.d.ts +1 -3
  45. package/dist/providers/PersSDKProvider.d.ts.map +1 -1
  46. package/dist/providers/PersSDKProvider.js +14 -11
  47. package/dist/providers/react-native-auth-provider.d.ts.map +1 -1
  48. package/dist/providers/react-native-auth-provider.js +4 -0
  49. package/dist/providers/rn-dpop-provider.d.ts +2 -4
  50. package/dist/providers/rn-dpop-provider.d.ts.map +1 -1
  51. package/dist/providers/rn-dpop-provider.js +50 -23
  52. package/dist/storage/rn-secure-storage.d.ts +1 -0
  53. package/dist/storage/rn-secure-storage.d.ts.map +1 -1
  54. package/dist/storage/rn-secure-storage.js +9 -12
  55. package/package.json +2 -2
  56. package/src/hooks/index.ts +10 -2
  57. package/src/hooks/useAnalytics.ts +0 -1
  58. package/src/hooks/useAuth.ts +4 -25
  59. package/src/hooks/useBusiness.ts +0 -9
  60. package/src/hooks/useCampaigns.ts +0 -10
  61. package/src/hooks/useDonations.ts +0 -1
  62. package/src/hooks/useFiles.ts +0 -4
  63. package/src/hooks/usePurchases.ts +0 -3
  64. package/src/hooks/useRedemptions.ts +7 -21
  65. package/src/hooks/useTenants.ts +0 -3
  66. package/src/hooks/useTokens.ts +0 -6
  67. package/src/hooks/useTransactionSigner.ts +74 -4
  68. package/src/hooks/useTransactions.ts +10 -12
  69. package/src/hooks/useUserStatus.ts +0 -3
  70. package/src/hooks/useUsers.ts +0 -7
  71. package/src/hooks/useWeb3.ts +28 -68
  72. package/src/index.ts +4 -0
  73. package/src/providers/PersSDKProvider.tsx +19 -20
  74. package/src/providers/react-native-auth-provider.ts +5 -0
  75. package/src/providers/rn-dpop-provider.ts +85 -45
  76. package/src/storage/rn-secure-storage.ts +13 -13
@@ -16,14 +16,12 @@ export interface PersSDKContext {
16
16
  tenants: TenantManager | null;
17
17
  analytics: AnalyticsManager | null;
18
18
  donations: DonationManager | null;
19
- business: BusinessManager | null;
20
19
  authProvider: DefaultAuthProvider | null;
21
20
  isInitialized: boolean;
22
21
  isAuthenticated: boolean;
23
22
  user: UserDTO | AdminDTO | null;
24
- accountAddress: string | null;
25
23
  initialize: (config: PersConfig) => Promise<void>;
26
- setAuthenticationState: (user: UserDTO | AdminDTO | null, accountAddress: string | null, isAuthenticated: boolean) => void;
24
+ setAuthenticationState: (user: UserDTO | AdminDTO | null, isAuthenticated: boolean) => void;
27
25
  refreshUserData: () => Promise<void>;
28
26
  }
29
27
  export declare const PersSDKProvider: React.FC<{
@@ -1 +1 @@
1
- {"version":3,"file":"PersSDKProvider.d.ts","sourceRoot":"","sources":["../../src/providers/PersSDKProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAuC,SAAS,EAAkC,MAAM,OAAO,CAAC;AAE9G,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAsB,MAAM,0BAA0B,CAAC;AAIxG,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAG3D,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAGlC,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,MAAM,WAAW,cAAc;IAE7B,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IAGpB,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACtC,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACxC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAGlC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IAGjC,YAAY,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAGzC,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAG9B,UAAU,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,sBAAsB,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,eAAe,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3H,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAMD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,CA4IA,CAAC;AAGF,eAAO,MAAM,UAAU,QAAO,cAQ7B,CAAC"}
1
+ {"version":3,"file":"PersSDKProvider.d.ts","sourceRoot":"","sources":["../../src/providers/PersSDKProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAuC,SAAS,EAA2C,MAAM,OAAO,CAAC;AAEvH,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAIpF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAG3D,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAGlC,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,MAAM,WAAW,cAAc;IAE7B,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IAGpB,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACtC,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACxC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAGlC,YAAY,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAGzC,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC;IAGhC,UAAU,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,sBAAsB,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,EAAE,eAAe,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5F,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAMD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,CA+IA,CAAC;AAGF,eAAO,MAAM,UAAU,QAAO,cAQ7B,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { createContext, useContext, useState, useCallback, useRef, useEffect } from 'react';
2
+ import { createContext, useContext, useState, useCallback, useRef, useEffect, useMemo } from 'react';
3
3
  import { Platform } from 'react-native';
4
4
  import { PersSDK } from '@explorins/pers-sdk/core';
5
5
  import { ReactNativeHttpClient } from './react-native-http-client';
@@ -15,7 +15,6 @@ export const PersSDKProvider = ({ children, config }) => {
15
15
  const [isInitialized, setIsInitialized] = useState(false);
16
16
  const [isAuthenticated, setIsAuthenticated] = useState(false);
17
17
  const [user, setUser] = useState(null);
18
- const [accountAddress, setAccountAddress] = useState(null);
19
18
  const initialize = useCallback(async (config) => {
20
19
  // Prevent multiple initializations
21
20
  if (isInitialized || initializingRef.current) {
@@ -25,8 +24,7 @@ export const PersSDKProvider = ({ children, config }) => {
25
24
  try {
26
25
  // Create HTTP client
27
26
  const httpClient = new ReactNativeHttpClient();
28
- // Ensure DPoP is enabled by default for all platforms
29
- const dpopConfig = config.dpop || {};
27
+ const dpopConfig = config.dpop ?? {};
30
28
  const isDpopEnabled = dpopConfig.enabled ?? true;
31
29
  // Prepare DPoP settings for Auth Provider
32
30
  const dpopSettings = {
@@ -78,9 +76,8 @@ export const PersSDKProvider = ({ children, config }) => {
78
76
  });
79
77
  }
80
78
  }, [config, isInitialized, initialize]);
81
- const setAuthenticationState = useCallback((user, accountAddress, isAuthenticated) => {
79
+ const setAuthenticationState = useCallback((user, isAuthenticated) => {
82
80
  setUser(user);
83
- setAccountAddress(accountAddress);
84
81
  setIsAuthenticated(isAuthenticated);
85
82
  }, []);
86
83
  const refreshUserData = useCallback(async () => {
@@ -96,7 +93,7 @@ export const PersSDKProvider = ({ children, config }) => {
96
93
  throw error;
97
94
  }
98
95
  }, [sdk, isAuthenticated, isInitialized]);
99
- const contextValue = {
96
+ const contextValue = useMemo(() => ({
100
97
  // Main SDK instance
101
98
  sdk,
102
99
  // Manager shortcuts for convenience
@@ -111,20 +108,26 @@ export const PersSDKProvider = ({ children, config }) => {
111
108
  tenants: sdk?.tenants || null,
112
109
  analytics: sdk?.analytics || null,
113
110
  donations: sdk?.donations || null,
114
- // Legacy support (deprecated but kept for backward compatibility)
115
- business: sdk?.businesses || null,
116
111
  // Platform-specific providers
117
112
  authProvider,
118
113
  // State
119
114
  isInitialized,
120
115
  isAuthenticated,
121
116
  user,
122
- accountAddress,
123
117
  // Methods
124
118
  initialize,
125
119
  setAuthenticationState,
126
120
  refreshUserData,
127
- };
121
+ }), [
122
+ sdk,
123
+ authProvider,
124
+ isInitialized,
125
+ isAuthenticated,
126
+ user,
127
+ initialize,
128
+ setAuthenticationState,
129
+ refreshUserData
130
+ ]);
128
131
  return (_jsx(SDKContext.Provider, { value: contextValue, children: children }));
129
132
  };
130
133
  // Custom hook to use the SDK context
@@ -1 +1 @@
1
- {"version":3,"file":"react-native-auth-provider.d.ts","sourceRoot":"","sources":["../../src/providers/react-native-auth-provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,mBAAmB,EAAW,QAAQ,EAA4B,MAAM,0BAA0B,CAAC;AAG5G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAK7D;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0CAA0C;IAC1C,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,oCAAoC;IACpC,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,cAAc,CAAC,EAAE,OAAO,0BAA0B,EAAE,kBAAkB,CAAC;KACxE,CAAC;CACH;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,qBAA0B,GACjC,mBAAmB,CAiCrB"}
1
+ {"version":3,"file":"react-native-auth-provider.d.ts","sourceRoot":"","sources":["../../src/providers/react-native-auth-provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,mBAAmB,EAAW,QAAQ,EAA4B,MAAM,0BAA0B,CAAC;AAG5G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAK7D;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0CAA0C;IAC1C,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,oCAAoC;IACpC,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,cAAc,CAAC,EAAE,OAAO,0BAA0B,EAAE,kBAAkB,CAAC;KACxE,CAAC;CACH;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,qBAA0B,GACjC,mBAAmB,CAsCrB"}
@@ -35,6 +35,10 @@ export function createReactNativeAuthProvider(projectKey, config = {}) {
35
35
  enabled: dpop.enabled ?? true,
36
36
  cryptoProvider: dpop.cryptoProvider
37
37
  } : undefined;
38
+ // DEBUG LOGGING
39
+ if (debug) {
40
+ console.log('[ReactNativeAuthProvider] Creating provider with DPoP config:', JSON.stringify(dpopConfig));
41
+ }
38
42
  // Return DefaultAuthProvider configured with platform-appropriate storage
39
43
  return new DefaultAuthProvider({
40
44
  authType,
@@ -3,10 +3,8 @@ export declare class ReactNativeDPoPProvider implements DPoPCryptoProvider {
3
3
  /**
4
4
  * Generates a new key pair (ES256 recommended)
5
5
  *
6
- * Note: options.extractable is ignored because for React Native Keychain storage,
7
- * we MUST export the keys as JWK/strings. We rely on the Keychain encryption
8
- * for security at rest (High Security), making the key "Extractable" in memory
9
- * but protected by hardware encryption when stored.
6
+ * Uses WebCrypto API (crypto.subtle) for cross-platform compatibility.
7
+ * Falls back to Node.js crypto API on iOS if needed.
10
8
  */
11
9
  generateKeyPair(options?: {
12
10
  extractable?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"rn-dpop-provider.d.ts","sourceRoot":"","sources":["../../src/providers/rn-dpop-provider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAkB3E,qBAAa,uBAAwB,YAAW,kBAAkB;IAChE;;;;;;;OAOG;IACG,eAAe,CAAC,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAoB1E,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAmC9E,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO3D,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,eAAe;CAQxB"}
1
+ {"version":3,"file":"rn-dpop-provider.d.ts","sourceRoot":"","sources":["../../src/providers/rn-dpop-provider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAiB3E,qBAAa,uBAAwB,YAAW,kBAAkB;IAChE;;;;;OAKG;IACG,eAAe,CAAC,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAqC1E,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAqD9E,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgB3D,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,eAAe;CAOxB"}
@@ -12,7 +12,6 @@ if (Platform.OS !== 'web') {
12
12
  }
13
13
  else {
14
14
  // on Web, we shouldn't be using this provider anyway (Core SDK has WebDPoPProvider)
15
- // But to be safe, we can mock or throw
16
15
  crypto = {
17
16
  generateKeyPair: () => { throw new Error('ReactNativeDPoPProvider not supported on Web'); }
18
17
  };
@@ -21,26 +20,39 @@ export class ReactNativeDPoPProvider {
21
20
  /**
22
21
  * Generates a new key pair (ES256 recommended)
23
22
  *
24
- * Note: options.extractable is ignored because for React Native Keychain storage,
25
- * we MUST export the keys as JWK/strings. We rely on the Keychain encryption
26
- * for security at rest (High Security), making the key "Extractable" in memory
27
- * but protected by hardware encryption when stored.
23
+ * Uses WebCrypto API (crypto.subtle) for cross-platform compatibility.
24
+ * Falls back to Node.js crypto API on iOS if needed.
28
25
  */
29
26
  async generateKeyPair(options) {
30
- // Generate P-256 Key Pair
27
+ // Try WebCrypto API first (works on both iOS and Android)
28
+ if (crypto.subtle) {
29
+ try {
30
+ const keyPair = await crypto.subtle.generateKey({ name: 'ECDSA', namedCurve: 'P-256' }, true, // extractable - required for JWK export
31
+ ['sign', 'verify']);
32
+ const publicKeyJwk = await crypto.subtle.exportKey('jwk', keyPair.publicKey);
33
+ const privateKeyJwk = await crypto.subtle.exportKey('jwk', keyPair.privateKey);
34
+ return {
35
+ publicKey: publicKeyJwk,
36
+ privateKey: privateKeyJwk
37
+ };
38
+ }
39
+ catch (err) {
40
+ console.warn('[DPoP] WebCrypto API failed, trying Node.js crypto API', err);
41
+ }
42
+ }
43
+ // Fallback: Node.js crypto API (works on iOS)
31
44
  return new Promise((resolve, reject) => {
32
45
  crypto.generateKeyPair('ec', { namedCurve: 'P-256' }, (err, publicKey, privateKey) => {
33
46
  if (err)
34
47
  return reject(err);
35
- // Export to JWK for SDK Compatibility
36
- // We use 'export' because supportsObjects=false in our storage forces the SDK
37
- // to expect serializable keys.
38
- const pubJwk = publicKey.export({ format: 'jwk' });
39
- const privJwk = privateKey.export({ format: 'jwk' });
40
- resolve({
41
- publicKey: pubJwk,
42
- privateKey: privJwk
43
- });
48
+ try {
49
+ const pJwk = publicKey.export({ format: 'jwk' });
50
+ const prJwk = privateKey.export({ format: 'jwk' });
51
+ resolve({ publicKey: pJwk, privateKey: prJwk });
52
+ }
53
+ catch (exportErr) {
54
+ reject(exportErr);
55
+ }
44
56
  });
45
57
  });
46
58
  }
@@ -61,21 +73,37 @@ export class ReactNativeDPoPProvider {
61
73
  const b64Header = this.base64Url(JSON.stringify(header));
62
74
  const b64Payload = this.base64Url(JSON.stringify(finalPayload));
63
75
  const signingInput = `${b64Header}.${b64Payload}`;
64
- // 4. Sign
76
+ // 4. Sign - try WebCrypto first, fallback to Node.js crypto
77
+ if (crypto.subtle) {
78
+ try {
79
+ const privateKey = await crypto.subtle.importKey('jwk', keyPair.privateKey, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['sign']);
80
+ const signatureBuffer = await crypto.subtle.sign({ name: 'ECDSA', hash: 'SHA-256' }, privateKey, Buffer.from(signingInput));
81
+ // WebCrypto returns signature in IEEE P1363 format (r || s), which is what we need for JWT
82
+ return `${signingInput}.${this.base64UrlBuffer(Buffer.from(signatureBuffer))}`;
83
+ }
84
+ catch (err) {
85
+ console.warn('[DPoP] WebCrypto sign failed, trying Node.js crypto', err);
86
+ }
87
+ }
88
+ // Fallback: Node.js crypto API
65
89
  const sign = crypto.createSign('SHA256');
66
90
  sign.update(signingInput);
67
- // sign.end() is not required/available in quick-crypto as it doesn't strictly follow stream interface
68
- // Import private key back from JWK to sign
69
- // The keyPair.privateKey is a JsonWebKey object because we exported it earlier.
70
- // quick-crypto createPrivateKey expects jwk object if format is jwk
71
91
  const privateKeyObj = crypto.createPrivateKey({ key: keyPair.privateKey, format: 'jwk' });
72
92
  const signature = sign.sign(privateKeyObj);
73
- // signature is a Buffer in quick-crypto
74
93
  return `${signingInput}.${this.base64UrlBuffer(signature)}`;
75
94
  }
76
95
  async hashAccessToken(accessToken) {
96
+ // Try WebCrypto first
97
+ if (crypto.subtle) {
98
+ try {
99
+ const hashBuffer = await crypto.subtle.digest('SHA-256', Buffer.from(accessToken));
100
+ return this.base64UrlBuffer(Buffer.from(hashBuffer));
101
+ }
102
+ catch (err) {
103
+ // Fallback to Node.js crypto
104
+ }
105
+ }
77
106
  const hash = crypto.createHash('sha256').update(accessToken).digest();
78
- // digest returns Buffer in quick-crypto
79
107
  return this.base64UrlBuffer(hash);
80
108
  }
81
109
  // --- Helpers ---
@@ -83,7 +111,6 @@ export class ReactNativeDPoPProvider {
83
111
  return this.base64UrlBuffer(Buffer.from(str));
84
112
  }
85
113
  base64UrlBuffer(buf) {
86
- // Ensure we have a Buffer
87
114
  const buffer = Buffer.isBuffer(buf) ? buf : Buffer.from(buf);
88
115
  return buffer.toString('base64')
89
116
  .replace(/=/g, '')
@@ -7,6 +7,7 @@ export declare class ReactNativeSecureStorage implements TokenStorage {
7
7
  private keyPrefix;
8
8
  readonly supportsObjects = false;
9
9
  private readonly SECURE_KEYS;
10
+ private fallbackStorage;
10
11
  constructor(keyPrefix?: string);
11
12
  set(key: string, value: unknown): Promise<void>;
12
13
  get(key: string): Promise<unknown | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"rn-secure-storage.d.ts","sourceRoot":"","sources":["../../src/storage/rn-secure-storage.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,YAAY,EAGb,MAAM,0BAA0B,CAAC;AAYlC;;;GAGG;AACH,qBAAa,wBAAyB,YAAW,YAAY;IAY/C,OAAO,CAAC,SAAS;IAV7B,QAAQ,CAAC,eAAe,SAAS;IAGjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAKzB;gBAEiB,SAAS,GAAE,MAAuB;IAEhD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B/C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAkCzC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB5B,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,QAAQ;CAOjB"}
1
+ {"version":3,"file":"rn-secure-storage.d.ts","sourceRoot":"","sources":["../../src/storage/rn-secure-storage.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,EAGb,MAAM,0BAA0B,CAAC;AAalC;;;GAGG;AACH,qBAAa,wBAAyB,YAAW,YAAY;IAc/C,OAAO,CAAC,SAAS;IAZ7B,QAAQ,CAAC,eAAe,SAAS;IAGjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAKzB;IAEH,OAAO,CAAC,eAAe,CAA2B;gBAE9B,SAAS,GAAE,MAAuB;IAIhD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B/C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAkCzC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB5B,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,QAAQ;CAOjB"}
@@ -1,6 +1,6 @@
1
1
  import { Platform } from 'react-native';
2
- import AsyncStorage from '@react-native-async-storage/async-storage';
3
2
  import { DPOP_STORAGE_KEYS, AUTH_STORAGE_KEYS } from '@explorins/pers-sdk/core';
3
+ import { AsyncStorageTokenStorage } from './async-storage-token-storage';
4
4
  // Conditionally require Keychain to avoid Web bundler errors
5
5
  let Keychain;
6
6
  if (Platform.OS !== 'web') {
@@ -27,6 +27,7 @@ export class ReactNativeSecureStorage {
27
27
  AUTH_STORAGE_KEYS.REFRESH_TOKEN,
28
28
  AUTH_STORAGE_KEYS.PROVIDER_TOKEN
29
29
  ]);
30
+ this.fallbackStorage = new AsyncStorageTokenStorage(keyPrefix);
30
31
  }
31
32
  async set(key, value) {
32
33
  const prefixedKey = this.getKeyName(key);
@@ -47,12 +48,12 @@ export class ReactNativeSecureStorage {
47
48
  catch (e) {
48
49
  console.warn(`[ReactNativeSecureStorage] Keychain set failed for ${key}, falling back to AsyncStorage`, e);
49
50
  // Fallback to AsyncStorage if Keychain fails
50
- await AsyncStorage.setItem(prefixedKey, stringValue);
51
+ await this.fallbackStorage.set(key, stringValue);
51
52
  }
52
53
  }
53
54
  else {
54
55
  // Store standard config/metadata in AsyncStorage
55
- await AsyncStorage.setItem(prefixedKey, stringValue);
56
+ await this.fallbackStorage.set(key, stringValue);
56
57
  }
57
58
  }
58
59
  async get(key) {
@@ -72,7 +73,7 @@ export class ReactNativeSecureStorage {
72
73
  }
73
74
  // Fallback: Check AsyncStorage if not found in Keychain or Keychain failed
74
75
  try {
75
- const val = await AsyncStorage.getItem(prefixedKey);
76
+ const val = await this.fallbackStorage.get(key);
76
77
  return val ? this.tryParse(val) : null;
77
78
  }
78
79
  catch (e) {
@@ -81,7 +82,7 @@ export class ReactNativeSecureStorage {
81
82
  }
82
83
  else {
83
84
  try {
84
- const val = await AsyncStorage.getItem(prefixedKey);
85
+ const val = await this.fallbackStorage.get(key);
85
86
  return val ? this.tryParse(val) : null;
86
87
  }
87
88
  catch (e) {
@@ -102,10 +103,10 @@ export class ReactNativeSecureStorage {
102
103
  console.warn(`[ReactNativeSecureStorage] Failed to reset keychain for ${key}`, e);
103
104
  }
104
105
  // Always remove from fallback storage too, just in case
105
- await AsyncStorage.removeItem(prefixedKey);
106
+ await this.fallbackStorage.remove(key);
106
107
  }
107
108
  else {
108
- await AsyncStorage.removeItem(prefixedKey);
109
+ await this.fallbackStorage.remove(key);
109
110
  }
110
111
  }
111
112
  async clear() {
@@ -122,11 +123,7 @@ export class ReactNativeSecureStorage {
122
123
  }
123
124
  // Clear AsyncStorage keys related to PERS
124
125
  try {
125
- const allKeys = await AsyncStorage.getAllKeys();
126
- const ourKeys = allKeys.filter(k => k.startsWith(this.keyPrefix));
127
- if (ourKeys.length > 0) {
128
- await AsyncStorage.multiRemove(ourKeys);
129
- }
126
+ await this.fallbackStorage.clear();
130
127
  }
131
128
  catch (e) {
132
129
  console.warn('[ReactNativeSecureStorage] Failed to clear AsyncStorage', e);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@explorins/pers-sdk-react-native",
3
- "version": "1.5.30",
3
+ "version": "1.5.32",
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",
@@ -39,7 +39,7 @@
39
39
  "dependencies": {
40
40
  "@explorins/pers-sdk": "^1.6.36",
41
41
  "@explorins/pers-shared": "^2.1.52",
42
- "@explorins/pers-signer": "^1.0.32",
42
+ "@explorins/pers-signer": "^1.0.33",
43
43
  "@explorins/web3-ts": "^0.3.75",
44
44
  "buffer": "^6.0.3",
45
45
  "ethers": "^6.15.0",
@@ -2,7 +2,7 @@
2
2
  export { useAuth } from './useAuth';
3
3
  export { useTokens } from './useTokens';
4
4
  export { useTransactions } from './useTransactions';
5
- export { useTransactionSigner } from './useTransactionSigner';
5
+ export { useTransactionSigner, SigningStatus } from './useTransactionSigner';
6
6
  export { useBusiness } from './useBusiness';
7
7
  export { useCampaigns } from './useCampaigns';
8
8
  export { useRedemptions } from './useRedemptions';
@@ -17,4 +17,12 @@ export { useDonations } from './useDonations';
17
17
 
18
18
  // Re-export auth-related types for convenience
19
19
  export type { RawUserData } from './useAuth';
20
- export type { TransactionSignerHook, SubmissionResult, AuthenticatedUser, TransactionSigningResult } from './useTransactionSigner';
20
+ export type {
21
+ TransactionSignerHook,
22
+ SubmissionResult,
23
+ AuthenticatedUser,
24
+ TransactionSigningResult,
25
+ StatusUpdateData,
26
+ OnStatusUpdateFn,
27
+ SigningStatus as SigningStatusType
28
+ } from './useTransactionSigner';
@@ -65,7 +65,6 @@ export const useAnalytics = () => {
65
65
 
66
66
  try {
67
67
  const result = await sdk.analytics.getTransactionAnalytics(request);
68
- console.log('Transaction analytics fetched successfully:', result);
69
68
  return result;
70
69
  } catch (error) {
71
70
  console.error('Failed to fetch transaction analytics:', error);
@@ -50,7 +50,6 @@ export const useAuth = () => {
50
50
  isInitialized,
51
51
  isAuthenticated,
52
52
  user,
53
- accountAddress,
54
53
  setAuthenticationState,
55
54
  refreshUserData
56
55
  } = usePersSDK();
@@ -76,8 +75,6 @@ export const useAuth = () => {
76
75
  }
77
76
 
78
77
  try {
79
- console.log(`Logging in as ${userType}...`);
80
-
81
78
  // Set token in auth provider
82
79
  await authProvider.setAccessToken(jwtToken);
83
80
 
@@ -87,13 +84,8 @@ export const useAuth = () => {
87
84
  const userData = result.user || result.admin;
88
85
 
89
86
  if (userData) {
90
- const userAccountAddress = ('accountAddress' in userData && userData.accountAddress) ||
91
- ('wallets' in userData && userData.wallets?.[0]?.address) ||
92
- null;
93
-
94
- setAuthenticationState(userData, userAccountAddress as string | null, true);
87
+ setAuthenticationState(userData, true);
95
88
 
96
- console.log('Login successful');
97
89
  return result;
98
90
  } else {
99
91
  throw new Error('No user data returned from login');
@@ -122,8 +114,6 @@ export const useAuth = () => {
122
114
  }
123
115
 
124
116
  try {
125
- console.log('Logging in with raw user data...');
126
-
127
117
  // Use the raw data login from the auth manager
128
118
  const result = await sdk.auth.loginWithRawData(rawUserData);
129
119
 
@@ -135,13 +125,7 @@ export const useAuth = () => {
135
125
  const userData = result.user;
136
126
 
137
127
  if (userData) {
138
- const userAccountAddress = userData.accountAddress ||
139
- (userData as UserDTO & { wallets?: Array<{ address: string }> })?.wallets?.[0]?.address ||
140
- null;
141
-
142
- setAuthenticationState(userData, userAccountAddress, true);
143
-
144
- console.log('Raw data login successful');
128
+ setAuthenticationState(userData, true);
145
129
  } else {
146
130
  throw new Error('No user data returned from raw data login');
147
131
  }
@@ -165,15 +149,11 @@ export const useAuth = () => {
165
149
  */
166
150
  const logout = useCallback(async (): Promise<void> => {
167
151
  try {
168
- console.log('Logging out...');
169
-
170
152
  if (authProvider) {
171
153
  await authProvider.clearTokens();
172
154
  }
173
155
 
174
- setAuthenticationState(null, null, false);
175
-
176
- console.log('Logout successful');
156
+ setAuthenticationState(null, false);
177
157
  } catch (error) {
178
158
  console.error('Logout failed:', error);
179
159
  throw error;
@@ -257,7 +237,7 @@ export const useAuth = () => {
257
237
  throw new Error('SDK not initialized. Call initialize() first.');
258
238
  }
259
239
  await sdk.auth.clearAuth();
260
- setAuthenticationState(null, null, false);
240
+ setAuthenticationState(null, false);
261
241
  }, [sdk, setAuthenticationState]);
262
242
 
263
243
  /**
@@ -284,7 +264,6 @@ export const useAuth = () => {
284
264
  isInitialized,
285
265
  isAuthenticated,
286
266
  user,
287
- accountAddress,
288
267
 
289
268
  // Methods
290
269
  login,
@@ -59,7 +59,6 @@ export const useBusiness = () => {
59
59
 
60
60
  try {
61
61
  const result = await sdk.businesses.getActiveBusinesses();
62
- console.log('Active businesses fetched successfully:', result);
63
62
  return result;
64
63
  } catch (error) {
65
64
  console.error('Failed to fetch active businesses:', error);
@@ -87,7 +86,6 @@ export const useBusiness = () => {
87
86
 
88
87
  try {
89
88
  const result = await sdk.businesses.getBusinessTypes();
90
- console.log('Business types fetched successfully:', result);
91
89
  return result;
92
90
  } catch (error) {
93
91
  console.error('Failed to fetch business types:', error);
@@ -102,7 +100,6 @@ export const useBusiness = () => {
102
100
 
103
101
  try {
104
102
  const result = await sdk.businesses.getBusinessById(businessId);
105
- console.log('Business fetched successfully:', result);
106
103
  return result;
107
104
  } catch (error) {
108
105
  console.error('Failed to fetch business:', error);
@@ -117,7 +114,6 @@ export const useBusiness = () => {
117
114
 
118
115
  try {
119
116
  const result = await sdk.businesses.getBusinesses();
120
- console.log('All businesses fetched successfully:', result);
121
117
  return result;
122
118
  } catch (error) {
123
119
  console.error('Failed to fetch all businesses:', error);
@@ -132,7 +128,6 @@ export const useBusiness = () => {
132
128
 
133
129
  try {
134
130
  const result = await sdk.businesses.getBusinessByAccount(accountAddress);
135
- console.log('Business by account fetched successfully:', result);
136
131
  return result;
137
132
  } catch (error) {
138
133
  console.error('Failed to fetch business by account:', error);
@@ -147,7 +142,6 @@ export const useBusiness = () => {
147
142
 
148
143
  try {
149
144
  const result = await sdk.businesses.getBusinessesByType(typeId);
150
- console.log('Businesses by type fetched successfully:', result);
151
145
  return result;
152
146
  } catch (error) {
153
147
  console.error('Failed to fetch businesses by type:', error);
@@ -177,7 +171,6 @@ export const useBusiness = () => {
177
171
 
178
172
  try {
179
173
  const result = await sdk.businesses.createBusiness(displayName);
180
- console.log('Business created successfully:', result);
181
174
  return result;
182
175
  } catch (error) {
183
176
  console.error('Failed to create business:', error);
@@ -192,7 +185,6 @@ export const useBusiness = () => {
192
185
 
193
186
  try {
194
187
  const result = await sdk.businesses.updateBusiness(businessId, businessData);
195
- console.log('Business updated successfully:', result);
196
188
  return result;
197
189
  } catch (error) {
198
190
  console.error('Failed to update business:', error);
@@ -207,7 +199,6 @@ export const useBusiness = () => {
207
199
 
208
200
  try {
209
201
  const result = await sdk.businesses.toggleBusinessStatus(businessId, toggleData);
210
- console.log('Business status toggled successfully:', result);
211
202
  return result;
212
203
  } catch (error) {
213
204
  console.error('Failed to toggle business status:', error);
@@ -20,7 +20,6 @@ export const useCampaigns = () => {
20
20
 
21
21
  try {
22
22
  const result = await sdk.campaigns.getActiveCampaigns();
23
- console.log('Active campaigns fetched successfully:', result);
24
23
  return result;
25
24
  } catch (error) {
26
25
  console.error('Failed to fetch active campaigns:', error);
@@ -35,7 +34,6 @@ export const useCampaigns = () => {
35
34
 
36
35
  try {
37
36
  const result = await sdk.campaigns.getCampaignById(campaignId);
38
- console.log('Campaign fetched successfully:', result);
39
37
  return result;
40
38
  } catch (error) {
41
39
  console.error('Failed to fetch campaign:', error);
@@ -52,9 +50,7 @@ export const useCampaigns = () => {
52
50
  }
53
51
 
54
52
  try {
55
- console.log('Claiming campaign with request:', request);
56
53
  const result = await sdk.campaigns.claimCampaign(request);
57
- console.log('Campaign claimed successfully:', result);
58
54
  return result;
59
55
  } catch (error) {
60
56
  console.error('Failed to claim campaign:', error);
@@ -73,7 +69,6 @@ export const useCampaigns = () => {
73
69
 
74
70
  try {
75
71
  const result = await sdk.campaigns.getUserClaims();
76
- console.log('User claims fetched successfully:', result);
77
72
  return result;
78
73
  } catch (error) {
79
74
  console.error('Failed to fetch user claims:', error);
@@ -88,7 +83,6 @@ export const useCampaigns = () => {
88
83
 
89
84
  try {
90
85
  const result = await sdk.campaigns.getCampaignTriggers();
91
- console.log('Campaign triggers fetched successfully:', result);
92
86
  return result;
93
87
  } catch (error) {
94
88
  console.error('Failed to fetch campaign triggers:', error);
@@ -104,7 +98,6 @@ export const useCampaigns = () => {
104
98
 
105
99
  try {
106
100
  const result = await sdk.campaigns.getAllCampaigns(active);
107
- console.log('All campaigns fetched successfully:', result);
108
101
  return result;
109
102
  } catch (error) {
110
103
  console.error('Failed to fetch all campaigns:', error);
@@ -119,7 +112,6 @@ export const useCampaigns = () => {
119
112
 
120
113
  try {
121
114
  const result = await sdk.campaigns.getCampaignClaims();
122
- console.log('Campaign claims fetched successfully:', result);
123
115
  return result;
124
116
  } catch (error) {
125
117
  console.error('Failed to fetch campaign claims:', error);
@@ -134,7 +126,6 @@ export const useCampaigns = () => {
134
126
 
135
127
  try {
136
128
  const result = await sdk.campaigns.getCampaignClaimsByUserId(userId);
137
- console.log('Campaign claims by user ID fetched successfully:', result);
138
129
  return result;
139
130
  } catch (error) {
140
131
  console.error('Failed to fetch campaign claims by user ID:', error);
@@ -149,7 +140,6 @@ export const useCampaigns = () => {
149
140
 
150
141
  try {
151
142
  const result = await sdk.campaigns.getCampaignClaimsByBusinessId(businessId);
152
- console.log('Campaign claims by business ID fetched successfully:', result);
153
143
  return result;
154
144
  } catch (error) {
155
145
  console.error('Failed to fetch campaign claims by business ID:', error);
@@ -51,7 +51,6 @@ export const useDonations = () => {
51
51
 
52
52
  try {
53
53
  const result = await sdk.donations.getDonationTypes();
54
- console.log('Donation types fetched successfully:', result);
55
54
  return result;
56
55
  } catch (error) {
57
56
  console.error('Failed to fetch donation types:', error);