@explorins/pers-sdk-react-native 2.1.20 → 2.1.22

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 +1 @@
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;AAkB3D,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAE7B,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IAGpB,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;IACrC,cAAc,EAAE,MAAM,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;CAC/C;AAKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,CAqOA,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;AAkB3D,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAE7B,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IAGpB,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;IACrC,cAAc,EAAE,MAAM,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;CAC/C;AAKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,CA6NA,CAAC;AAGF,eAAO,MAAM,UAAU,QAAO,cAQ7B,CAAC"}
@@ -72,13 +72,6 @@ export const PersSDKProvider = ({ children, config }) => {
72
72
  if (Platform.OS !== 'web' && isDpopEnabled && !dpopSettings.cryptoProvider) {
73
73
  dpopSettings.cryptoProvider = new ReactNativeDPoPProvider();
74
74
  }
75
- // Log DPoP settings before creating auth provider
76
- console.log('[PersSDKProvider] DPoP settings:', {
77
- platform: Platform.OS,
78
- isDpopEnabled,
79
- hasCryptoProvider: !!dpopSettings.cryptoProvider,
80
- cryptoProviderType: dpopSettings.cryptoProvider?.constructor?.name || 'none'
81
- });
82
75
  // Create platform-aware auth provider if not provided
83
76
  let authProvider;
84
77
  if (config.authProvider) {
@@ -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,EAAE,gBAAgB,EAAmD,MAAM,0BAA0B,CAAC;AAElI,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAc7D;;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,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,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,CA4DrB"}
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,EAAE,gBAAgB,EAAmD,MAAM,0BAA0B,CAAC;AAElI,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAc7D;;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,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,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,CAkDrB"}
@@ -63,15 +63,6 @@ export function createReactNativeAuthProvider(projectKey, config = {}) {
63
63
  enabled: dpop.enabled ?? true,
64
64
  cryptoProvider: dpop.cryptoProvider
65
65
  } : undefined;
66
- // Always log DPoP config for debugging (critical for mobile auth)
67
- console.log('[ReactNativeAuthProvider] Config:', {
68
- platform: Platform.OS,
69
- isWebPlatform,
70
- dpopEnabled: dpopConfig?.enabled ?? false,
71
- hasCryptoProvider: !!dpopConfig?.cryptoProvider,
72
- cryptoProviderType: dpopConfig?.cryptoProvider?.constructor?.name || 'none',
73
- storageType: tokenStorage.constructor.name
74
- });
75
66
  // Return DefaultAuthProvider configured with platform-appropriate storage
76
67
  return new DefaultAuthProvider({
77
68
  authType,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@explorins/pers-sdk-react-native",
3
- "version": "2.1.20",
3
+ "version": "2.1.22",
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",
@@ -8,6 +8,7 @@ export { useBusiness } from './useBusiness';
8
8
  export { useCampaigns } from './useCampaigns';
9
9
  export { useRedemptions } from './useRedemptions';
10
10
  export { useWeb3 } from './useWeb3';
11
+ export { useResolvedUrl, useMetadata, useIPFSUrl, useTransactionMetadata } from './useIPFSUrl';
11
12
  export { usePurchases } from './usePurchases';
12
13
  export { useTenants } from './useTenants';
13
14
  export { useUsers } from './useUsers';
@@ -0,0 +1,192 @@
1
+ import { useState, useEffect, useCallback } from 'react';
2
+ import { usePersSDK } from '../providers/PersSDKProvider';
3
+ import type { TokenMetadata } from '@explorins/pers-sdk';
4
+
5
+ /**
6
+ * React hook for resolving media URLs (IPFS or HTTPS).
7
+ *
8
+ * Automatically handles IPFS URLs by resolving them to HTTPS via tenant's gateway.
9
+ * Non-IPFS URLs are returned as-is. Handles loading and error states.
10
+ *
11
+ * Uses sdk.tenants for IPFS resolution (lightweight, no Web3 deps).
12
+ *
13
+ * @param url - The URL to resolve (can be ipfs://, https://, or undefined)
14
+ * @returns Object with resolved URL, loading state, and error
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * function NFTImage({ metadataUri }: { metadataUri?: string }) {
19
+ * const { url, isLoading } = useResolvedUrl(metadataUri);
20
+ *
21
+ * if (isLoading) return <ActivityIndicator />;
22
+ * return <Image source={{ uri: url }} />;
23
+ * }
24
+ * ```
25
+ */
26
+ export function useResolvedUrl(url: string | undefined | null) {
27
+ const { sdk, isInitialized } = usePersSDK();
28
+ const [resolvedUrl, setResolvedUrl] = useState<string | null>(null);
29
+ const [isLoading, setIsLoading] = useState(false);
30
+ const [error, setError] = useState<string | null>(null);
31
+
32
+ useEffect(() => {
33
+ if (!url || !isInitialized || !sdk) {
34
+ setResolvedUrl(null);
35
+ return;
36
+ }
37
+
38
+ // Non-IPFS URLs don't need resolution
39
+ if (!url.startsWith('ipfs://')) {
40
+ setResolvedUrl(url);
41
+ return;
42
+ }
43
+
44
+ setIsLoading(true);
45
+ setError(null);
46
+
47
+ sdk.tenants.resolveIpfsUrl(url)
48
+ .then((resolved) => {
49
+ setResolvedUrl(resolved);
50
+ })
51
+ .catch((err) => {
52
+ setError(err instanceof Error ? err.message : 'Failed to resolve URL');
53
+ setResolvedUrl(null);
54
+ })
55
+ .finally(() => {
56
+ setIsLoading(false);
57
+ });
58
+ }, [url, isInitialized, sdk]);
59
+
60
+ return {
61
+ /** Resolved HTTPS URL (or original if not IPFS) */
62
+ url: resolvedUrl,
63
+ /** Whether resolution is in progress */
64
+ isLoading,
65
+ /** Error message if resolution failed */
66
+ error,
67
+ };
68
+ }
69
+
70
+ /**
71
+ * React hook for fetching NFT/token metadata from a URI.
72
+ *
73
+ * Handles IPFS resolution automatically and returns parsed metadata
74
+ * with all nested IPFS URLs already resolved to HTTPS.
75
+ *
76
+ * Uses sdk.tenants for metadata fetching (lightweight, no Web3 deps).
77
+ *
78
+ * @param metadataUri - The metadata URI to fetch (can be ipfs:// or https://)
79
+ * @returns Object with metadata, loading state, error, and refresh function
80
+ *
81
+ * @example
82
+ * ```tsx
83
+ * function NFTDetails({ metadataUri }: { metadataUri?: string }) {
84
+ * const { metadata, isLoading, error } = useMetadata(metadataUri);
85
+ *
86
+ * if (isLoading) return <ActivityIndicator />;
87
+ * if (error) return <Text>Error: {error}</Text>;
88
+ * if (!metadata) return null;
89
+ *
90
+ * return (
91
+ * <View>
92
+ * <Image source={{ uri: metadata.imageUrl }} />
93
+ * <Text>{metadata.name}</Text>
94
+ * <Text>{metadata.description}</Text>
95
+ * </View>
96
+ * );
97
+ * }
98
+ * ```
99
+ */
100
+ export function useMetadata(metadataUri: string | undefined | null) {
101
+ const { sdk, isInitialized } = usePersSDK();
102
+ const [metadata, setMetadata] = useState<TokenMetadata | null>(null);
103
+ const [isLoading, setIsLoading] = useState(false);
104
+ const [error, setError] = useState<string | null>(null);
105
+
106
+ const fetchMetadata = useCallback(async () => {
107
+ if (!metadataUri || !isInitialized || !sdk) {
108
+ setMetadata(null);
109
+ return;
110
+ }
111
+
112
+ setIsLoading(true);
113
+ setError(null);
114
+
115
+ try {
116
+ const result = await sdk.tenants.fetchAndProcessMetadata(metadataUri);
117
+ setMetadata(result);
118
+ } catch (err) {
119
+ setError(err instanceof Error ? err.message : 'Failed to fetch metadata');
120
+ setMetadata(null);
121
+ } finally {
122
+ setIsLoading(false);
123
+ }
124
+ }, [metadataUri, isInitialized, sdk]);
125
+
126
+ useEffect(() => {
127
+ fetchMetadata();
128
+ }, [fetchMetadata]);
129
+
130
+ return {
131
+ /** Parsed metadata with resolved IPFS URLs (imageUrl, animationUrl, etc.) */
132
+ metadata,
133
+ /** Whether fetch is in progress */
134
+ isLoading,
135
+ /** Error message if fetch failed */
136
+ error,
137
+ /** Manually refresh metadata */
138
+ refresh: fetchMetadata,
139
+ };
140
+ }
141
+
142
+ // Re-export with descriptive aliases
143
+ export { useResolvedUrl as useIPFSUrl };
144
+
145
+ /**
146
+ * React hook for loading transaction/token metadata.
147
+ *
148
+ * Convenience wrapper around useMetadata specifically for transaction items.
149
+ * Pass a transaction's metadataUri to get the NFT image, name, description, etc.
150
+ *
151
+ * @param transaction - Transaction object with optional metadataUri field
152
+ * @returns Object with metadata, loading state, and image URL
153
+ *
154
+ * @example
155
+ * ```tsx
156
+ * import { useTransactionMetadata } from '@explorins/pers-sdk-react-native';
157
+ *
158
+ * function TransactionItem({ tx }: { tx: TransactionDTO }) {
159
+ * const { metadata, isLoading, imageUrl } = useTransactionMetadata(tx);
160
+ *
161
+ * if (isLoading) return <ActivityIndicator />;
162
+ *
163
+ * return (
164
+ * <View>
165
+ * {imageUrl && <Image source={{ uri: imageUrl }} style={{ width: 60, height: 60 }} />}
166
+ * <Text>{metadata?.name || tx.type}</Text>
167
+ * <Text>{tx.amount} tokens</Text>
168
+ * </View>
169
+ * );
170
+ * }
171
+ * ```
172
+ */
173
+ export function useTransactionMetadata(transaction: { metadataUri?: string | null } | null | undefined) {
174
+ const { metadata, isLoading, error, refresh } = useMetadata(transaction?.metadataUri);
175
+
176
+ return {
177
+ /** Parsed metadata with resolved URLs */
178
+ metadata,
179
+ /** Whether metadata is loading */
180
+ isLoading,
181
+ /** Error message if fetch failed */
182
+ error,
183
+ /** Convenience: resolved image URL (or undefined) */
184
+ imageUrl: metadata?.imageUrl,
185
+ /** Convenience: token/NFT name (or undefined) */
186
+ name: metadata?.name,
187
+ /** Convenience: token/NFT description (or undefined) */
188
+ description: metadata?.description,
189
+ /** Manually refresh metadata */
190
+ refresh,
191
+ };
192
+ }
@@ -157,8 +157,7 @@ export const useTransactions = () => {
157
157
  }
158
158
 
159
159
  try {
160
- const result = await sdk.transactions.getTransactionById(transactionId, include);
161
- return result;
160
+ return await sdk.transactions.getTransactionById(transactionId, include);
162
161
  } catch (error) {
163
162
  console.error('Failed to fetch transaction:', error);
164
163
  throw error;
@@ -205,14 +204,12 @@ export const useTransactions = () => {
205
204
  const getUserTransactionHistory = useCallback(async (
206
205
  options?: TransactionQueryOptions
207
206
  ): Promise<PaginatedResponseDTO<TransactionDTO>> => {
208
-
209
207
  if (!isInitialized || !sdk) {
210
208
  throw new Error('SDK not initialized. Call initialize() first.');
211
209
  }
212
210
 
213
211
  try {
214
- const result = await sdk.transactions.getUserTransactionHistory(options);
215
- return result;
212
+ return await sdk.transactions.getUserTransactionHistory(options);
216
213
  } catch (error) {
217
214
  console.error('Failed to fetch transaction history:', error);
218
215
  throw error;
@@ -166,9 +166,20 @@ export const useWeb3 = () => {
166
166
  /**
167
167
  * Resolve IPFS URL to HTTP gateway URL
168
168
  *
169
- * @deprecated Use `sdk.tenant.resolveIPFSUrl()` directly - IPFS is chain-agnostic
169
+ * Converts an ipfs:// URL to an HTTPS URL using the tenant's configured IPFS gateway.
170
+ * Non-IPFS URLs are returned unchanged.
171
+ *
172
+ * Note: Uses sdk.tenants for IPFS resolution (chain-agnostic).
173
+ *
170
174
  * @param url - IPFS URL to resolve (ipfs://...)
171
175
  * @returns Promise resolving to HTTP gateway URL
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * const { resolveIPFSUrl } = useWeb3();
180
+ * const httpsUrl = await resolveIPFSUrl('ipfs://QmHash...');
181
+ * // Returns: 'https://gateway.pinata.cloud/ipfs/QmHash...'
182
+ * ```
172
183
  */
173
184
  const resolveIPFSUrl = useCallback(async (url: string): Promise<string> => {
174
185
  if (!isInitialized || !sdk) {
@@ -176,7 +187,7 @@ export const useWeb3 = () => {
176
187
  }
177
188
 
178
189
  try {
179
- const result = await sdk.tenants.resolveIPFSUrl(url);
190
+ const result = await sdk.tenants.resolveIpfsUrl(url);
180
191
  return result;
181
192
  } catch (error) {
182
193
  console.error('Failed to resolve IPFS URL:', error);
@@ -187,22 +198,24 @@ export const useWeb3 = () => {
187
198
  /**
188
199
  * Fetch and process token metadata from a URI
189
200
  *
201
+ * Note: Uses sdk.tenants for metadata fetching (chain-agnostic IPFS).
202
+ *
190
203
  * @param tokenUri - Token URI to fetch metadata from
191
204
  * @returns Promise resolving to processed metadata or null
192
205
  */
193
206
  const fetchAndProcessMetadata = useCallback(async (tokenUri: string): Promise<TokenMetadata | null> => {
194
- if (!isInitialized || !web3) {
207
+ if (!isInitialized || !sdk) {
195
208
  throw new Error('SDK not initialized. Call initialize() first.');
196
209
  }
197
210
 
198
211
  try {
199
- const result = await web3.fetchAndProcessMetadata(tokenUri);
212
+ const result = await sdk.tenants.fetchAndProcessMetadata(tokenUri);
200
213
  return result;
201
214
  } catch (error) {
202
215
  console.error('Failed to fetch and process metadata:', error);
203
216
  throw error;
204
217
  }
205
- }, [web3, isInitialized]);
218
+ }, [sdk, isInitialized]);
206
219
 
207
220
  const getChainDataById = useCallback(async (chainId: number): Promise<ChainData> => {
208
221
  if (!isInitialized || !web3) {
package/src/index.ts CHANGED
@@ -263,7 +263,12 @@ export {
263
263
  useAnalytics,
264
264
  useDonations,
265
265
  useEvents,
266
- useTriggerSources
266
+ useTriggerSources,
267
+ // IPFS hooks - for resolving ipfs:// URLs and loading metadata
268
+ useResolvedUrl,
269
+ useMetadata,
270
+ useIPFSUrl, // alias for useResolvedUrl
271
+ useTransactionMetadata // convenience for transaction items
267
272
  } from './hooks';
268
273
 
269
274
  // Re-export signing status types for convenience
@@ -135,14 +135,6 @@ export const PersSDKProvider: React.FC<{
135
135
  dpopSettings.cryptoProvider = new ReactNativeDPoPProvider();
136
136
  }
137
137
 
138
- // Log DPoP settings before creating auth provider
139
- console.log('[PersSDKProvider] DPoP settings:', {
140
- platform: Platform.OS,
141
- isDpopEnabled,
142
- hasCryptoProvider: !!dpopSettings.cryptoProvider,
143
- cryptoProviderType: dpopSettings.cryptoProvider?.constructor?.name || 'none'
144
- });
145
-
146
138
  // Create platform-aware auth provider if not provided
147
139
  let authProvider: DefaultAuthProvider;
148
140
  if (config.authProvider) {
@@ -98,16 +98,6 @@ export function createReactNativeAuthProvider(
98
98
  enabled: dpop.enabled ?? true,
99
99
  cryptoProvider: dpop.cryptoProvider
100
100
  } : undefined;
101
-
102
- // Always log DPoP config for debugging (critical for mobile auth)
103
- console.log('[ReactNativeAuthProvider] Config:', {
104
- platform: Platform.OS,
105
- isWebPlatform,
106
- dpopEnabled: dpopConfig?.enabled ?? false,
107
- hasCryptoProvider: !!dpopConfig?.cryptoProvider,
108
- cryptoProviderType: dpopConfig?.cryptoProvider?.constructor?.name || 'none',
109
- storageType: tokenStorage.constructor.name
110
- });
111
101
 
112
102
  // Return DefaultAuthProvider configured with platform-appropriate storage
113
103
  return new DefaultAuthProvider({