@explorins/pers-sdk-react-native 2.1.21 → 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.
package/dist/index.js CHANGED
@@ -8500,6 +8500,100 @@ class TenantManager {
8500
8500
  clearCache() {
8501
8501
  this.cache.clear();
8502
8502
  }
8503
+ // ==========================================
8504
+ // IPFS OPERATIONS (Lightweight, no Web3 deps)
8505
+ // ==========================================
8506
+ /**
8507
+ * Get the IPFS gateway domain from tenant config (cached)
8508
+ *
8509
+ * @returns Promise resolving to IPFS gateway domain (e.g., 'gateway.pinata.cloud')
8510
+ * @example
8511
+ * ```typescript
8512
+ * const gateway = await sdk.tenants.getIpfsGatewayDomain();
8513
+ * // Returns 'gateway.pinata.cloud' or tenant-specific gateway
8514
+ * ```
8515
+ */
8516
+ async getIpfsGatewayDomain() {
8517
+ return this.cache.getOrSet('ipfsGateway', async () => {
8518
+ const config = await this.getClientConfig();
8519
+ return config.ipfsGatewayDomain || 'gateway.pinata.cloud';
8520
+ }, CacheTTL.LONG);
8521
+ }
8522
+ /**
8523
+ * Resolve an IPFS URL to an HTTP gateway URL
8524
+ *
8525
+ * @param url - The URL to resolve (ipfs://, ar://, or HTTP URL)
8526
+ * @returns Promise resolving to HTTP gateway URL
8527
+ *
8528
+ * @example
8529
+ * ```typescript
8530
+ * const httpUrl = await sdk.tenants.resolveIpfsUrl('ipfs://QmXxx...');
8531
+ * // Returns 'https://gateway.pinata.cloud/ipfs/QmXxx...'
8532
+ * ```
8533
+ */
8534
+ async resolveIpfsUrl(url) {
8535
+ if (!url)
8536
+ return '';
8537
+ // Already an HTTP URL
8538
+ if (url.startsWith('http://') || url.startsWith('https://')) {
8539
+ return url;
8540
+ }
8541
+ const gateway = await this.getIpfsGatewayDomain();
8542
+ // Handle ipfs:// protocol
8543
+ if (url.startsWith('ipfs://')) {
8544
+ const cid = url.replace('ipfs://', '');
8545
+ return `https://${gateway}/ipfs/${cid}`;
8546
+ }
8547
+ // Handle ar:// (Arweave) protocol
8548
+ if (url.startsWith('ar://')) {
8549
+ const txId = url.replace('ar://', '');
8550
+ return `https://arweave.net/${txId}`;
8551
+ }
8552
+ return url;
8553
+ }
8554
+ /**
8555
+ * Fetch and process token metadata from IPFS/HTTP URI
8556
+ *
8557
+ * @param tokenUri - The token URI (ipfs://, ar://, or HTTP)
8558
+ * @returns Promise resolving to processed metadata or null on error
8559
+ *
8560
+ * @example
8561
+ * ```typescript
8562
+ * const metadata = await sdk.tenants.fetchAndProcessMetadata('ipfs://QmXxx.../metadata.json');
8563
+ * if (metadata) {
8564
+ * console.log(metadata.name, metadata.imageUrl);
8565
+ * }
8566
+ * ```
8567
+ */
8568
+ async fetchAndProcessMetadata(tokenUri) {
8569
+ try {
8570
+ const resolvedUri = await this.resolveIpfsUrl(tokenUri);
8571
+ const response = await fetch(resolvedUri);
8572
+ if (!response.ok) {
8573
+ console.warn(`Failed to fetch metadata from ${resolvedUri}: ${response.status}`);
8574
+ return null;
8575
+ }
8576
+ const rawMetadata = await response.json();
8577
+ // Normalize the metadata - resolve image URLs
8578
+ const imageUrl = rawMetadata.image || rawMetadata.image_url || rawMetadata.imageUrl || '';
8579
+ const resolvedImageUrl = await this.resolveIpfsUrl(imageUrl);
8580
+ const animationUrl = rawMetadata.animation_url || rawMetadata.animationUrl || '';
8581
+ const resolvedAnimationUrl = animationUrl ? await this.resolveIpfsUrl(animationUrl) : undefined;
8582
+ return {
8583
+ name: rawMetadata.name || 'Untitled',
8584
+ description: rawMetadata.description || '',
8585
+ imageUrl: resolvedImageUrl,
8586
+ animationUrl: resolvedAnimationUrl,
8587
+ externalUrl: rawMetadata.external_url || rawMetadata.externalUrl,
8588
+ attributes: rawMetadata.attributes,
8589
+ ...rawMetadata // Include any additional properties
8590
+ };
8591
+ }
8592
+ catch (error) {
8593
+ console.warn(`Error fetching metadata from ${tokenUri}:`, error);
8594
+ return null;
8595
+ }
8596
+ }
8503
8597
  }
