@tuwaio/orbit-solana 0.0.4 → 1.0.0-fix-test-alpha.2.f8f5982

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.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { SolanaClusterMoniker, Rpc, SolanaRpcApi } from 'gill';
1
+ import { SolanaClusterMoniker, SolanaClient, Rpc, SolanaRpcApi } from 'gill';
2
2
 
3
3
  type SolanaRPCUrls = {
4
4
  rpcUrls: Partial<Record<SolanaClusterMoniker, string>>;
@@ -25,6 +25,38 @@ declare const getRpcUrlForCluster: ({ cluster, walletCluster, rpcUrls, }: {
25
25
  walletCluster?: SolanaClusterMoniker;
26
26
  } & SolanaRPCUrls) => string;
27
27
 
28
+ /**
29
+ * RPC Client Caching Module
30
+ *
31
+ * This module provides a caching mechanism for Solana RPC clients to optimize
32
+ * performance and resource usage by reusing existing client instances.
33
+ *
34
+ * @module RpcClientCache
35
+ */
36
+
37
+ /**
38
+ * Creates or retrieves a cached Solana RPC client instance
39
+ *
40
+ * This function implements a caching mechanism for Solana RPC clients to:
41
+ * - Avoid redundant client instance creation
42
+ * - Optimize memory usage
43
+ * - Maintain consistent client instances throughout the application
44
+ *
45
+ * @param rpcUrlOrMoniker - RPC endpoint URL or cluster moniker (e.g., 'mainnet', 'devnet')
46
+ * @returns Cached or newly created Solana RPC client instance
47
+ * @throws Error if unable to resolve a valid RPC URL
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * // Using cluster moniker
52
+ * const mainnetClient = createSolanaClientWithCache('mainnet');
53
+ *
54
+ * // Using custom RPC URL
55
+ * const customClient = createSolanaClientWithCache('https://my-rpc.example.com');
56
+ * ```
57
+ */
58
+ declare const createSolanaClientWithCache: (rpcUrlOrMoniker: string) => SolanaClient;
59
+
28
60
  /**
29
61
  * Retrieves a cached RPC client for a given URL or cluster moniker.
30
62
  * If no cached client exists, it creates a new instance.
@@ -35,6 +67,13 @@ declare const getRpcUrlForCluster: ({ cluster, walletCluster, rpcUrls, }: {
35
67
  */
36
68
  declare const createSolanaRPC: (rpcUrlOrMoniker: string) => Rpc<SolanaRpcApi>;
37
69
 
70
+ /**
71
+ * The default RPC URLs for each Solana cluster.
72
+ * Not all clusters need to be defined; undefined ones will fall back to other logic.
73
+ * @internal
74
+ */
75
+ declare const defaultRpcUrlsByMoniker: Partial<Record<SolanaClusterMoniker, string>>;
76
+
38
77
  /**
39
78
  * @file This file contains a utility function for generating Solana transaction explorer links.
40
79
  */
@@ -48,4 +87,4 @@ declare const createSolanaRPC: (rpcUrlOrMoniker: string) => Rpc<SolanaRpcApi>;
48
87
  */
49
88
  declare const getSolanaExplorerLink: (url?: string, cluster?: SolanaClusterMoniker) => string;
50
89
 
51
- export { type SolanaRPCUrls, createSolanaRPC, getCluster, getRpcUrlForCluster, getSolanaExplorerLink };
90
+ export { type SolanaRPCUrls, createSolanaClientWithCache, createSolanaRPC, defaultRpcUrlsByMoniker, getCluster, getRpcUrlForCluster, getSolanaExplorerLink };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { SolanaClusterMoniker, Rpc, SolanaRpcApi } from 'gill';
1
+ import { SolanaClusterMoniker, SolanaClient, Rpc, SolanaRpcApi } from 'gill';
2
2
 
3
3
  type SolanaRPCUrls = {
4
4
  rpcUrls: Partial<Record<SolanaClusterMoniker, string>>;
@@ -25,6 +25,38 @@ declare const getRpcUrlForCluster: ({ cluster, walletCluster, rpcUrls, }: {
25
25
  walletCluster?: SolanaClusterMoniker;
26
26
  } & SolanaRPCUrls) => string;
27
27
 
28
+ /**
29
+ * RPC Client Caching Module
30
+ *
31
+ * This module provides a caching mechanism for Solana RPC clients to optimize
32
+ * performance and resource usage by reusing existing client instances.
33
+ *
34
+ * @module RpcClientCache
35
+ */
36
+
37
+ /**
38
+ * Creates or retrieves a cached Solana RPC client instance
39
+ *
40
+ * This function implements a caching mechanism for Solana RPC clients to:
41
+ * - Avoid redundant client instance creation
42
+ * - Optimize memory usage
43
+ * - Maintain consistent client instances throughout the application
44
+ *
45
+ * @param rpcUrlOrMoniker - RPC endpoint URL or cluster moniker (e.g., 'mainnet', 'devnet')
46
+ * @returns Cached or newly created Solana RPC client instance
47
+ * @throws Error if unable to resolve a valid RPC URL
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * // Using cluster moniker
52
+ * const mainnetClient = createSolanaClientWithCache('mainnet');
53
+ *
54
+ * // Using custom RPC URL
55
+ * const customClient = createSolanaClientWithCache('https://my-rpc.example.com');
56
+ * ```
57
+ */
58
+ declare const createSolanaClientWithCache: (rpcUrlOrMoniker: string) => SolanaClient;
59
+
28
60
  /**
29
61
  * Retrieves a cached RPC client for a given URL or cluster moniker.
30
62
  * If no cached client exists, it creates a new instance.
@@ -35,6 +67,13 @@ declare const getRpcUrlForCluster: ({ cluster, walletCluster, rpcUrls, }: {
35
67
  */
36
68
  declare const createSolanaRPC: (rpcUrlOrMoniker: string) => Rpc<SolanaRpcApi>;
37
69
 
70
+ /**
71
+ * The default RPC URLs for each Solana cluster.
72
+ * Not all clusters need to be defined; undefined ones will fall back to other logic.
73
+ * @internal
74
+ */
75
+ declare const defaultRpcUrlsByMoniker: Partial<Record<SolanaClusterMoniker, string>>;
76
+
38
77
  /**
39
78
  * @file This file contains a utility function for generating Solana transaction explorer links.
40
79
  */
@@ -48,4 +87,4 @@ declare const createSolanaRPC: (rpcUrlOrMoniker: string) => Rpc<SolanaRpcApi>;
48
87
  */
49
88
  declare const getSolanaExplorerLink: (url?: string, cluster?: SolanaClusterMoniker) => string;
50
89
 
51
- export { type SolanaRPCUrls, createSolanaRPC, getCluster, getRpcUrlForCluster, getSolanaExplorerLink };
90
+ export { type SolanaRPCUrls, createSolanaClientWithCache, createSolanaRPC, defaultRpcUrlsByMoniker, getCluster, getRpcUrlForCluster, getSolanaExplorerLink };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- 'use strict';var gill=require('gill');var c=({cluster:t,walletCluster:n})=>{let e="mainnet";return t?t.includes(":")?t.split(":")[1]:t:n??e},u=({cluster:t,walletCluster:n,rpcUrls:e})=>e[n??t]??"https://api.mainnet-beta.solana.com/";function l(t){try{return new URL(t),!0}catch{return false}}var i={mainnet:"https://api.mainnet-beta.solana.com",devnet:"https://api.devnet.solana.com",testnet:"https://api.testnet.solana.com"},r=new Map,g=t=>{if(r.has(t))return r.get(t);let n=l(t)?t:i[t];if(!n)throw new Error(`Unable to resolve RPC URL for input: "${t}". Ensure it's a valid URL or known moniker.`);let e=gill.createSolanaRpc(n);return r.set(t,e),e};var h=(t,n)=>{let e=gill.getExplorerLink(),a=e.endsWith("/")?e.slice(0,-1):e,o=n?`?cluster=${n}`:"";return `${a}${t||"/"}${o}`};
2
- exports.createSolanaRPC=g;exports.getCluster=c;exports.getRpcUrlForCluster=u;exports.getSolanaExplorerLink=h;//# sourceMappingURL=index.js.map
1
+ 'use strict';var gill=require('gill');var C=({cluster:t,walletCluster:n})=>{let e="mainnet";return t?t.includes(":")?t.split(":")[1]:t:n??e},f=({cluster:t,walletCluster:n,rpcUrls:e})=>e[n??t]??"https://api.mainnet-beta.solana.com/";var o={mainnet:"https://api.mainnet-beta.solana.com",devnet:"https://api.devnet.solana.com",testnet:"https://api.testnet.solana.com"};function u(t){try{return new URL(t),!0}catch{return false}}var a=new Map,x=t=>{if(a.has(t))return a.get(t);let n=u(t)?t:o[t];if(!n)throw new Error(`Unable to resolve RPC URL for input: "${t}". Ensure it's a valid URL or known moniker.`);let e=gill.createSolanaClient({urlOrMoniker:n});return a.set(t,e),e};function c(t){try{return new URL(t),!0}catch{return false}}var r=new Map,P=t=>{if(r.has(t))return r.get(t);let n=c(t)?t:o[t];if(!n)throw new Error(`Unable to resolve RPC URL for input: "${t}". Ensure it's a valid URL or known moniker.`);let e=gill.createSolanaRpc(n);return r.set(t,e),e};var $=(t,n)=>{let e=gill.getExplorerLink(),s=e.endsWith("/")?e.slice(0,-1):e,l=n?`?cluster=${n}`:"";return `${s}${t||"/"}${l}`};
2
+ exports.createSolanaClientWithCache=x;exports.createSolanaRPC=P;exports.defaultRpcUrlsByMoniker=o;exports.getCluster=C;exports.getRpcUrlForCluster=f;exports.getSolanaExplorerLink=$;//# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/clusterHelpers.ts","../src/utils/createSolanaRPC.ts","../src/utils/getSolanaExplorerLink.ts"],"names":["getCluster","cluster","walletCluster","defaultCluster","getRpcUrlForCluster","rpcUrls","isValidUrl","str","defaultRpcUrlsByMoniker","rpcCache","createSolanaRPC","rpcUrlOrMoniker","rpcUrl","newRpc","createSolanaRpc","getSolanaExplorerLink","url","baseUrl","getExplorerLink","sanitizedBaseUrl","clusterParam"],"mappings":"sCAWO,IAAMA,EAAa,CAAC,CAAE,OAAA,CAAAC,CAAAA,CAAS,cAAAC,CAAc,CAAA,GAAoD,CACtG,IAAMC,EAAuC,SAAA,CAC7C,OAAKF,CAAAA,CAGGA,CAAAA,CAAQ,SAAS,GAAG,CAAA,CAAIA,CAAAA,CAAQ,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,CAAIA,CAAAA,CAF/CC,GAAiBC,CAG5B,CAAA,CAOaC,CAAAA,CAAsB,CAAC,CAClC,OAAA,CAAAH,CAAAA,CACA,cAAAC,CAAAA,CACA,OAAA,CAAAG,CACF,CAAA,GAESA,CAAAA,CADeH,CAAAA,EAAiBD,CACX,GAAK,uCCrBnC,SAASK,CAAAA,CAAWC,CAAAA,CAAsB,CACxC,GAAI,CACF,OAAA,IAAI,GAAA,CAAIA,CAAG,EACJ,CAAA,CACT,CAAA,KAAQ,CACN,OAAO,MACT,CACF,CAOA,IAAMC,CAAAA,CAAyE,CAC7E,OAAA,CAAS,qCAAA,CACT,MAAA,CAAQ,+BAAA,CACR,QAAS,gCACX,CAAA,CAMMC,EAAW,IAAI,GAAA,CAURC,EAAmBC,CAAAA,EAA+C,CAE7E,GAAIF,CAAAA,CAAS,IAAIE,CAAe,CAAA,CAC9B,OAAOF,CAAAA,CAAS,IAAIE,CAAe,CAAA,CAGrC,IAAMC,CAAAA,CAASN,EAAWK,CAAe,CAAA,CACrCA,CAAAA,CACAH,CAAAA,CAAwBG,CAAuC,CAAA,CAGnE,GAAI,CAACC,CAAAA,CACH,MAAM,IAAI,KAAA,CACR,CAAA,sCAAA,EAAyCD,CAAe,8CAC1D,CAAA,CAIF,IAAME,CAAAA,CAASC,oBAAAA,CAAgBF,CAAM,CAAA,CAGrC,OAAAH,EAAS,GAAA,CAAIE,CAAAA,CAAiBE,CAAM,CAAA,CAC7BA,CACT,ECpDO,IAAME,CAAAA,CAAwB,CAACC,CAAAA,CAAcf,CAAAA,GAA2C,CAE7F,IAAMgB,EAAUC,oBAAAA,EAAgB,CAC1BC,EAAmBF,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,CAAIA,CAAAA,CAAQ,KAAA,CAAM,CAAA,CAAG,EAAE,CAAA,CAAIA,CAAAA,CAGlEG,CAAAA,CAAenB,CAAAA,CAAU,YAAYA,CAAO,CAAA,CAAA,CAAK,EAAA,CAEvD,OAAO,GAAGkB,CAAgB,CAAA,EAAGH,GAAY,GAAG,CAAA,EAAGI,CAAY,CAAA,CAC7D","file":"index.js","sourcesContent":["import type { SolanaClusterMoniker } from 'gill';\n\nimport { SolanaRPCUrls } from '../types';\n\n/**\n * Safely extracts the cluster moniker from a chain identifier.\n * Handles both full chain IDs ('solana:mainnet-beta') and simple monikers ('mainnet-beta').\n * @returns The extracted cluster moniker.\n * @param walletCluster\n * @param cluster\n */\nexport const getCluster = ({ cluster, walletCluster }: { cluster?: string; walletCluster?: string }) => {\n const defaultCluster: SolanaClusterMoniker = 'mainnet';\n if (!cluster) {\n return walletCluster ?? defaultCluster;\n }\n return (cluster.includes(':') ? cluster.split(':')[1] : cluster) as SolanaClusterMoniker;\n};\n\n/**\n * Retrieves the configured RPC URL for a given cluster moniker.\n * @param cluster The target cluster. Defaults to the wallet's active chain.\n * @returns The RPC URL or undefined if not found.\n */\nexport const getRpcUrlForCluster = ({\n cluster,\n walletCluster,\n rpcUrls,\n}: { cluster: SolanaClusterMoniker; walletCluster?: SolanaClusterMoniker } & SolanaRPCUrls) => {\n const targetCluster = walletCluster ?? cluster;\n return rpcUrls[targetCluster] ?? 'https://api.mainnet-beta.solana.com/';\n};\n","// --- RPC Client Caching ---\n\nimport { createSolanaRpc, Rpc, SolanaClusterMoniker, SolanaRpcApi } from 'gill';\n\n/**\n * Validates whether a string is a properly formatted URL.\n * @param str - The string to validate.\n * @returns True if the string is a valid URL, otherwise false.\n */\nfunction isValidUrl(str: string): boolean {\n try {\n new URL(str);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * The default RPC URLs for each Solana cluster.\n * Not all clusters need to be defined; undefined ones will fall back to other logic.\n * @internal\n */\nconst defaultRpcUrlsByMoniker: Partial<Record<SolanaClusterMoniker, string>> = {\n mainnet: 'https://api.mainnet-beta.solana.com',\n devnet: 'https://api.devnet.solana.com',\n testnet: 'https://api.testnet.solana.com',\n};\n\n/**\n * An in-memory cache for RPC clients to avoid redundant instance creation.\n * @internal\n */\nconst rpcCache = new Map<string, Rpc<SolanaRpcApi>>();\n\n/**\n * Retrieves a cached RPC client for a given URL or cluster moniker.\n * If no cached client exists, it creates a new instance.\n *\n * @param rpcUrlOrMoniker - Either a full RPC URL or a cluster moniker like 'mainnet'.\n * @returns The RPC client instance.\n * @internal\n */\nexport const createSolanaRPC = (rpcUrlOrMoniker: string): Rpc<SolanaRpcApi> => {\n // Check the cache first for an existing RPC instance.\n if (rpcCache.has(rpcUrlOrMoniker)) {\n return rpcCache.get(rpcUrlOrMoniker)!;\n }\n // Determine the RPC URL: validate if it's a full URL or fall back to default list.\n const rpcUrl = isValidUrl(rpcUrlOrMoniker)\n ? rpcUrlOrMoniker\n : defaultRpcUrlsByMoniker[rpcUrlOrMoniker as SolanaClusterMoniker];\n\n // If no valid RPC URL could be resolved, default to the mainnet URL.\n if (!rpcUrl) {\n throw new Error(\n `Unable to resolve RPC URL for input: \"${rpcUrlOrMoniker}\". Ensure it's a valid URL or known moniker.`,\n );\n }\n\n // Create a new RPC client instance.\n const newRpc = createSolanaRpc(rpcUrl);\n\n // Cache the new instance and return it.\n rpcCache.set(rpcUrlOrMoniker, newRpc);\n return newRpc;\n};\n","/**\n * @file This file contains a utility function for generating Solana transaction explorer links.\n */\n\nimport type { SolanaClusterMoniker } from 'gill';\nimport { getExplorerLink } from 'gill';\n\n/**\n * Generates a full URL to a transaction on a Solana explorer like Solscan.\n *\n * @param {string} url - The url after baseUrl.\n * @param {SolanaCluster} [cluster] - The optional cluster name ('devnet', 'testnet') to add as a query parameter.\n * @returns {string} The full URL to the transaction on the explorer.\n */\nexport const getSolanaExplorerLink = (url?: string, cluster?: SolanaClusterMoniker): string => {\n // Ensure there are no trailing slashes on the base URL for clean URL construction.\n const baseUrl = getExplorerLink();\n const sanitizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n\n // Build the cluster query parameter if provided.\n const clusterParam = cluster ? `?cluster=${cluster}` : '';\n\n return `${sanitizedBaseUrl}${url ? url : '/'}${clusterParam}`;\n};\n"]}
1
+ {"version":3,"sources":["../src/utils/clusterHelpers.ts","../src/utils/defaultRpcUrlsByMoniker.ts","../src/utils/createSolanaClientWithCache.ts","../src/utils/createSolanaRPC.ts","../src/utils/getSolanaExplorerLink.ts"],"names":["getCluster","cluster","walletCluster","defaultCluster","getRpcUrlForCluster","rpcUrls","defaultRpcUrlsByMoniker","isValidUrl","str","clientsCache","createSolanaClientWithCache","rpcUrlOrMoniker","rpcUrl","newClient","createSolanaClient","rpcCache","createSolanaRPC","newRpc","createSolanaRpc","getSolanaExplorerLink","url","baseUrl","getExplorerLink","sanitizedBaseUrl","clusterParam"],"mappings":"sCAWO,IAAMA,CAAAA,CAAa,CAAC,CAAE,OAAA,CAAAC,CAAAA,CAAS,cAAAC,CAAc,CAAA,GAAoD,CACtG,IAAMC,CAAAA,CAAuC,SAAA,CAC7C,OAAKF,CAAAA,CAGGA,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,CAAIA,CAAAA,CAAQ,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,CAAIA,CAAAA,CAF/CC,CAAAA,EAAiBC,CAG5B,EAOaC,CAAAA,CAAsB,CAAC,CAClC,OAAA,CAAAH,CAAAA,CACA,aAAA,CAAAC,CAAAA,CACA,OAAA,CAAAG,CACF,CAAA,GAESA,CAAAA,CADeH,CAAAA,EAAiBD,CACX,CAAA,EAAK,uCCvB5B,IAAMK,CAAAA,CAAyE,CACpF,OAAA,CAAS,qCAAA,CACT,MAAA,CAAQ,+BAAA,CACR,OAAA,CAAS,gCACX,ECcA,SAASC,CAAAA,CAAWC,CAAAA,CAAsB,CACxC,GAAI,CACF,OAAA,IAAI,GAAA,CAAIA,CAAG,CAAA,CACJ,CAAA,CACT,CAAA,KAAQ,CACN,OAAO,MACT,CACF,CAQA,IAAMC,CAAAA,CAAe,IAAI,GAAA,CAuBZC,CAAAA,CAA+BC,CAAAA,EAA0C,CAEpF,GAAIF,CAAAA,CAAa,GAAA,CAAIE,CAAe,CAAA,CAClC,OAAOF,EAAa,GAAA,CAAIE,CAAe,CAAA,CAIzC,IAAMC,CAAAA,CAASL,CAAAA,CAAWI,CAAe,CAAA,CACrCA,CAAAA,CACAL,CAAAA,CAAwBK,CAAuC,CAAA,CAGnE,GAAI,CAACC,EACH,MAAM,IAAI,KAAA,CACR,CAAA,sCAAA,EAAyCD,CAAe,CAAA,4CAAA,CAC1D,CAAA,CAIF,IAAME,CAAAA,CAAYC,uBAAAA,CAAmB,CAAE,YAAA,CAAcF,CAAO,CAAC,EAG7D,OAAAH,CAAAA,CAAa,GAAA,CAAIE,CAAAA,CAAiBE,CAAS,CAAA,CACpCA,CACT,EC5EA,SAASN,CAAAA,CAAWC,EAAsB,CACxC,GAAI,CACF,OAAA,IAAI,GAAA,CAAIA,CAAG,CAAA,CACJ,CAAA,CACT,CAAA,KAAQ,CACN,OAAO,MACT,CACF,KAMMO,CAAAA,CAAW,IAAI,GAAA,CAURC,CAAAA,CAAmBL,CAAAA,EAA+C,CAE7E,GAAII,CAAAA,CAAS,GAAA,CAAIJ,CAAe,CAAA,CAC9B,OAAOI,CAAAA,CAAS,GAAA,CAAIJ,CAAe,CAAA,CAGrC,IAAMC,CAAAA,CAASL,CAAAA,CAAWI,CAAe,CAAA,CACrCA,CAAAA,CACAL,CAAAA,CAAwBK,CAAuC,CAAA,CAGnE,GAAI,CAACC,CAAAA,CACH,MAAM,IAAI,KAAA,CACR,CAAA,sCAAA,EAAyCD,CAAe,CAAA,4CAAA,CAC1D,CAAA,CAIF,IAAMM,CAAAA,CAASC,oBAAAA,CAAgBN,CAAM,CAAA,CAGrC,OAAAG,CAAAA,CAAS,GAAA,CAAIJ,CAAAA,CAAiBM,CAAM,CAAA,CAC7BA,CACT,EC3CO,IAAME,CAAAA,CAAwB,CAACC,CAAAA,CAAcnB,CAAAA,GAA2C,CAE7F,IAAMoB,EAAUC,oBAAAA,EAAgB,CAC1BC,CAAAA,CAAmBF,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,CAAIA,CAAAA,CAAQ,KAAA,CAAM,CAAA,CAAG,EAAE,CAAA,CAAIA,CAAAA,CAGlEG,CAAAA,CAAevB,EAAU,CAAA,SAAA,EAAYA,CAAO,CAAA,CAAA,CAAK,EAAA,CAEvD,OAAO,CAAA,EAAGsB,CAAgB,CAAA,EAAGH,CAAAA,EAAY,GAAG,CAAA,EAAGI,CAAY,CAAA,CAC7D","file":"index.js","sourcesContent":["import type { SolanaClusterMoniker } from 'gill';\n\nimport { SolanaRPCUrls } from '../types';\n\n/**\n * Safely extracts the cluster moniker from a chain identifier.\n * Handles both full chain IDs ('solana:mainnet-beta') and simple monikers ('mainnet-beta').\n * @returns The extracted cluster moniker.\n * @param walletCluster\n * @param cluster\n */\nexport const getCluster = ({ cluster, walletCluster }: { cluster?: string; walletCluster?: string }) => {\n const defaultCluster: SolanaClusterMoniker = 'mainnet';\n if (!cluster) {\n return walletCluster ?? defaultCluster;\n }\n return (cluster.includes(':') ? cluster.split(':')[1] : cluster) as SolanaClusterMoniker;\n};\n\n/**\n * Retrieves the configured RPC URL for a given cluster moniker.\n * @param cluster The target cluster. Defaults to the wallet's active chain.\n * @returns The RPC URL or undefined if not found.\n */\nexport const getRpcUrlForCluster = ({\n cluster,\n walletCluster,\n rpcUrls,\n}: { cluster: SolanaClusterMoniker; walletCluster?: SolanaClusterMoniker } & SolanaRPCUrls) => {\n const targetCluster = walletCluster ?? cluster;\n return rpcUrls[targetCluster] ?? 'https://api.mainnet-beta.solana.com/';\n};\n","import { SolanaClusterMoniker } from 'gill';\n\n/**\n * The default RPC URLs for each Solana cluster.\n * Not all clusters need to be defined; undefined ones will fall back to other logic.\n * @internal\n */\nexport const defaultRpcUrlsByMoniker: Partial<Record<SolanaClusterMoniker, string>> = {\n mainnet: 'https://api.mainnet-beta.solana.com',\n devnet: 'https://api.devnet.solana.com',\n testnet: 'https://api.testnet.solana.com',\n};\n","/**\n * RPC Client Caching Module\n *\n * This module provides a caching mechanism for Solana RPC clients to optimize\n * performance and resource usage by reusing existing client instances.\n *\n * @module RpcClientCache\n */\n\nimport { createSolanaClient, SolanaClient, SolanaClusterMoniker } from 'gill';\n\nimport { defaultRpcUrlsByMoniker } from './defaultRpcUrlsByMoniker';\n\n/**\n * Validates if a string represents a properly formatted URL\n *\n * @param str - String to validate as URL\n * @returns Boolean indicating if the string is a valid URL\n *\n * @example\n * ```typescript\n * isValidUrl('https://api.mainnet-beta.solana.com') // returns true\n * isValidUrl('not-a-url') // returns false\n * ```\n */\nfunction isValidUrl(str: string): boolean {\n try {\n new URL(str);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * In-memory cache storage for Solana client instances\n * Maps Solana URLs or monikers to their corresponding client instances\n *\n * @internal\n */\nconst clientsCache = new Map<string, SolanaClient>();\n\n/**\n * Creates or retrieves a cached Solana RPC client instance\n *\n * This function implements a caching mechanism for Solana RPC clients to:\n * - Avoid redundant client instance creation\n * - Optimize memory usage\n * - Maintain consistent client instances throughout the application\n *\n * @param rpcUrlOrMoniker - RPC endpoint URL or cluster moniker (e.g., 'mainnet', 'devnet')\n * @returns Cached or newly created Solana RPC client instance\n * @throws Error if unable to resolve a valid RPC URL\n *\n * @example\n * ```typescript\n * // Using cluster moniker\n * const mainnetClient = createSolanaClientWithCache('mainnet');\n *\n * // Using custom RPC URL\n * const customClient = createSolanaClientWithCache('https://my-rpc.example.com');\n * ```\n */\nexport const createSolanaClientWithCache = (rpcUrlOrMoniker: string): SolanaClient => {\n // Return existing client instance if available in cache\n if (clientsCache.has(rpcUrlOrMoniker)) {\n return clientsCache.get(rpcUrlOrMoniker)!;\n }\n\n // Resolve RPC URL from input: direct URL or cluster moniker\n const rpcUrl = isValidUrl(rpcUrlOrMoniker)\n ? rpcUrlOrMoniker\n : defaultRpcUrlsByMoniker[rpcUrlOrMoniker as SolanaClusterMoniker];\n\n // Validate resolved RPC URL\n if (!rpcUrl) {\n throw new Error(\n `Unable to resolve RPC URL for input: \"${rpcUrlOrMoniker}\". Ensure it's a valid URL or known moniker.`,\n );\n }\n\n // Create new client instance with resolved URL\n const newClient = createSolanaClient({ urlOrMoniker: rpcUrl });\n\n // Cache and return the new instance\n clientsCache.set(rpcUrlOrMoniker, newClient);\n return newClient;\n};\n","// --- RPC Client Caching ---\n\nimport { createSolanaRpc, Rpc, SolanaClusterMoniker, SolanaRpcApi } from 'gill';\n\nimport { defaultRpcUrlsByMoniker } from './defaultRpcUrlsByMoniker';\n\n/**\n * Validates whether a string is a properly formatted URL.\n * @param str - The string to validate.\n * @returns True if the string is a valid URL, otherwise false.\n */\nfunction isValidUrl(str: string): boolean {\n try {\n new URL(str);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * An in-memory cache for RPC clients to avoid redundant instance creation.\n * @internal\n */\nconst rpcCache = new Map<string, Rpc<SolanaRpcApi>>();\n\n/**\n * Retrieves a cached RPC client for a given URL or cluster moniker.\n * If no cached client exists, it creates a new instance.\n *\n * @param rpcUrlOrMoniker - Either a full RPC URL or a cluster moniker like 'mainnet'.\n * @returns The RPC client instance.\n * @internal\n */\nexport const createSolanaRPC = (rpcUrlOrMoniker: string): Rpc<SolanaRpcApi> => {\n // Check the cache first for an existing RPC instance.\n if (rpcCache.has(rpcUrlOrMoniker)) {\n return rpcCache.get(rpcUrlOrMoniker)!;\n }\n // Determine the RPC URL: validate if it's a full URL or fall back to default list.\n const rpcUrl = isValidUrl(rpcUrlOrMoniker)\n ? rpcUrlOrMoniker\n : defaultRpcUrlsByMoniker[rpcUrlOrMoniker as SolanaClusterMoniker];\n\n // If no valid RPC URL could be resolved, default to the mainnet URL.\n if (!rpcUrl) {\n throw new Error(\n `Unable to resolve RPC URL for input: \"${rpcUrlOrMoniker}\". Ensure it's a valid URL or known moniker.`,\n );\n }\n\n // Create a new RPC client instance.\n const newRpc = createSolanaRpc(rpcUrl);\n\n // Cache the new instance and return it.\n rpcCache.set(rpcUrlOrMoniker, newRpc);\n return newRpc;\n};\n","/**\n * @file This file contains a utility function for generating Solana transaction explorer links.\n */\n\nimport type { SolanaClusterMoniker } from 'gill';\nimport { getExplorerLink } from 'gill';\n\n/**\n * Generates a full URL to a transaction on a Solana explorer like Solscan.\n *\n * @param {string} url - The url after baseUrl.\n * @param {SolanaCluster} [cluster] - The optional cluster name ('devnet', 'testnet') to add as a query parameter.\n * @returns {string} The full URL to the transaction on the explorer.\n */\nexport const getSolanaExplorerLink = (url?: string, cluster?: SolanaClusterMoniker): string => {\n // Ensure there are no trailing slashes on the base URL for clean URL construction.\n const baseUrl = getExplorerLink();\n const sanitizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n\n // Build the cluster query parameter if provided.\n const clusterParam = cluster ? `?cluster=${cluster}` : '';\n\n return `${sanitizedBaseUrl}${url ? url : '/'}${clusterParam}`;\n};\n"]}
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import {createSolanaRpc,getExplorerLink}from'gill';var c=({cluster:t,walletCluster:n})=>{let e="mainnet";return t?t.includes(":")?t.split(":")[1]:t:n??e},u=({cluster:t,walletCluster:n,rpcUrls:e})=>e[n??t]??"https://api.mainnet-beta.solana.com/";function l(t){try{return new URL(t),!0}catch{return false}}var i={mainnet:"https://api.mainnet-beta.solana.com",devnet:"https://api.devnet.solana.com",testnet:"https://api.testnet.solana.com"},r=new Map,g=t=>{if(r.has(t))return r.get(t);let n=l(t)?t:i[t];if(!n)throw new Error(`Unable to resolve RPC URL for input: "${t}". Ensure it's a valid URL or known moniker.`);let e=createSolanaRpc(n);return r.set(t,e),e};var h=(t,n)=>{let e=getExplorerLink(),a=e.endsWith("/")?e.slice(0,-1):e,o=n?`?cluster=${n}`:"";return `${a}${t||"/"}${o}`};
2
- export{g as createSolanaRPC,c as getCluster,u as getRpcUrlForCluster,h as getSolanaExplorerLink};//# sourceMappingURL=index.mjs.map
1
+ import {createSolanaClient,createSolanaRpc,getExplorerLink}from'gill';var C=({cluster:t,walletCluster:n})=>{let e="mainnet";return t?t.includes(":")?t.split(":")[1]:t:n??e},f=({cluster:t,walletCluster:n,rpcUrls:e})=>e[n??t]??"https://api.mainnet-beta.solana.com/";var o={mainnet:"https://api.mainnet-beta.solana.com",devnet:"https://api.devnet.solana.com",testnet:"https://api.testnet.solana.com"};function u(t){try{return new URL(t),!0}catch{return false}}var a=new Map,x=t=>{if(a.has(t))return a.get(t);let n=u(t)?t:o[t];if(!n)throw new Error(`Unable to resolve RPC URL for input: "${t}". Ensure it's a valid URL or known moniker.`);let e=createSolanaClient({urlOrMoniker:n});return a.set(t,e),e};function c(t){try{return new URL(t),!0}catch{return false}}var r=new Map,P=t=>{if(r.has(t))return r.get(t);let n=c(t)?t:o[t];if(!n)throw new Error(`Unable to resolve RPC URL for input: "${t}". Ensure it's a valid URL or known moniker.`);let e=createSolanaRpc(n);return r.set(t,e),e};var $=(t,n)=>{let e=getExplorerLink(),s=e.endsWith("/")?e.slice(0,-1):e,l=n?`?cluster=${n}`:"";return `${s}${t||"/"}${l}`};
2
+ export{x as createSolanaClientWithCache,P as createSolanaRPC,o as defaultRpcUrlsByMoniker,C as getCluster,f as getRpcUrlForCluster,$ as getSolanaExplorerLink};//# sourceMappingURL=index.mjs.map
3
3
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/clusterHelpers.ts","../src/utils/createSolanaRPC.ts","../src/utils/getSolanaExplorerLink.ts"],"names":["getCluster","cluster","walletCluster","defaultCluster","getRpcUrlForCluster","rpcUrls","isValidUrl","str","defaultRpcUrlsByMoniker","rpcCache","createSolanaRPC","rpcUrlOrMoniker","rpcUrl","newRpc","createSolanaRpc","getSolanaExplorerLink","url","baseUrl","getExplorerLink","sanitizedBaseUrl","clusterParam"],"mappings":"mDAWO,IAAMA,EAAa,CAAC,CAAE,OAAA,CAAAC,CAAAA,CAAS,cAAAC,CAAc,CAAA,GAAoD,CACtG,IAAMC,EAAuC,SAAA,CAC7C,OAAKF,CAAAA,CAGGA,CAAAA,CAAQ,SAAS,GAAG,CAAA,CAAIA,CAAAA,CAAQ,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,CAAIA,CAAAA,CAF/CC,GAAiBC,CAG5B,CAAA,CAOaC,CAAAA,CAAsB,CAAC,CAClC,OAAA,CAAAH,CAAAA,CACA,cAAAC,CAAAA,CACA,OAAA,CAAAG,CACF,CAAA,GAESA,CAAAA,CADeH,CAAAA,EAAiBD,CACX,GAAK,uCCrBnC,SAASK,CAAAA,CAAWC,CAAAA,CAAsB,CACxC,GAAI,CACF,OAAA,IAAI,GAAA,CAAIA,CAAG,EACJ,CAAA,CACT,CAAA,KAAQ,CACN,OAAO,MACT,CACF,CAOA,IAAMC,CAAAA,CAAyE,CAC7E,OAAA,CAAS,qCAAA,CACT,MAAA,CAAQ,+BAAA,CACR,QAAS,gCACX,CAAA,CAMMC,EAAW,IAAI,GAAA,CAURC,EAAmBC,CAAAA,EAA+C,CAE7E,GAAIF,CAAAA,CAAS,IAAIE,CAAe,CAAA,CAC9B,OAAOF,CAAAA,CAAS,IAAIE,CAAe,CAAA,CAGrC,IAAMC,CAAAA,CAASN,EAAWK,CAAe,CAAA,CACrCA,CAAAA,CACAH,CAAAA,CAAwBG,CAAuC,CAAA,CAGnE,GAAI,CAACC,CAAAA,CACH,MAAM,IAAI,KAAA,CACR,CAAA,sCAAA,EAAyCD,CAAe,8CAC1D,CAAA,CAIF,IAAME,CAAAA,CAASC,eAAAA,CAAgBF,CAAM,CAAA,CAGrC,OAAAH,EAAS,GAAA,CAAIE,CAAAA,CAAiBE,CAAM,CAAA,CAC7BA,CACT,ECpDO,IAAME,CAAAA,CAAwB,CAACC,CAAAA,CAAcf,CAAAA,GAA2C,CAE7F,IAAMgB,EAAUC,eAAAA,EAAgB,CAC1BC,EAAmBF,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,CAAIA,CAAAA,CAAQ,KAAA,CAAM,CAAA,CAAG,EAAE,CAAA,CAAIA,CAAAA,CAGlEG,CAAAA,CAAenB,CAAAA,CAAU,YAAYA,CAAO,CAAA,CAAA,CAAK,EAAA,CAEvD,OAAO,GAAGkB,CAAgB,CAAA,EAAGH,GAAY,GAAG,CAAA,EAAGI,CAAY,CAAA,CAC7D","file":"index.mjs","sourcesContent":["import type { SolanaClusterMoniker } from 'gill';\n\nimport { SolanaRPCUrls } from '../types';\n\n/**\n * Safely extracts the cluster moniker from a chain identifier.\n * Handles both full chain IDs ('solana:mainnet-beta') and simple monikers ('mainnet-beta').\n * @returns The extracted cluster moniker.\n * @param walletCluster\n * @param cluster\n */\nexport const getCluster = ({ cluster, walletCluster }: { cluster?: string; walletCluster?: string }) => {\n const defaultCluster: SolanaClusterMoniker = 'mainnet';\n if (!cluster) {\n return walletCluster ?? defaultCluster;\n }\n return (cluster.includes(':') ? cluster.split(':')[1] : cluster) as SolanaClusterMoniker;\n};\n\n/**\n * Retrieves the configured RPC URL for a given cluster moniker.\n * @param cluster The target cluster. Defaults to the wallet's active chain.\n * @returns The RPC URL or undefined if not found.\n */\nexport const getRpcUrlForCluster = ({\n cluster,\n walletCluster,\n rpcUrls,\n}: { cluster: SolanaClusterMoniker; walletCluster?: SolanaClusterMoniker } & SolanaRPCUrls) => {\n const targetCluster = walletCluster ?? cluster;\n return rpcUrls[targetCluster] ?? 'https://api.mainnet-beta.solana.com/';\n};\n","// --- RPC Client Caching ---\n\nimport { createSolanaRpc, Rpc, SolanaClusterMoniker, SolanaRpcApi } from 'gill';\n\n/**\n * Validates whether a string is a properly formatted URL.\n * @param str - The string to validate.\n * @returns True if the string is a valid URL, otherwise false.\n */\nfunction isValidUrl(str: string): boolean {\n try {\n new URL(str);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * The default RPC URLs for each Solana cluster.\n * Not all clusters need to be defined; undefined ones will fall back to other logic.\n * @internal\n */\nconst defaultRpcUrlsByMoniker: Partial<Record<SolanaClusterMoniker, string>> = {\n mainnet: 'https://api.mainnet-beta.solana.com',\n devnet: 'https://api.devnet.solana.com',\n testnet: 'https://api.testnet.solana.com',\n};\n\n/**\n * An in-memory cache for RPC clients to avoid redundant instance creation.\n * @internal\n */\nconst rpcCache = new Map<string, Rpc<SolanaRpcApi>>();\n\n/**\n * Retrieves a cached RPC client for a given URL or cluster moniker.\n * If no cached client exists, it creates a new instance.\n *\n * @param rpcUrlOrMoniker - Either a full RPC URL or a cluster moniker like 'mainnet'.\n * @returns The RPC client instance.\n * @internal\n */\nexport const createSolanaRPC = (rpcUrlOrMoniker: string): Rpc<SolanaRpcApi> => {\n // Check the cache first for an existing RPC instance.\n if (rpcCache.has(rpcUrlOrMoniker)) {\n return rpcCache.get(rpcUrlOrMoniker)!;\n }\n // Determine the RPC URL: validate if it's a full URL or fall back to default list.\n const rpcUrl = isValidUrl(rpcUrlOrMoniker)\n ? rpcUrlOrMoniker\n : defaultRpcUrlsByMoniker[rpcUrlOrMoniker as SolanaClusterMoniker];\n\n // If no valid RPC URL could be resolved, default to the mainnet URL.\n if (!rpcUrl) {\n throw new Error(\n `Unable to resolve RPC URL for input: \"${rpcUrlOrMoniker}\". Ensure it's a valid URL or known moniker.`,\n );\n }\n\n // Create a new RPC client instance.\n const newRpc = createSolanaRpc(rpcUrl);\n\n // Cache the new instance and return it.\n rpcCache.set(rpcUrlOrMoniker, newRpc);\n return newRpc;\n};\n","/**\n * @file This file contains a utility function for generating Solana transaction explorer links.\n */\n\nimport type { SolanaClusterMoniker } from 'gill';\nimport { getExplorerLink } from 'gill';\n\n/**\n * Generates a full URL to a transaction on a Solana explorer like Solscan.\n *\n * @param {string} url - The url after baseUrl.\n * @param {SolanaCluster} [cluster] - The optional cluster name ('devnet', 'testnet') to add as a query parameter.\n * @returns {string} The full URL to the transaction on the explorer.\n */\nexport const getSolanaExplorerLink = (url?: string, cluster?: SolanaClusterMoniker): string => {\n // Ensure there are no trailing slashes on the base URL for clean URL construction.\n const baseUrl = getExplorerLink();\n const sanitizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n\n // Build the cluster query parameter if provided.\n const clusterParam = cluster ? `?cluster=${cluster}` : '';\n\n return `${sanitizedBaseUrl}${url ? url : '/'}${clusterParam}`;\n};\n"]}
1
+ {"version":3,"sources":["../src/utils/clusterHelpers.ts","../src/utils/defaultRpcUrlsByMoniker.ts","../src/utils/createSolanaClientWithCache.ts","../src/utils/createSolanaRPC.ts","../src/utils/getSolanaExplorerLink.ts"],"names":["getCluster","cluster","walletCluster","defaultCluster","getRpcUrlForCluster","rpcUrls","defaultRpcUrlsByMoniker","isValidUrl","str","clientsCache","createSolanaClientWithCache","rpcUrlOrMoniker","rpcUrl","newClient","createSolanaClient","rpcCache","createSolanaRPC","newRpc","createSolanaRpc","getSolanaExplorerLink","url","baseUrl","getExplorerLink","sanitizedBaseUrl","clusterParam"],"mappings":"sEAWO,IAAMA,CAAAA,CAAa,CAAC,CAAE,OAAA,CAAAC,CAAAA,CAAS,cAAAC,CAAc,CAAA,GAAoD,CACtG,IAAMC,CAAAA,CAAuC,SAAA,CAC7C,OAAKF,CAAAA,CAGGA,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,CAAIA,CAAAA,CAAQ,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,CAAIA,CAAAA,CAF/CC,CAAAA,EAAiBC,CAG5B,EAOaC,CAAAA,CAAsB,CAAC,CAClC,OAAA,CAAAH,CAAAA,CACA,aAAA,CAAAC,CAAAA,CACA,OAAA,CAAAG,CACF,CAAA,GAESA,CAAAA,CADeH,CAAAA,EAAiBD,CACX,CAAA,EAAK,uCCvB5B,IAAMK,CAAAA,CAAyE,CACpF,OAAA,CAAS,qCAAA,CACT,MAAA,CAAQ,+BAAA,CACR,OAAA,CAAS,gCACX,ECcA,SAASC,CAAAA,CAAWC,CAAAA,CAAsB,CACxC,GAAI,CACF,OAAA,IAAI,GAAA,CAAIA,CAAG,CAAA,CACJ,CAAA,CACT,CAAA,KAAQ,CACN,OAAO,MACT,CACF,CAQA,IAAMC,CAAAA,CAAe,IAAI,GAAA,CAuBZC,CAAAA,CAA+BC,CAAAA,EAA0C,CAEpF,GAAIF,CAAAA,CAAa,GAAA,CAAIE,CAAe,CAAA,CAClC,OAAOF,EAAa,GAAA,CAAIE,CAAe,CAAA,CAIzC,IAAMC,CAAAA,CAASL,CAAAA,CAAWI,CAAe,CAAA,CACrCA,CAAAA,CACAL,CAAAA,CAAwBK,CAAuC,CAAA,CAGnE,GAAI,CAACC,EACH,MAAM,IAAI,KAAA,CACR,CAAA,sCAAA,EAAyCD,CAAe,CAAA,4CAAA,CAC1D,CAAA,CAIF,IAAME,CAAAA,CAAYC,kBAAAA,CAAmB,CAAE,YAAA,CAAcF,CAAO,CAAC,EAG7D,OAAAH,CAAAA,CAAa,GAAA,CAAIE,CAAAA,CAAiBE,CAAS,CAAA,CACpCA,CACT,EC5EA,SAASN,CAAAA,CAAWC,EAAsB,CACxC,GAAI,CACF,OAAA,IAAI,GAAA,CAAIA,CAAG,CAAA,CACJ,CAAA,CACT,CAAA,KAAQ,CACN,OAAO,MACT,CACF,KAMMO,CAAAA,CAAW,IAAI,GAAA,CAURC,CAAAA,CAAmBL,CAAAA,EAA+C,CAE7E,GAAII,CAAAA,CAAS,GAAA,CAAIJ,CAAe,CAAA,CAC9B,OAAOI,CAAAA,CAAS,GAAA,CAAIJ,CAAe,CAAA,CAGrC,IAAMC,CAAAA,CAASL,CAAAA,CAAWI,CAAe,CAAA,CACrCA,CAAAA,CACAL,CAAAA,CAAwBK,CAAuC,CAAA,CAGnE,GAAI,CAACC,CAAAA,CACH,MAAM,IAAI,KAAA,CACR,CAAA,sCAAA,EAAyCD,CAAe,CAAA,4CAAA,CAC1D,CAAA,CAIF,IAAMM,CAAAA,CAASC,eAAAA,CAAgBN,CAAM,CAAA,CAGrC,OAAAG,CAAAA,CAAS,GAAA,CAAIJ,CAAAA,CAAiBM,CAAM,CAAA,CAC7BA,CACT,EC3CO,IAAME,CAAAA,CAAwB,CAACC,CAAAA,CAAcnB,CAAAA,GAA2C,CAE7F,IAAMoB,EAAUC,eAAAA,EAAgB,CAC1BC,CAAAA,CAAmBF,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,CAAIA,CAAAA,CAAQ,KAAA,CAAM,CAAA,CAAG,EAAE,CAAA,CAAIA,CAAAA,CAGlEG,CAAAA,CAAevB,EAAU,CAAA,SAAA,EAAYA,CAAO,CAAA,CAAA,CAAK,EAAA,CAEvD,OAAO,CAAA,EAAGsB,CAAgB,CAAA,EAAGH,CAAAA,EAAY,GAAG,CAAA,EAAGI,CAAY,CAAA,CAC7D","file":"index.mjs","sourcesContent":["import type { SolanaClusterMoniker } from 'gill';\n\nimport { SolanaRPCUrls } from '../types';\n\n/**\n * Safely extracts the cluster moniker from a chain identifier.\n * Handles both full chain IDs ('solana:mainnet-beta') and simple monikers ('mainnet-beta').\n * @returns The extracted cluster moniker.\n * @param walletCluster\n * @param cluster\n */\nexport const getCluster = ({ cluster, walletCluster }: { cluster?: string; walletCluster?: string }) => {\n const defaultCluster: SolanaClusterMoniker = 'mainnet';\n if (!cluster) {\n return walletCluster ?? defaultCluster;\n }\n return (cluster.includes(':') ? cluster.split(':')[1] : cluster) as SolanaClusterMoniker;\n};\n\n/**\n * Retrieves the configured RPC URL for a given cluster moniker.\n * @param cluster The target cluster. Defaults to the wallet's active chain.\n * @returns The RPC URL or undefined if not found.\n */\nexport const getRpcUrlForCluster = ({\n cluster,\n walletCluster,\n rpcUrls,\n}: { cluster: SolanaClusterMoniker; walletCluster?: SolanaClusterMoniker } & SolanaRPCUrls) => {\n const targetCluster = walletCluster ?? cluster;\n return rpcUrls[targetCluster] ?? 'https://api.mainnet-beta.solana.com/';\n};\n","import { SolanaClusterMoniker } from 'gill';\n\n/**\n * The default RPC URLs for each Solana cluster.\n * Not all clusters need to be defined; undefined ones will fall back to other logic.\n * @internal\n */\nexport const defaultRpcUrlsByMoniker: Partial<Record<SolanaClusterMoniker, string>> = {\n mainnet: 'https://api.mainnet-beta.solana.com',\n devnet: 'https://api.devnet.solana.com',\n testnet: 'https://api.testnet.solana.com',\n};\n","/**\n * RPC Client Caching Module\n *\n * This module provides a caching mechanism for Solana RPC clients to optimize\n * performance and resource usage by reusing existing client instances.\n *\n * @module RpcClientCache\n */\n\nimport { createSolanaClient, SolanaClient, SolanaClusterMoniker } from 'gill';\n\nimport { defaultRpcUrlsByMoniker } from './defaultRpcUrlsByMoniker';\n\n/**\n * Validates if a string represents a properly formatted URL\n *\n * @param str - String to validate as URL\n * @returns Boolean indicating if the string is a valid URL\n *\n * @example\n * ```typescript\n * isValidUrl('https://api.mainnet-beta.solana.com') // returns true\n * isValidUrl('not-a-url') // returns false\n * ```\n */\nfunction isValidUrl(str: string): boolean {\n try {\n new URL(str);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * In-memory cache storage for Solana client instances\n * Maps Solana URLs or monikers to their corresponding client instances\n *\n * @internal\n */\nconst clientsCache = new Map<string, SolanaClient>();\n\n/**\n * Creates or retrieves a cached Solana RPC client instance\n *\n * This function implements a caching mechanism for Solana RPC clients to:\n * - Avoid redundant client instance creation\n * - Optimize memory usage\n * - Maintain consistent client instances throughout the application\n *\n * @param rpcUrlOrMoniker - RPC endpoint URL or cluster moniker (e.g., 'mainnet', 'devnet')\n * @returns Cached or newly created Solana RPC client instance\n * @throws Error if unable to resolve a valid RPC URL\n *\n * @example\n * ```typescript\n * // Using cluster moniker\n * const mainnetClient = createSolanaClientWithCache('mainnet');\n *\n * // Using custom RPC URL\n * const customClient = createSolanaClientWithCache('https://my-rpc.example.com');\n * ```\n */\nexport const createSolanaClientWithCache = (rpcUrlOrMoniker: string): SolanaClient => {\n // Return existing client instance if available in cache\n if (clientsCache.has(rpcUrlOrMoniker)) {\n return clientsCache.get(rpcUrlOrMoniker)!;\n }\n\n // Resolve RPC URL from input: direct URL or cluster moniker\n const rpcUrl = isValidUrl(rpcUrlOrMoniker)\n ? rpcUrlOrMoniker\n : defaultRpcUrlsByMoniker[rpcUrlOrMoniker as SolanaClusterMoniker];\n\n // Validate resolved RPC URL\n if (!rpcUrl) {\n throw new Error(\n `Unable to resolve RPC URL for input: \"${rpcUrlOrMoniker}\". Ensure it's a valid URL or known moniker.`,\n );\n }\n\n // Create new client instance with resolved URL\n const newClient = createSolanaClient({ urlOrMoniker: rpcUrl });\n\n // Cache and return the new instance\n clientsCache.set(rpcUrlOrMoniker, newClient);\n return newClient;\n};\n","// --- RPC Client Caching ---\n\nimport { createSolanaRpc, Rpc, SolanaClusterMoniker, SolanaRpcApi } from 'gill';\n\nimport { defaultRpcUrlsByMoniker } from './defaultRpcUrlsByMoniker';\n\n/**\n * Validates whether a string is a properly formatted URL.\n * @param str - The string to validate.\n * @returns True if the string is a valid URL, otherwise false.\n */\nfunction isValidUrl(str: string): boolean {\n try {\n new URL(str);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * An in-memory cache for RPC clients to avoid redundant instance creation.\n * @internal\n */\nconst rpcCache = new Map<string, Rpc<SolanaRpcApi>>();\n\n/**\n * Retrieves a cached RPC client for a given URL or cluster moniker.\n * If no cached client exists, it creates a new instance.\n *\n * @param rpcUrlOrMoniker - Either a full RPC URL or a cluster moniker like 'mainnet'.\n * @returns The RPC client instance.\n * @internal\n */\nexport const createSolanaRPC = (rpcUrlOrMoniker: string): Rpc<SolanaRpcApi> => {\n // Check the cache first for an existing RPC instance.\n if (rpcCache.has(rpcUrlOrMoniker)) {\n return rpcCache.get(rpcUrlOrMoniker)!;\n }\n // Determine the RPC URL: validate if it's a full URL or fall back to default list.\n const rpcUrl = isValidUrl(rpcUrlOrMoniker)\n ? rpcUrlOrMoniker\n : defaultRpcUrlsByMoniker[rpcUrlOrMoniker as SolanaClusterMoniker];\n\n // If no valid RPC URL could be resolved, default to the mainnet URL.\n if (!rpcUrl) {\n throw new Error(\n `Unable to resolve RPC URL for input: \"${rpcUrlOrMoniker}\". Ensure it's a valid URL or known moniker.`,\n );\n }\n\n // Create a new RPC client instance.\n const newRpc = createSolanaRpc(rpcUrl);\n\n // Cache the new instance and return it.\n rpcCache.set(rpcUrlOrMoniker, newRpc);\n return newRpc;\n};\n","/**\n * @file This file contains a utility function for generating Solana transaction explorer links.\n */\n\nimport type { SolanaClusterMoniker } from 'gill';\nimport { getExplorerLink } from 'gill';\n\n/**\n * Generates a full URL to a transaction on a Solana explorer like Solscan.\n *\n * @param {string} url - The url after baseUrl.\n * @param {SolanaCluster} [cluster] - The optional cluster name ('devnet', 'testnet') to add as a query parameter.\n * @returns {string} The full URL to the transaction on the explorer.\n */\nexport const getSolanaExplorerLink = (url?: string, cluster?: SolanaClusterMoniker): string => {\n // Ensure there are no trailing slashes on the base URL for clean URL construction.\n const baseUrl = getExplorerLink();\n const sanitizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n\n // Build the cluster query parameter if provided.\n const clusterParam = cluster ? `?cluster=${cluster}` : '';\n\n return `${sanitizedBaseUrl}${url ? url : '/'}${clusterParam}`;\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tuwaio/orbit-solana",
3
- "version": "0.0.4",
3
+ "version": "1.0.0-fix-test-alpha.2.f8f5982",
4
4
  "private": false,
5
5
  "author": "Oleksandr Tkach",
6
6
  "license": "Apache-2.0",