@explorins/pers-sdk-react-native 2.3.7 → 2.3.8

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 (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1266 -1244
  3. package/dist/__tests__/PersSDKProvider.test.js +33 -0
  4. package/dist/hooks/useBusiness.d.ts +2 -2
  5. package/dist/hooks/useBusiness.d.ts.map +1 -1
  6. package/dist/hooks/useBusiness.js +2 -2
  7. package/dist/hooks/useIPFSUrl.d.ts +3 -3
  8. package/dist/hooks/useIPFSUrl.d.ts.map +1 -1
  9. package/dist/hooks/useIPFSUrl.js +7 -7
  10. package/dist/hooks/useWeb3.js +4 -4
  11. package/dist/index.js +2400 -487
  12. package/dist/index.js.map +1 -1
  13. package/dist/providers/PersSDKProvider.d.ts +4 -0
  14. package/dist/providers/PersSDKProvider.d.ts.map +1 -1
  15. package/dist/providers/PersSDKProvider.js +14 -0
  16. package/dist/providers/react-native-http-client.d.ts +2 -0
  17. package/dist/providers/react-native-http-client.d.ts.map +1 -1
  18. package/dist/providers/react-native-http-client.js +5 -2
  19. package/dist/storage/rn-secure-storage.d.ts.map +1 -1
  20. package/dist/storage/rn-secure-storage.js +21 -8
  21. package/package.json +3 -3
  22. package/src/__tests__/PersSDKProvider.test.tsx +484 -420
  23. package/src/__tests__/setup.ts +40 -40
  24. package/src/hooks/index.ts +60 -60
  25. package/src/hooks/useAnalytics.ts +327 -327
  26. package/src/hooks/useAuth.ts +265 -265
  27. package/src/hooks/useBookings.ts +191 -191
  28. package/src/hooks/useBusiness.ts +251 -251
  29. package/src/hooks/useCampaigns.ts +500 -500
  30. package/src/hooks/useDonations.ts +66 -66
  31. package/src/hooks/useEvents.ts +372 -372
  32. package/src/hooks/useFiles.ts +155 -155
  33. package/src/hooks/useIPFSUrl.ts +192 -192
  34. package/src/hooks/usePurchases.ts +65 -65
  35. package/src/hooks/useRedemptions.ts +467 -467
  36. package/src/hooks/useTenants.ts +72 -72
  37. package/src/hooks/useTokenBalances.ts +385 -385
  38. package/src/hooks/useTokens.ts +313 -313
  39. package/src/hooks/useTransactionSigner.ts +611 -611
  40. package/src/hooks/useTransactions.ts +299 -299
  41. package/src/hooks/useTriggerSources.ts +301 -301
  42. package/src/hooks/useUserStatus.ts +61 -61
  43. package/src/hooks/useUsers.ts +167 -167
  44. package/src/hooks/useWeb3.ts +355 -355
  45. package/src/index.ts +777 -777
  46. package/src/polyfills/index.ts +160 -160
  47. package/src/polyfills/web3-polyfills.ts +97 -97
  48. package/src/providers/PersSDKProvider.tsx +393 -374
  49. package/src/providers/react-native-auth-provider.ts +110 -110
  50. package/src/providers/react-native-http-client.ts +150 -145
  51. package/src/providers/rn-dpop-provider.ts +190 -190
  52. package/src/storage/async-storage-token-storage.ts +185 -185
  53. package/src/storage/rn-secure-storage.ts +182 -170
  54. package/src/types/react-native-globals.d.ts +45 -45
  55. package/src/utils/index.ts +8 -8
  56. package/src/utils/platform-detection.ts +86 -86
  57. package/dist/index-CzLxqePZ.js +0 -7717
  58. package/dist/index-CzLxqePZ.js.map +0 -1
@@ -1,110 +1,110 @@
1
- /**
2
- * React Native Unified Auth Provider
3
- *
4
- * Creates a platform-specific auth provider that automatically selects the appropriate storage:
5
- * - Web: Uses IndexedDBTokenStorage for DPoP (CryptoKey persistence) or LocalStorage
6
- * - Mobile: Uses AsyncStorage-based storage
7
- */
8
-
9
- import { Platform } from 'react-native';
10
- import { DefaultAuthProvider, AccountOwnerType, LocalStorageTokenStorage, IndexedDBTokenStorage } from '@explorins/pers-sdk/core';
11
- import { ReactNativeSecureStorage } from '../storage/rn-secure-storage';
12
- import type { TokenStorage } from '@explorins/pers-sdk/core';
13
-
14
- // Use React Native's built-in platform detection
15
- const isWebPlatform = Platform.OS === 'web';
16
-
17
- /**
18
- * Check if IndexedDB is available (web environments only)
19
- * Uses globalThis to avoid TypeScript errors in React Native context
20
- */
21
- function hasIndexedDB(): boolean {
22
- return typeof globalThis !== 'undefined' &&
23
- typeof (globalThis as Record<string, unknown>).indexedDB !== 'undefined';
24
- }
25
-
26
- /**
27
- * Configuration for React Native Auth Provider
28
- */
29
- export interface ReactNativeAuthConfig {
30
- /** Custom storage key prefix */
31
- keyPrefix?: string;
32
- /** Enable debug logging */
33
- debug?: boolean;
34
- /** Custom token storage implementation */
35
- customStorage?: TokenStorage;
36
- /** Authentication type (default: AccountOwnerType.USER) */
37
- authType?: AccountOwnerType;
38
- /** DPoP Configuration (optional) */
39
- dpop?: {
40
- enabled?: boolean;
41
- cryptoProvider?: import('@explorins/pers-sdk/core').DPoPCryptoProvider;
42
- };
43
- }
44
-
45
- /**
46
- * Create a React Native auth provider with platform-appropriate storage
47
- *
48
- * Automatically selects storage implementation:
49
- * - Web: Uses LocalStorageTokenStorage (from core SDK)
50
- * - Mobile: Uses AsyncStorageTokenStorage (React Native specific)
51
- *
52
- * @param projectKey - PERS project key
53
- * @param config - Configuration options
54
- * @returns DefaultAuthProvider configured for the current platform
55
- */
56
- export function createReactNativeAuthProvider(
57
- projectKey: string,
58
- config: ReactNativeAuthConfig = {}
59
- ): DefaultAuthProvider {
60
- if (!projectKey || typeof projectKey !== 'string') {
61
- throw new Error('createReactNativeAuthProvider: projectKey is required and must be a string');
62
- }
63
-
64
- const {
65
- keyPrefix = `pers_${projectKey.slice(0, 8)}_`,
66
- debug = false,
67
- customStorage,
68
- authType = AccountOwnerType.USER,
69
- dpop
70
- } = config;
71
-
72
- // Platform-specific storage selection
73
- // Web with DPoP: Use IndexedDB for CryptoKey persistence
74
- // Web without DPoP or no IndexedDB: Use LocalStorage
75
- // Mobile: Use ReactNativeSecureStorage
76
- let tokenStorage: TokenStorage;
77
-
78
- if (customStorage) {
79
- tokenStorage = customStorage;
80
- } else if (isWebPlatform) {
81
- // On web, prefer IndexedDB when DPoP is enabled for proper CryptoKey persistence
82
- const dpopEnabled = dpop?.enabled ?? true;
83
-
84
- if (dpopEnabled && hasIndexedDB()) {
85
- tokenStorage = new IndexedDBTokenStorage();
86
- } else {
87
- if (dpopEnabled && !hasIndexedDB()) {
88
- console.warn('[ReactNativeAuthProvider] DPoP requested but IndexedDB not available. Falling back to LocalStorage (DPoP will be disabled by DefaultAuthProvider).');
89
- }
90
- tokenStorage = new LocalStorageTokenStorage();
91
- }
92
- } else {
93
- tokenStorage = new ReactNativeSecureStorage(keyPrefix);
94
- }
95
-
96
- // Prepare DPoP config ensuring enabled is boolean (default true)
97
- const dpopConfig = dpop ? {
98
- enabled: dpop.enabled ?? true,
99
- cryptoProvider: dpop.cryptoProvider
100
- } : undefined;
101
-
102
- // Return DefaultAuthProvider configured with platform-appropriate storage
103
- return new DefaultAuthProvider({
104
- authType,
105
- projectKey,
106
- storage: tokenStorage,
107
- dpop: dpopConfig
108
- });
109
- }
110
-
1
+ /**
2
+ * React Native Unified Auth Provider
3
+ *
4
+ * Creates a platform-specific auth provider that automatically selects the appropriate storage:
5
+ * - Web: Uses IndexedDBTokenStorage for DPoP (CryptoKey persistence) or LocalStorage
6
+ * - Mobile: Uses AsyncStorage-based storage
7
+ */
8
+
9
+ import { Platform } from 'react-native';
10
+ import { DefaultAuthProvider, AccountOwnerType, LocalStorageTokenStorage, IndexedDBTokenStorage } from '@explorins/pers-sdk/core';
11
+ import { ReactNativeSecureStorage } from '../storage/rn-secure-storage';
12
+ import type { TokenStorage } from '@explorins/pers-sdk/core';
13
+
14
+ // Use React Native's built-in platform detection
15
+ const isWebPlatform = Platform.OS === 'web';
16
+
17
+ /**
18
+ * Check if IndexedDB is available (web environments only)
19
+ * Uses globalThis to avoid TypeScript errors in React Native context
20
+ */
21
+ function hasIndexedDB(): boolean {
22
+ return typeof globalThis !== 'undefined' &&
23
+ typeof (globalThis as Record<string, unknown>).indexedDB !== 'undefined';
24
+ }
25
+
26
+ /**
27
+ * Configuration for React Native Auth Provider
28
+ */
29
+ export interface ReactNativeAuthConfig {
30
+ /** Custom storage key prefix */
31
+ keyPrefix?: string;
32
+ /** Enable debug logging */
33
+ debug?: boolean;
34
+ /** Custom token storage implementation */
35
+ customStorage?: TokenStorage;
36
+ /** Authentication type (default: AccountOwnerType.USER) */
37
+ authType?: AccountOwnerType;
38
+ /** DPoP Configuration (optional) */
39
+ dpop?: {
40
+ enabled?: boolean;
41
+ cryptoProvider?: import('@explorins/pers-sdk/core').DPoPCryptoProvider;
42
+ };
43
+ }
44
+
45
+ /**
46
+ * Create a React Native auth provider with platform-appropriate storage
47
+ *
48
+ * Automatically selects storage implementation:
49
+ * - Web: Uses LocalStorageTokenStorage (from core SDK)
50
+ * - Mobile: Uses AsyncStorageTokenStorage (React Native specific)
51
+ *
52
+ * @param projectKey - PERS project key
53
+ * @param config - Configuration options
54
+ * @returns DefaultAuthProvider configured for the current platform
55
+ */
56
+ export function createReactNativeAuthProvider(
57
+ projectKey: string,
58
+ config: ReactNativeAuthConfig = {}
59
+ ): DefaultAuthProvider {
60
+ if (!projectKey || typeof projectKey !== 'string') {
61
+ throw new Error('createReactNativeAuthProvider: projectKey is required and must be a string');
62
+ }
63
+
64
+ const {
65
+ keyPrefix = `pers_${projectKey.slice(0, 8)}_`,
66
+ debug = false,
67
+ customStorage,
68
+ authType = AccountOwnerType.USER,
69
+ dpop
70
+ } = config;
71
+
72
+ // Platform-specific storage selection
73
+ // Web with DPoP: Use IndexedDB for CryptoKey persistence
74
+ // Web without DPoP or no IndexedDB: Use LocalStorage
75
+ // Mobile: Use ReactNativeSecureStorage
76
+ let tokenStorage: TokenStorage;
77
+
78
+ if (customStorage) {
79
+ tokenStorage = customStorage;
80
+ } else if (isWebPlatform) {
81
+ // On web, prefer IndexedDB when DPoP is enabled for proper CryptoKey persistence
82
+ const dpopEnabled = dpop?.enabled ?? true;
83
+
84
+ if (dpopEnabled && hasIndexedDB()) {
85
+ tokenStorage = new IndexedDBTokenStorage();
86
+ } else {
87
+ if (dpopEnabled && !hasIndexedDB()) {
88
+ console.warn('[ReactNativeAuthProvider] DPoP requested but IndexedDB not available. Falling back to LocalStorage (DPoP will be disabled by DefaultAuthProvider).');
89
+ }
90
+ tokenStorage = new LocalStorageTokenStorage();
91
+ }
92
+ } else {
93
+ tokenStorage = new ReactNativeSecureStorage(keyPrefix);
94
+ }
95
+
96
+ // Prepare DPoP config ensuring enabled is boolean (default true)
97
+ const dpopConfig = dpop ? {
98
+ enabled: dpop.enabled ?? true,
99
+ cryptoProvider: dpop.cryptoProvider
100
+ } : undefined;
101
+
102
+ // Return DefaultAuthProvider configured with platform-appropriate storage
103
+ return new DefaultAuthProvider({
104
+ authType,
105
+ projectKey,
106
+ storage: tokenStorage,
107
+ dpop: dpopConfig
108
+ });
109
+ }
110
+
@@ -1,146 +1,151 @@
1
- /**
2
- * HTTP Client implementation for React Native
3
- *
4
- * This implementation properly implements the core SDK's HttpClient interface
5
- * and uses fetch API which is available in React Native.
6
- */
7
-
8
- /**
9
- * Request options for HTTP client operations
10
- *
11
- * @interface RequestOptions
12
- * @property {Record<string, string>} [headers] - HTTP headers to include
13
- * @property {Record<string, string>} [params] - URL parameters
14
- * @property {number} [timeout] - Request timeout in milliseconds
15
- * @property {'json' | 'blob' | 'text' | 'arraybuffer'} [responseType] - Expected response type
16
- */
17
- export interface RequestOptions {
18
- headers?: Record<string, string>;
19
- params?: Record<string, string>;
20
- timeout?: number;
21
- responseType?: 'json' | 'blob' | 'text' | 'arraybuffer';
22
- }
23
-
24
- /**
25
- * HTTP Client interface for React Native
26
- *
27
- * @interface HttpClient
28
- * @template T - Response type
29
- */
30
- export interface HttpClient {
31
- get<T>(url: string, options?: RequestOptions): Promise<T>;
32
- post<T>(url: string, body: any, options?: RequestOptions): Promise<T>;
33
- put<T>(url: string, body: any, options?: RequestOptions): Promise<T>;
34
- delete<T>(url: string, options?: RequestOptions): Promise<T>;
35
- }
36
-
37
- export class ReactNativeHttpClient implements HttpClient {
38
- private baseURL?: string;
39
-
40
- constructor(baseURL?: string) {
41
- this.baseURL = baseURL;
42
- }
43
-
44
- async get<T = any>(url: string, options?: RequestOptions): Promise<T> {
45
- return this.request<T>('GET', url, undefined, options);
46
- }
47
-
48
- async post<T = any>(url: string, body?: any, options?: RequestOptions): Promise<T> {
49
- return this.request<T>('POST', url, body, options);
50
- }
51
-
52
- async put<T = any>(url: string, body?: any, options?: RequestOptions): Promise<T> {
53
- return this.request<T>('PUT', url, body, options);
54
- }
55
-
56
- async delete<T = any>(url: string, options?: RequestOptions): Promise<T> {
57
- return this.request<T>('DELETE', url, undefined, options);
58
- }
59
-
60
- private async request<T>(
61
- method: string,
62
- url: string,
63
- body?: any,
64
- options?: RequestOptions
65
- ): Promise<T> {
66
- const fullUrl = this.buildUrl(url, options?.params);
67
-
68
- const config: RequestInit = {
69
- method,
70
- headers: {
71
- 'Content-Type': 'application/json',
72
- ...options?.headers,
73
- },
74
- };
75
-
76
- // Add timeout if specified
77
- if (options?.timeout) {
78
- const controller = new AbortController();
79
- config.signal = controller.signal;
80
- setTimeout(() => controller.abort(), options.timeout);
81
- }
82
-
83
- // Add body for POST/PUT requests
84
- if (body && (method === 'POST' || method === 'PUT')) {
85
- config.body = JSON.stringify(body);
86
- }
87
-
88
- try {
89
- const response = await fetch(fullUrl, config);
90
-
91
- if (!response.ok) {
92
- // Get raw error response for ErrorUtils to handle
93
- let errorText = '';
94
- try {
95
- errorText = await response.text();
96
- } catch (e) {
97
- // Ignore errors when reading error body
98
- }
99
-
100
- // Create simple error with HTTP status and raw response
101
- const httpError = new Error(`HTTP ${response.status}: ${response.statusText} - ${errorText}`);
102
- (httpError as any).status = response.status;
103
-
104
- throw httpError;
105
- }
106
-
107
- // Handle different response types
108
- switch (options?.responseType) {
109
- case 'text':
110
- return response.text() as Promise<T>;
111
- case 'blob':
112
- return response.blob() as Promise<T>;
113
- case 'arraybuffer':
114
- return response.arrayBuffer() as Promise<T>;
115
- case 'json':
116
- default:
117
- // Check if response has content
118
- const contentLength = response.headers.get('content-length');
119
- if (contentLength === '0' || response.status === 204) {
120
- return undefined as T;
121
- }
122
- return response.json();
123
- }
124
- } catch (error) {
125
- if (error instanceof Error && error.name === 'AbortError') {
126
- throw new Error(`Request timeout after ${options?.timeout}ms`);
127
- }
128
- throw error;
129
- }
130
- }
131
-
132
- private buildUrl(url: string, params?: Record<string, string>): string {
133
- const fullUrl = this.baseURL ? `${this.baseURL}${url}` : url;
134
-
135
- if (!params || Object.keys(params).length === 0) {
136
- return fullUrl;
137
- }
138
-
139
- const urlObj = new URL(fullUrl);
140
- Object.entries(params).forEach(([key, value]) => {
141
- urlObj.searchParams.append(key, value);
142
- });
143
-
144
- return urlObj.toString();
145
- }
1
+ /**
2
+ * HTTP Client implementation for React Native
3
+ *
4
+ * This implementation properly implements the core SDK's HttpClient interface
5
+ * and uses fetch API which is available in React Native.
6
+ */
7
+
8
+ /**
9
+ * Request options for HTTP client operations
10
+ *
11
+ * @interface RequestOptions
12
+ * @property {Record<string, string>} [headers] - HTTP headers to include
13
+ * @property {Record<string, string>} [params] - URL parameters
14
+ * @property {number} [timeout] - Request timeout in milliseconds
15
+ * @property {'json' | 'blob' | 'text' | 'arraybuffer'} [responseType] - Expected response type
16
+ */
17
+ export interface RequestOptions {
18
+ headers?: Record<string, string>;
19
+ params?: Record<string, string>;
20
+ timeout?: number;
21
+ responseType?: 'json' | 'blob' | 'text' | 'arraybuffer';
22
+ }
23
+
24
+ /**
25
+ * HTTP Client interface for React Native
26
+ *
27
+ * @interface HttpClient
28
+ * @template T - Response type
29
+ */
30
+ export interface HttpClient {
31
+ get<T>(url: string, options?: RequestOptions): Promise<T>;
32
+ post<T>(url: string, body: any, options?: RequestOptions): Promise<T>;
33
+ put<T>(url: string, body: any, options?: RequestOptions): Promise<T>;
34
+ patch<T>(url: string, body: any, options?: RequestOptions): Promise<T>;
35
+ delete<T>(url: string, options?: RequestOptions): Promise<T>;
36
+ }
37
+
38
+ export class ReactNativeHttpClient implements HttpClient {
39
+ private baseURL?: string;
40
+
41
+ constructor(baseURL?: string) {
42
+ this.baseURL = baseURL;
43
+ }
44
+
45
+ async get<T = any>(url: string, options?: RequestOptions): Promise<T> {
46
+ return this.request<T>('GET', url, undefined, options);
47
+ }
48
+
49
+ async post<T = any>(url: string, body?: any, options?: RequestOptions): Promise<T> {
50
+ return this.request<T>('POST', url, body, options);
51
+ }
52
+
53
+ async put<T = any>(url: string, body?: any, options?: RequestOptions): Promise<T> {
54
+ return this.request<T>('PUT', url, body, options);
55
+ }
56
+
57
+ async patch<T = any>(url: string, body?: any, options?: RequestOptions): Promise<T> {
58
+ return this.request<T>('PATCH', url, body, options);
59
+ }
60
+
61
+ async delete<T = any>(url: string, options?: RequestOptions): Promise<T> {
62
+ return this.request<T>('DELETE', url, undefined, options);
63
+ }
64
+
65
+ private async request<T>(
66
+ method: string,
67
+ url: string,
68
+ body?: any,
69
+ options?: RequestOptions
70
+ ): Promise<T> {
71
+ const fullUrl = this.buildUrl(url, options?.params);
72
+
73
+ const config: RequestInit = {
74
+ method,
75
+ headers: {
76
+ 'Content-Type': 'application/json',
77
+ ...options?.headers,
78
+ },
79
+ };
80
+
81
+ // Add timeout if specified
82
+ if (options?.timeout) {
83
+ const controller = new AbortController();
84
+ config.signal = controller.signal;
85
+ setTimeout(() => controller.abort(), options.timeout);
86
+ }
87
+
88
+ // Add body for POST/PUT/PATCH requests
89
+ if (body && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
90
+ config.body = JSON.stringify(body);
91
+ }
92
+
93
+ try {
94
+ const response = await fetch(fullUrl, config);
95
+
96
+ if (!response.ok) {
97
+ // Get raw error response for ErrorUtils to handle
98
+ let errorText = '';
99
+ try {
100
+ errorText = await response.text();
101
+ } catch (e) {
102
+ // Ignore errors when reading error body
103
+ }
104
+
105
+ // Create simple error with HTTP status and raw response
106
+ const httpError = new Error(`HTTP ${response.status}: ${response.statusText} - ${errorText}`);
107
+ (httpError as any).status = response.status;
108
+
109
+ throw httpError;
110
+ }
111
+
112
+ // Handle different response types
113
+ switch (options?.responseType) {
114
+ case 'text':
115
+ return response.text() as Promise<T>;
116
+ case 'blob':
117
+ return response.blob() as Promise<T>;
118
+ case 'arraybuffer':
119
+ return response.arrayBuffer() as Promise<T>;
120
+ case 'json':
121
+ default:
122
+ // Check if response has content
123
+ const contentLength = response.headers.get('content-length');
124
+ if (contentLength === '0' || response.status === 204) {
125
+ return undefined as T;
126
+ }
127
+ return response.json();
128
+ }
129
+ } catch (error) {
130
+ if (error instanceof Error && error.name === 'AbortError') {
131
+ throw new Error(`Request timeout after ${options?.timeout}ms`);
132
+ }
133
+ throw error;
134
+ }
135
+ }
136
+
137
+ private buildUrl(url: string, params?: Record<string, string>): string {
138
+ const fullUrl = this.baseURL ? `${this.baseURL}${url}` : url;
139
+
140
+ if (!params || Object.keys(params).length === 0) {
141
+ return fullUrl;
142
+ }
143
+
144
+ const urlObj = new URL(fullUrl);
145
+ Object.entries(params).forEach(([key, value]) => {
146
+ urlObj.searchParams.append(key, value);
147
+ });
148
+
149
+ return urlObj.toString();
150
+ }
146
151
  }