8504
8598
 
8505
8599
  /**
@@ -40915,19 +41009,11 @@ async function getExplorerUrlByChainId(getChainData, chainId, address, type) {
40915
41009
  *
40916
41010
  * ## IPFS Resolution
40917
41011
  *
40918
- * Use `sdk.web3.resolveIPFSUrl()` to resolve IPFS URLs to HTTPS:
40919
- *
40920
- * ```typescript
40921
- * const httpsUrl = await sdk.web3.resolveIPFSUrl('ipfs://QmXxx.../image.png');
40922
- * // Returns: 'https://pers.mypinata.cloud/ipfs/QmXxx.../image.png'
40923
- * ```
40924
- *
40925
- * Or fetch full metadata with resolved URLs:
41012
+ * **Note:** IPFS is chain-agnostic. Use `sdk.tenants` for IPFS operations:
40926
41013
  *
40927
41014
  * ```typescript
40928
- * const metadata = await sdk.web3.fetchAndProcessMetadata('ipfs://QmXxx.../metadata.json');
40929
- * // All IPFS URLs in metadata are resolved to HTTPS
40930
- * // Returns SDK format: { imageUrl, animationUrl, externalUrl, ... }
41015
+ * const httpsUrl = await sdk.tenants.resolveIpfsUrl('ipfs://QmXxx.../image.png');
41016
+ * const metadata = await sdk.tenants.fetchAndProcessMetadata('ipfs://QmXxx.../metadata.json');
40931
41017
  * ```
40932
41018
  */
40933
41019
  class Web3Manager {
@@ -40982,48 +41068,10 @@ class Web3Manager {
40982
41068
  *
40983
41069
  * @param tokenUri - Token URI to fetch metadata from
40984
41070
  * @returns Promise resolving to processed metadata or null if not found
41071
+ * @deprecated Use sdk.tenants.fetchAndProcessMetadata() instead - IPFS is chain-agnostic
40985
41072
  */
40986
41073
  async fetchAndProcessMetadata(tokenUri) {
40987
- return this.web3ApplicationService.fetchAndProcessMetadata(tokenUri);
40988
- }
40989
- // ==========================================
40990
- // IPFS OPERATIONS
40991
- // ==========================================
40992
- /**
40993
- * Resolve IPFS URL to HTTPS URL using tenant's configured gateway.
40994
- *
40995
- * @param url - URL to resolve (can be ipfs:// or https://)
40996
- * @returns Resolved HTTPS URL
40997
- * @throws Error if tenant's ipfsGatewayDomain is not configured
40998
- *
40999
- * @example
41000
- * ```typescript
41001
- * const imageUrl = await sdk.web3.resolveIPFSUrl('ipfs://QmXxx.../image.png');
41002
- * // Returns: 'https://pers.mypinata.cloud/ipfs/QmXxx.../image.png'
41003
- *
41004
- * // Non-IPFS URLs pass through unchanged
41005
- * const httpUrl = await sdk.web3.resolveIPFSUrl('https://example.com/image.png');
41006
- * // Returns: 'https://example.com/image.png'
41007
- * ```
41008
- */
41009
- async resolveIPFSUrl(url) {
41010
- return this.web3ApplicationService.resolveIPFSUrl(url);
41011
- }
41012
- /**
41013
- * Get IPFS gateway domain from tenant configuration.
41014
- * Useful for pipes that need to resolve URLs synchronously after initial fetch.
41015
- *
41016
- * @returns Gateway domain (e.g., 'pers.mypinata.cloud')
41017
- * @throws Error if tenant's ipfsGatewayDomain is not configured
41018
- *
41019
- * @example
41020
- * ```typescript
41021
- * const gateway = await sdk.web3.getIpfsGatewayDomain();
41022
- * // Use gateway for sync resolution: `https://${gateway}/ipfs/${cid}`
41023
- * ```
41024
- */
41025
- async getIpfsGatewayDomain() {
41026
- return this.web3ApplicationService.getIpfsGatewayDomain();
41074
+ return this.tenantManager.fetchAndProcessMetadata(tokenUri);
41027
41075
  }
41028
41076
  /**
41029
41077
  * Get blockchain chain data by chain ID
@@ -41334,6 +41382,8 @@ const useWeb3 = () => {
41334
41382
  * Converts an ipfs:// URL to an HTTPS URL using the tenant's configured IPFS gateway.
41335
41383
  * Non-IPFS URLs are returned unchanged.
41336
41384
  *
41385
+ * Note: Uses sdk.tenants for IPFS resolution (chain-agnostic).
41386
+ *
41337
41387
  * @param url - IPFS URL to resolve (ipfs://...)
41338
41388
  * @returns Promise resolving to HTTP gateway URL
41339
41389
  *
@@ -41345,37 +41395,39 @@ const useWeb3 = () => {
41345
41395
  * ```
41346
41396
  */
41347
41397
  const resolveIPFSUrl = react.useCallback(async (url) => {
41348
- if (!isInitialized || !web3) {
41398
+ if (!isInitialized || !sdk) {
41349
41399
  throw new Error('SDK not initialized. Call initialize() first.');
41350
41400
  }
41351
41401
  try {
41352
- const result = await web3.resolveIPFSUrl(url);
41402
+ const result = await sdk.tenants.resolveIpfsUrl(url);
41353
41403
  return result;
41354
41404
  }
41355
41405
  catch (error) {
41356
41406
  console.error('Failed to resolve IPFS URL:', error);
41357
41407
  throw error;
41358
41408
  }
41359
- }, [web3, isInitialized]);
41409
+ }, [sdk, isInitialized]);
41360
41410
  /**
41361
41411
  * Fetch and process token metadata from a URI
41362
41412
  *
41413
+ * Note: Uses sdk.tenants for metadata fetching (chain-agnostic IPFS).
41414
+ *
41363
41415
  * @param tokenUri - Token URI to fetch metadata from
41364
41416
  * @returns Promise resolving to processed metadata or null
41365
41417
  */
41366
41418
  const fetchAndProcessMetadata = react.useCallback(async (tokenUri) => {
41367
- if (!isInitialized || !web3) {
41419
+ if (!isInitialized || !sdk) {
41368
41420
  throw new Error('SDK not initialized. Call initialize() first.');
41369
41421
  }
41370
41422
  try {
41371
- const result = await web3.fetchAndProcessMetadata(tokenUri);
41423
+ const result = await sdk.tenants.fetchAndProcessMetadata(tokenUri);
41372
41424
  return result;
41373
41425
  }
41374
41426
  catch (error) {
41375
41427
  console.error('Failed to fetch and process metadata:', error);
41376
41428
  throw error;
41377
41429
  }
41378
- }, [web3, isInitialized]);
41430
+ }, [sdk, isInitialized]);
41379
41431
  const getChainDataById = react.useCallback(async (chainId) => {
41380
41432
  if (!isInitialized || !web3) {
41381
41433
  throw new Error('SDK not initialized. Call initialize() first.');
@@ -44099,6 +44151,181 @@ const useRedemptions = () => {
44099
44151
  };
44100
44152
  };
44101
44153
 
44154
+ /**
44155
+ * React hook for resolving media URLs (IPFS or HTTPS).
44156
+ *
44157
+ * Automatically handles IPFS URLs by resolving them to HTTPS via tenant's gateway.
44158
+ * Non-IPFS URLs are returned as-is. Handles loading and error states.
44159
+ *
44160
+ * Uses sdk.tenants for IPFS resolution (lightweight, no Web3 deps).
44161
+ *
44162
+ * @param url - The URL to resolve (can be ipfs://, https://, or undefined)
44163
+ * @returns Object with resolved URL, loading state, and error
44164
+ *
44165
+ * @example
44166
+ * ```tsx
44167
+ * function NFTImage({ metadataUri }: { metadataUri?: string }) {
44168
+ * const { url, isLoading } = useResolvedUrl(metadataUri);
44169
+ *
44170
+ * if (isLoading) return <ActivityIndicator />;
44171
+ * return <Image source={{ uri: url }} />;
44172
+ * }
44173
+ * ```
44174
+ */
44175
+ function useResolvedUrl(url) {
44176
+ const { sdk, isInitialized } = usePersSDK();
44177
+ const [resolvedUrl, setResolvedUrl] = react.useState(null);
44178
+ const [isLoading, setIsLoading] = react.useState(false);
44179
+ const [error, setError] = react.useState(null);
44180
+ react.useEffect(() => {
44181
+ if (!url || !isInitialized || !sdk) {
44182
+ setResolvedUrl(null);
44183
+ return;
44184
+ }
44185
+ // Non-IPFS URLs don't need resolution
44186
+ if (!url.startsWith('ipfs://')) {
44187
+ setResolvedUrl(url);
44188
+ return;
44189
+ }
44190
+ setIsLoading(true);
44191
+ setError(null);
44192
+ sdk.tenants.resolveIpfsUrl(url)
44193
+ .then((resolved) => {
44194
+ setResolvedUrl(resolved);
44195
+ })
44196
+ .catch((err) => {
44197
+ setError(err instanceof Error ? err.message : 'Failed to resolve URL');
44198
+ setResolvedUrl(null);
44199
+ })
44200
+ .finally(() => {
44201
+ setIsLoading(false);
44202
+ });
44203
+ }, [url, isInitialized, sdk]);
44204
+ return {
44205
+ /** Resolved HTTPS URL (or original if not IPFS) */
44206
+ url: resolvedUrl,
44207
+ /** Whether resolution is in progress */
44208
+ isLoading,
44209
+ /** Error message if resolution failed */
44210
+ error,
44211
+ };
44212
+ }
44213
+ /**
44214
+ * React hook for fetching NFT/token metadata from a URI.
44215
+ *
44216
+ * Handles IPFS resolution automatically and returns parsed metadata
44217
+ * with all nested IPFS URLs already resolved to HTTPS.
44218
+ *
44219
+ * Uses sdk.tenants for metadata fetching (lightweight, no Web3 deps).
44220
+ *
44221
+ * @param metadataUri - The metadata URI to fetch (can be ipfs:// or https://)
44222
+ * @returns Object with metadata, loading state, error, and refresh function
44223
+ *
44224
+ * @example
44225
+ * ```tsx
44226
+ * function NFTDetails({ metadataUri }: { metadataUri?: string }) {
44227
+ * const { metadata, isLoading, error } = useMetadata(metadataUri);
44228
+ *
44229
+ * if (isLoading) return <ActivityIndicator />;
44230
+ * if (error) return <Text>Error: {error}</Text>;
44231
+ * if (!metadata) return null;
44232
+ *
44233
+ * return (
44234
+ * <View>
44235
+ * <Image source={{ uri: metadata.imageUrl }} />
44236
+ * <Text>{metadata.name}</Text>
44237
+ * <Text>{metadata.description}</Text>
44238
+ * </View>
44239
+ * );
44240
+ * }
44241
+ * ```
44242
+ */
44243
+ function useMetadata(metadataUri) {
44244
+ const { sdk, isInitialized } = usePersSDK();
44245
+ const [metadata, setMetadata] = react.useState(null);
44246
+ const [isLoading, setIsLoading] = react.useState(false);
44247
+ const [error, setError] = react.useState(null);
44248
+ const fetchMetadata = react.useCallback(async () => {
44249
+ if (!metadataUri || !isInitialized || !sdk) {
44250
+ setMetadata(null);
44251
+ return;
44252
+ }
44253
+ setIsLoading(true);
44254
+ setError(null);
44255
+ try {
44256
+ const result = await sdk.tenants.fetchAndProcessMetadata(metadataUri);
44257
+ setMetadata(result);
44258
+ }
44259
+ catch (err) {
44260
+ setError(err instanceof Error ? err.message : 'Failed to fetch metadata');
44261
+ setMetadata(null);
44262
+ }
44263
+ finally {
44264
+ setIsLoading(false);
44265
+ }
44266
+ }, [metadataUri, isInitialized, sdk]);
44267
+ react.useEffect(() => {
44268
+ fetchMetadata();
44269
+ }, [fetchMetadata]);
44270
+ return {
44271
+ /** Parsed metadata with resolved IPFS URLs (imageUrl, animationUrl, etc.) */
44272
+ metadata,
44273
+ /** Whether fetch is in progress */
44274
+ isLoading,
44275
+ /** Error message if fetch failed */
44276
+ error,
44277
+ /** Manually refresh metadata */
44278
+ refresh: fetchMetadata,
44279
+ };
44280
+ }
44281
+ /**
44282
+ * React hook for loading transaction/token metadata.
44283
+ *
44284
+ * Convenience wrapper around useMetadata specifically for transaction items.
44285
+ * Pass a transaction's metadataUri to get the NFT image, name, description, etc.
44286
+ *
44287
+ * @param transaction - Transaction object with optional metadataUri field
44288
+ * @returns Object with metadata, loading state, and image URL
44289
+ *
44290
+ * @example
44291
+ * ```tsx
44292
+ * import { useTransactionMetadata } from '@explorins/pers-sdk-react-native';
44293
+ *
44294
+ * function TransactionItem({ tx }: { tx: TransactionDTO }) {
44295
+ * const { metadata, isLoading, imageUrl } = useTransactionMetadata(tx);
44296
+ *
44297
+ * if (isLoading) return <ActivityIndicator />;
44298
+ *
44299
+ * return (
44300
+ * <View>
44301
+ * {imageUrl && <Image source={{ uri: imageUrl }} style={{ width: 60, height: 60 }} />}
44302
+ * <Text>{metadata?.name || tx.type}</Text>
44303
+ * <Text>{tx.amount} tokens</Text>
44304
+ * </View>
44305
+ * );
44306
+ * }
44307
+ * ```
44308
+ */
44309
+ function useTransactionMetadata(transaction) {
44310
+ const { metadata, isLoading, error, refresh } = useMetadata(transaction?.metadataUri);
44311
+ return {
44312
+ /** Parsed metadata with resolved URLs */
44313
+ metadata,
44314
+ /** Whether metadata is loading */
44315
+ isLoading,
44316
+ /** Error message if fetch failed */
44317
+ error,
44318
+ /** Convenience: resolved image URL (or undefined) */
44319
+ imageUrl: metadata?.imageUrl,
44320
+ /** Convenience: token/NFT name (or undefined) */
44321
+ name: metadata?.name,
44322
+ /** Convenience: token/NFT description (or undefined) */
44323
+ description: metadata?.description,
44324
+ /** Manually refresh metadata */
44325
+ refresh,
44326
+ };
44327
+ }
44328
+
44102
44329
  const usePurchases = () => {
44103
44330
  const { sdk, isInitialized, isAuthenticated } = usePersSDK();
44104
44331
  const createPaymentIntent = react.useCallback(async (amount, currency, receiptEmail, description) => {
@@ -45677,12 +45904,16 @@ exports.useCampaigns = useCampaigns;
45677
45904
  exports.useDonations = useDonations;
45678
45905
  exports.useEvents = useEvents;
45679
45906
  exports.useFiles = useFiles;
45907
+ exports.useIPFSUrl = useResolvedUrl;
45908
+ exports.useMetadata = useMetadata;
45680
45909
  exports.usePersSDK = usePersSDK;
45681
45910
  exports.usePurchases = usePurchases;
45682
45911
  exports.useRedemptions = useRedemptions;
45912
+ exports.useResolvedUrl = useResolvedUrl;
45683
45913
  exports.useTenants = useTenants;
45684
45914
  exports.useTokenBalances = useTokenBalances;
45685
45915
  exports.useTokens = useTokens;
45916
+ exports.useTransactionMetadata = useTransactionMetadata;
45686
45917
  exports.useTransactionSigner = useTransactionSigner;
45687
45918
  exports.useTransactions = useTransactions;
45688
45919
  exports.useTriggerSources = useTriggerSources;