@tuwaio/orbit-solana 0.2.13 → 0.3.0
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/README.md +20 -5
- package/dist/index.d.mts +40 -18
- package/dist/index.d.ts +40 -18
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@tuwaio/orbit-solana)
|
|
4
4
|
[](./LICENSE)
|
|
5
5
|
|
|
6
|
-
`@tuwaio/orbit-solana` provides concrete implementations of low-level Solana-specific communication primitives for Layer 2 (L2) of the TUWA Orbit stack. Engineered strictly on top of
|
|
6
|
+
`@tuwaio/orbit-solana` provides concrete implementations of low-level Solana-specific communication primitives for Layer 2 (L2) of the TUWA Orbit stack. Engineered strictly on top of **`@solana/kit`** (the official modern high-performance modular Solana JavaScript SDK), this package integrates Wallet Standard capabilities for discovery and persistent caching of RPC connections. It is fully compatible with instructions generated by **Codama** (`@codama/renderers-js`), completely eradicating legacy dependencies such as `gill` or `@solana/web3.js`.
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
## 🏛️ Core Capabilities
|
|
11
11
|
|
|
12
|
-
- **
|
|
12
|
+
- **Modular Solana RPC Caching:** Creates and caches high-performance Solana RPC connections (`createSolanaClientWithCache`, `createSolanaRPC`) powered by `@solana/kit` to optimize transaction dispatching and query pipelines.
|
|
13
13
|
- **Wallet Standard Integration:** Low-level discovery routines (`getAvailableSolanaConnectors`, `getConnectedSolanaConnector`) that strictly align with the `@wallet-standard/app` specifications.
|
|
14
|
-
- **
|
|
14
|
+
- **Codama Program Architecture:** Seamlessly executes instructions rendered by Codama (`kitImportStrategy: 'rootOnly'`) across Solana Devnet, Testnet, and Mainnet.
|
|
15
|
+
- **Profile Metadata Engine:** Resolves user-defined account descriptors (names, avatars, SNS resolution) directly from Solana accounts.
|
|
15
16
|
- **Cluster Parameter Resolution:** Maps Solana RPC clusters (mainnet, devnet, testnet) to explorer endpoints and RPC configurations.
|
|
16
17
|
|
|
17
18
|
---
|
|
@@ -19,11 +20,11 @@
|
|
|
19
20
|
## 💾 Installation
|
|
20
21
|
|
|
21
22
|
```bash
|
|
22
|
-
pnpm add @tuwaio/orbit-solana @tuwaio/orbit-core
|
|
23
|
+
pnpm add @tuwaio/orbit-solana @tuwaio/orbit-core @solana/kit @wallet-standard/app @wallet-standard/ui-core @wallet-standard/ui-registry
|
|
23
24
|
```
|
|
24
25
|
|
|
25
26
|
> [!IMPORTANT]
|
|
26
|
-
> `
|
|
27
|
+
> `@tuwaio/orbit-core` (>=0.2), `@solana/kit` (>=8.2), and `@wallet-standard` packages (v1.x) are peer dependencies and must be installed alongside `@tuwaio/orbit-solana`.
|
|
27
28
|
|
|
28
29
|
---
|
|
29
30
|
|
|
@@ -54,6 +55,20 @@ console.log(
|
|
|
54
55
|
);
|
|
55
56
|
```
|
|
56
57
|
|
|
58
|
+
### Working with Codama Generated Instructions
|
|
59
|
+
|
|
60
|
+
Use Codama (`@codama/renderers-js`) to generate type-safe instruction builders, then dispatch them using `@solana/kit` and `@tuwaio/orbit-solana`:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { createSolanaClientWithCache } from '@tuwaio/orbit-solana';
|
|
64
|
+
import { pipe } from '@solana/kit';
|
|
65
|
+
// Instruction generated via Codama
|
|
66
|
+
// import { getIncrementInstruction } from './generated';
|
|
67
|
+
|
|
68
|
+
const client = createSolanaClientWithCache({ rpcUrlOrMoniker: 'devnet' });
|
|
69
|
+
// Send and confirm using client.rpc and standard signers
|
|
70
|
+
```
|
|
71
|
+
|
|
57
72
|
---
|
|
58
73
|
|
|
59
74
|
## 🔧 API & Module Architecture
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Rpc, SolanaRpcApi, RpcSubscriptions, SolanaRpcSubscriptionsApi, MainnetUrl, DevnetUrl, TestnetUrl } from '@solana/kit';
|
|
2
2
|
import { ChainIdentifierArray } from '@tuwaio/orbit-core';
|
|
3
3
|
import * as _wallet_standard_ui_core from '@wallet-standard/ui-core';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Solana cluster moniker type inferred directly from @solana/kit branded cluster URLs plus localnet.
|
|
7
|
+
*/
|
|
8
|
+
type SolanaClusterMoniker = (MainnetUrl | DevnetUrl | TestnetUrl)['~cluster'] | 'localnet';
|
|
9
|
+
/**
|
|
10
|
+
* Configuration mapping Solana clusters to their RPC URLs.
|
|
11
|
+
*/
|
|
5
12
|
type SolanaRPCUrls = {
|
|
6
13
|
rpcUrls: Partial<Record<SolanaClusterMoniker, string>>;
|
|
7
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* Alias for Solana RPC methods interface.
|
|
17
|
+
*/
|
|
18
|
+
type SolanaRpcMethods = SolanaRpcApi;
|
|
19
|
+
/**
|
|
20
|
+
* Lightweight Solana client wrapper holding RPC and optional subscriptions clients.
|
|
21
|
+
*/
|
|
22
|
+
interface SolanaClient {
|
|
23
|
+
rpc: Rpc<SolanaRpcApi>;
|
|
24
|
+
rpcSubscriptions?: RpcSubscriptions<SolanaRpcSubscriptionsApi>;
|
|
25
|
+
}
|
|
8
26
|
|
|
9
27
|
/**
|
|
10
28
|
* Get Solana clusters from configuration
|
|
@@ -61,36 +79,40 @@ declare const getRpcUrlForCluster: ({ cluster, walletCluster, rpcUrls, }: {
|
|
|
61
79
|
* - Optimize memory usage
|
|
62
80
|
* - Maintain consistent client instances throughout the application
|
|
63
81
|
*
|
|
64
|
-
* @param
|
|
82
|
+
* @param params - Object containing rpcUrlOrMoniker and optional rpcUrls
|
|
83
|
+
* @param params.rpcUrlOrMoniker - RPC endpoint URL or cluster moniker (e.g., 'mainnet', 'devnet')
|
|
84
|
+
* @param params.rpcUrls - Optional custom mapping of cluster monikers to RPC endpoints
|
|
65
85
|
* @returns Cached or newly created Solana RPC client instance
|
|
66
86
|
* @throws Error if unable to resolve a valid RPC URL
|
|
67
|
-
*
|
|
68
|
-
* @example
|
|
69
|
-
* ```typescript
|
|
70
|
-
* // Using cluster moniker
|
|
71
|
-
* const mainnetClient = createSolanaClientWithCache('mainnet');
|
|
72
|
-
*
|
|
73
|
-
* // Using custom RPC URL
|
|
74
|
-
* const customClient = createSolanaClientWithCache('https://my-rpc.example.com');
|
|
75
|
-
* ```
|
|
76
87
|
*/
|
|
77
88
|
declare const createSolanaClientWithCache: ({ rpcUrlOrMoniker, rpcUrls, }: {
|
|
78
89
|
rpcUrlOrMoniker: string;
|
|
79
90
|
rpcUrls?: Partial<Record<SolanaClusterMoniker, string>>;
|
|
80
91
|
}) => SolanaClient;
|
|
92
|
+
/**
|
|
93
|
+
* Clears the Solana client cache.
|
|
94
|
+
* @internal
|
|
95
|
+
*/
|
|
96
|
+
declare const clearSolanaClientCache: () => void;
|
|
81
97
|
|
|
82
98
|
/**
|
|
83
99
|
* Retrieves a cached RPC client for a given URL or cluster moniker.
|
|
84
100
|
* If no cached client exists, it creates a new instance.
|
|
85
101
|
*
|
|
86
|
-
* @param
|
|
102
|
+
* @param params - Object containing rpcUrlOrMoniker and optional rpcUrls map.
|
|
103
|
+
* @param params.rpcUrlOrMoniker - Either a full RPC URL or a cluster moniker like 'mainnet'.
|
|
104
|
+
* @param params.rpcUrls - Optional custom mapping of cluster monikers to RPC endpoints.
|
|
87
105
|
* @returns The RPC client instance.
|
|
88
|
-
* @internal
|
|
89
106
|
*/
|
|
90
107
|
declare const createSolanaRPC: ({ rpcUrlOrMoniker, rpcUrls, }: {
|
|
91
108
|
rpcUrlOrMoniker: string;
|
|
92
109
|
rpcUrls?: Partial<Record<SolanaClusterMoniker, string>>;
|
|
93
110
|
}) => Rpc<SolanaRpcApi>;
|
|
111
|
+
/**
|
|
112
|
+
* Clears the Solana RPC client cache.
|
|
113
|
+
* @internal
|
|
114
|
+
*/
|
|
115
|
+
declare const clearSolanaRpcCache: () => void;
|
|
94
116
|
|
|
95
117
|
/**
|
|
96
118
|
* The default RPC URLs for each Solana cluster.
|
|
@@ -153,12 +175,12 @@ declare const getSolanaNameCacheSize: () => number;
|
|
|
153
175
|
* @file This file contains a utility function for generating Solana transaction explorer links.
|
|
154
176
|
*/
|
|
155
177
|
/**
|
|
156
|
-
* Generates a full URL to
|
|
178
|
+
* Generates a full URL to an account, transaction, or block on the Solana explorer.
|
|
157
179
|
*
|
|
158
|
-
* @param
|
|
159
|
-
* @param chainId
|
|
160
|
-
* @returns
|
|
180
|
+
* @param url - The path after baseUrl (e.g. '/tx/...' or '/address/...').
|
|
181
|
+
* @param chainId - Chain ID or cluster name.
|
|
182
|
+
* @returns The full URL on the Solana explorer.
|
|
161
183
|
*/
|
|
162
184
|
declare const getSolanaExplorerLink: (url?: string, chainId?: string | number | undefined) => string;
|
|
163
185
|
|
|
164
|
-
export { type SolanaRPCUrls, clearSolanaAvatarCache, clearSolanaNameCache, createSolanaClientWithCache, createSolanaRPC, defaultRpcUrlsByMoniker, getAvailableSolanaClusters, getAvailableSolanaConnectors, getCluster, getConnectedSolanaConnector, getRpcUrlForCluster, getSolanaAddressAvatar, getSolanaAddressName, getSolanaAvatarCacheSize, getSolanaClusters, getSolanaExplorerLink, getSolanaNameCacheSize, isSolanaChainList, isValidSolanaCluster, preloadSolanaAvatar };
|
|
186
|
+
export { type SolanaClient, type SolanaClusterMoniker, type SolanaRPCUrls, type SolanaRpcMethods, clearSolanaAvatarCache, clearSolanaClientCache, clearSolanaNameCache, clearSolanaRpcCache, createSolanaClientWithCache, createSolanaRPC, defaultRpcUrlsByMoniker, getAvailableSolanaClusters, getAvailableSolanaConnectors, getCluster, getConnectedSolanaConnector, getRpcUrlForCluster, getSolanaAddressAvatar, getSolanaAddressName, getSolanaAvatarCacheSize, getSolanaClusters, getSolanaExplorerLink, getSolanaNameCacheSize, isSolanaChainList, isValidSolanaCluster, preloadSolanaAvatar };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Rpc, SolanaRpcApi, RpcSubscriptions, SolanaRpcSubscriptionsApi, MainnetUrl, DevnetUrl, TestnetUrl } from '@solana/kit';
|
|
2
2
|
import { ChainIdentifierArray } from '@tuwaio/orbit-core';
|
|
3
3
|
import * as _wallet_standard_ui_core from '@wallet-standard/ui-core';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Solana cluster moniker type inferred directly from @solana/kit branded cluster URLs plus localnet.
|
|
7
|
+
*/
|
|
8
|
+
type SolanaClusterMoniker = (MainnetUrl | DevnetUrl | TestnetUrl)['~cluster'] | 'localnet';
|
|
9
|
+
/**
|
|
10
|
+
* Configuration mapping Solana clusters to their RPC URLs.
|
|
11
|
+
*/
|
|
5
12
|
type SolanaRPCUrls = {
|
|
6
13
|
rpcUrls: Partial<Record<SolanaClusterMoniker, string>>;
|
|
7
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* Alias for Solana RPC methods interface.
|
|
17
|
+
*/
|
|
18
|
+
type SolanaRpcMethods = SolanaRpcApi;
|
|
19
|
+
/**
|
|
20
|
+
* Lightweight Solana client wrapper holding RPC and optional subscriptions clients.
|
|
21
|
+
*/
|
|
22
|
+
interface SolanaClient {
|
|
23
|
+
rpc: Rpc<SolanaRpcApi>;
|
|
24
|
+
rpcSubscriptions?: RpcSubscriptions<SolanaRpcSubscriptionsApi>;
|
|
25
|
+
}
|
|
8
26
|
|
|
9
27
|
/**
|
|
10
28
|
* Get Solana clusters from configuration
|
|
@@ -61,36 +79,40 @@ declare const getRpcUrlForCluster: ({ cluster, walletCluster, rpcUrls, }: {
|
|
|
61
79
|
* - Optimize memory usage
|
|
62
80
|
* - Maintain consistent client instances throughout the application
|
|
63
81
|
*
|
|
64
|
-
* @param
|
|
82
|
+
* @param params - Object containing rpcUrlOrMoniker and optional rpcUrls
|
|
83
|
+
* @param params.rpcUrlOrMoniker - RPC endpoint URL or cluster moniker (e.g., 'mainnet', 'devnet')
|
|
84
|
+
* @param params.rpcUrls - Optional custom mapping of cluster monikers to RPC endpoints
|
|
65
85
|
* @returns Cached or newly created Solana RPC client instance
|
|
66
86
|
* @throws Error if unable to resolve a valid RPC URL
|
|
67
|
-
*
|
|
68
|
-
* @example
|
|
69
|
-
* ```typescript
|
|
70
|
-
* // Using cluster moniker
|
|
71
|
-
* const mainnetClient = createSolanaClientWithCache('mainnet');
|
|
72
|
-
*
|
|
73
|
-
* // Using custom RPC URL
|
|
74
|
-
* const customClient = createSolanaClientWithCache('https://my-rpc.example.com');
|
|
75
|
-
* ```
|
|
76
87
|
*/
|
|
77
88
|
declare const createSolanaClientWithCache: ({ rpcUrlOrMoniker, rpcUrls, }: {
|
|
78
89
|
rpcUrlOrMoniker: string;
|
|
79
90
|
rpcUrls?: Partial<Record<SolanaClusterMoniker, string>>;
|
|
80
91
|
}) => SolanaClient;
|
|
92
|
+
/**
|
|
93
|
+
* Clears the Solana client cache.
|
|
94
|
+
* @internal
|
|
95
|
+
*/
|
|
96
|
+
declare const clearSolanaClientCache: () => void;
|
|
81
97
|
|
|
82
98
|
/**
|
|
83
99
|
* Retrieves a cached RPC client for a given URL or cluster moniker.
|
|
84
100
|
* If no cached client exists, it creates a new instance.
|
|
85
101
|
*
|
|
86
|
-
* @param
|
|
102
|
+
* @param params - Object containing rpcUrlOrMoniker and optional rpcUrls map.
|
|
103
|
+
* @param params.rpcUrlOrMoniker - Either a full RPC URL or a cluster moniker like 'mainnet'.
|
|
104
|
+
* @param params.rpcUrls - Optional custom mapping of cluster monikers to RPC endpoints.
|
|
87
105
|
* @returns The RPC client instance.
|
|
88
|
-
* @internal
|
|
89
106
|
*/
|
|
90
107
|
declare const createSolanaRPC: ({ rpcUrlOrMoniker, rpcUrls, }: {
|
|
91
108
|
rpcUrlOrMoniker: string;
|
|
92
109
|
rpcUrls?: Partial<Record<SolanaClusterMoniker, string>>;
|
|
93
110
|
}) => Rpc<SolanaRpcApi>;
|
|
111
|
+
/**
|
|
112
|
+
* Clears the Solana RPC client cache.
|
|
113
|
+
* @internal
|
|
114
|
+
*/
|
|
115
|
+
declare const clearSolanaRpcCache: () => void;
|
|
94
116
|
|
|
95
117
|
/**
|
|
96
118
|
* The default RPC URLs for each Solana cluster.
|
|
@@ -153,12 +175,12 @@ declare const getSolanaNameCacheSize: () => number;
|
|
|
153
175
|
* @file This file contains a utility function for generating Solana transaction explorer links.
|
|
154
176
|
*/
|
|
155
177
|
/**
|
|
156
|
-
* Generates a full URL to
|
|
178
|
+
* Generates a full URL to an account, transaction, or block on the Solana explorer.
|
|
157
179
|
*
|
|
158
|
-
* @param
|
|
159
|
-
* @param chainId
|
|
160
|
-
* @returns
|
|
180
|
+
* @param url - The path after baseUrl (e.g. '/tx/...' or '/address/...').
|
|
181
|
+
* @param chainId - Chain ID or cluster name.
|
|
182
|
+
* @returns The full URL on the Solana explorer.
|
|
161
183
|
*/
|
|
162
184
|
declare const getSolanaExplorerLink: (url?: string, chainId?: string | number | undefined) => string;
|
|
163
185
|
|
|
164
|
-
export { type SolanaRPCUrls, clearSolanaAvatarCache, clearSolanaNameCache, createSolanaClientWithCache, createSolanaRPC, defaultRpcUrlsByMoniker, getAvailableSolanaClusters, getAvailableSolanaConnectors, getCluster, getConnectedSolanaConnector, getRpcUrlForCluster, getSolanaAddressAvatar, getSolanaAddressName, getSolanaAvatarCacheSize, getSolanaClusters, getSolanaExplorerLink, getSolanaNameCacheSize, isSolanaChainList, isValidSolanaCluster, preloadSolanaAvatar };
|
|
186
|
+
export { type SolanaClient, type SolanaClusterMoniker, type SolanaRPCUrls, type SolanaRpcMethods, clearSolanaAvatarCache, clearSolanaClientCache, clearSolanaNameCache, clearSolanaRpcCache, createSolanaClientWithCache, createSolanaRPC, defaultRpcUrlsByMoniker, getAvailableSolanaClusters, getAvailableSolanaConnectors, getCluster, getConnectedSolanaConnector, getRpcUrlForCluster, getSolanaAddressAvatar, getSolanaAddressName, getSolanaAvatarCacheSize, getSolanaClusters, getSolanaExplorerLink, getSolanaNameCacheSize, isSolanaChainList, isValidSolanaCluster, preloadSolanaAvatar };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var
|
|
2
|
-
exports.clearSolanaAvatarCache=ut;exports.clearSolanaNameCache=
|
|
1
|
+
'use strict';var kit=require('@solana/kit'),orbitCore=require('@tuwaio/orbit-core'),app=require('@wallet-standard/app'),uiRegistry=require('@wallet-standard/ui-registry');var s={mainnet:"https://api.mainnet-beta.solana.com",devnet:"https://api.devnet.solana.com",testnet:"https://api.testnet.solana.com"};function d(t){let e=t.split(":");if(e.length<2)return null;let r=e[1];r==="mainnet-beta"&&(r="mainnet");let a=r;return a in s?a:null}function S(t,e){let r={},a=Object.keys(e||s);for(let n of t){if(typeof n!="string")continue;let o=d(n);if(!o||!a.includes(o))continue;let f=e?.[o]??s[o];f&&(r[o]=f);}return r}function j(t,e){if(e&&e.length>0){let r=S(e,t);return Object.keys(r)}return Object.keys(t||s)}function z(t){return t.length>0&&t.every(e=>typeof e=="string")}function T(){return Object.keys(s)}function W(t){return t in s}var m=({cluster:t,walletCluster:e})=>{let r="mainnet";return t?t.includes(":")?t.split(":")[1]:t:e??r},q=({cluster:t,walletCluster:e,rpcUrls:r})=>r[e??t]??"https://api.mainnet-beta.solana.com/";function h(t){try{return new URL(t),!0}catch{return false}}function R(t){return t.replace(/^http/,"ws")}var l=new Map,X=({rpcUrlOrMoniker:t,rpcUrls:e})=>{if(l.has(t))return l.get(t);let r=h(t)?t:e?e[t]??s[t]:s[t];if(!r)throw new Error(`Unable to resolve RPC URL for input: "${t}". Ensure it's a valid URL or known moniker.`);let a=kit.createSolanaRpc(r),n;try{n=kit.createSolanaRpcSubscriptions(R(r));}catch{}let o={rpc:a,...n?{rpcSubscriptions:n}:{}};return l.set(t,o),o},G=()=>{l.clear();};function v(t){try{return new URL(t),!0}catch{return false}}var c=new Map,Z=({rpcUrlOrMoniker:t,rpcUrls:e})=>{if(c.has(t))return c.get(t);let r=v(t)?t:e?e[t]??s[t]:s[t];if(!r)throw new Error(`Unable to resolve RPC URL for input: "${t}". Ensure it's a valid URL or known moniker.`);let a=kit.createSolanaRpc(r);return c.set(t,a),a},O=()=>{c.clear();};function g(){return orbitCore.filterUniqueByKey(app.getWallets().get().map(uiRegistry.getOrCreateUiWalletForStandardWallet),"name").filter(t=>{try{return !t||!Array.isArray(t.chains)||!t.features||!Array.isArray(t.features)||!["standard:connect","standard:disconnect","standard:events","solana:signAndSendTransaction","solana:signTransaction","solana:signMessage"].every(a=>t.features.includes(a))?!1:t.chains.every(a=>{try{if(typeof a!="string")return !1;let n=a.split(":");return n.length>=1&&n[0]==="solana"}catch(n){return console.warn("Error parsing chain:",a,n),!1}})}catch(e){return console.warn("Error filtering wallet:",e),false}})}function it(){let t=orbitCore.lastConnectedConnectorHelpers.getLastConnectedConnector(),r=g().find(a=>a.accounts.find(n=>n.address.toLowerCase()===t?.address?.toLowerCase()));if(!r)throw new Error("Connector not provided. Cannot perform chain check.");return r}var u=new Map,P="https://image-api.bonfida.com",N=t=>/^[a-z0-9-]+\.sol$/.test(t.toLowerCase()),L=async t=>{try{let e=await fetch(`${P}/image?domain=${encodeURIComponent(t)}`);if(!e.ok)return null;let r=await e.json();return r.result&&Array.isArray(r.result)&&r.result.length>0?r.result.find(n=>n.domain===t)?.image??r.result[0]?.image??null:null}catch(e){return console.warn("Failed to fetch SNS avatar:",e),null}},i=t=>`https://api.dicebear.com/7.x/identicon/svg?seed=${encodeURIComponent(t)}`,M=async t=>{if(!t)return i("default");let e=t.trim();if(!e)return i("default");let r=e.toLowerCase(),a=u.get(r);if(a!==void 0)return a;let n;try{if(N(e)){let o=await L(e);o?n=o:n=i(e);}else kit.isAddress(e),n=i(e);}catch(o){console.warn("Error resolving avatar:",o),n=i(e);}return u.set(r,n),n},ut=()=>{u.clear();},pt=()=>u.size,ft=async t=>{try{await M(t);}catch(e){console.warn("Failed to preload avatar:",e);}};var p=new Map,$="https://sns-api.bonfida.com",I=async t=>{try{let e=await fetch(`${$}/v2/user/fav-domains/${t}`);if(!e.ok)return null;let r=await e.json();return r.result&&typeof r.result=="object"&&t in r.result?r.result[t]:null}catch(e){return console.warn("Failed to fetch SNS name:",e),null}},dt=async t=>{if(!t)return t||"";let e=t.trim();if(!kit.isAddress(e))return t;let r=e.toLowerCase(),a=p.get(r);if(a!==void 0)return a;let n=t;try{let o=await I(e);o&&(n=o);}catch(o){console.warn("Error resolving address name:",o);}return p.set(r,n),n},St=()=>{p.clear();},Ct=()=>p.size;var B="https://explorer.solana.com",Rt=(t,e)=>{let r=m({cluster:String(e)})??"mainnet",a=B,n=r&&r!=="mainnet"?`?cluster=${r}`:"",o=t?t.startsWith("/")?t:`/${t}`:"/";return `${a}${o}${n}`};
|
|
2
|
+
exports.clearSolanaAvatarCache=ut;exports.clearSolanaClientCache=G;exports.clearSolanaNameCache=St;exports.clearSolanaRpcCache=O;exports.createSolanaClientWithCache=X;exports.createSolanaRPC=Z;exports.defaultRpcUrlsByMoniker=s;exports.getAvailableSolanaClusters=T;exports.getAvailableSolanaConnectors=g;exports.getCluster=m;exports.getConnectedSolanaConnector=it;exports.getRpcUrlForCluster=q;exports.getSolanaAddressAvatar=M;exports.getSolanaAddressName=dt;exports.getSolanaAvatarCacheSize=pt;exports.getSolanaClusters=j;exports.getSolanaExplorerLink=Rt;exports.getSolanaNameCacheSize=Ct;exports.isSolanaChainList=z;exports.isValidSolanaCluster=W;exports.preloadSolanaAvatar=ft;
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export{ut as clearSolanaAvatarCache,
|
|
1
|
+
import {createSolanaRpc,createSolanaRpcSubscriptions,isAddress}from'@solana/kit';import {filterUniqueByKey,lastConnectedConnectorHelpers}from'@tuwaio/orbit-core';import {getWallets}from'@wallet-standard/app';import {getOrCreateUiWalletForStandardWallet}from'@wallet-standard/ui-registry';var s={mainnet:"https://api.mainnet-beta.solana.com",devnet:"https://api.devnet.solana.com",testnet:"https://api.testnet.solana.com"};function d(t){let e=t.split(":");if(e.length<2)return null;let r=e[1];r==="mainnet-beta"&&(r="mainnet");let a=r;return a in s?a:null}function S(t,e){let r={},a=Object.keys(e||s);for(let n of t){if(typeof n!="string")continue;let o=d(n);if(!o||!a.includes(o))continue;let f=e?.[o]??s[o];f&&(r[o]=f);}return r}function j(t,e){if(e&&e.length>0){let r=S(e,t);return Object.keys(r)}return Object.keys(t||s)}function z(t){return t.length>0&&t.every(e=>typeof e=="string")}function T(){return Object.keys(s)}function W(t){return t in s}var m=({cluster:t,walletCluster:e})=>{let r="mainnet";return t?t.includes(":")?t.split(":")[1]:t:e??r},q=({cluster:t,walletCluster:e,rpcUrls:r})=>r[e??t]??"https://api.mainnet-beta.solana.com/";function h(t){try{return new URL(t),!0}catch{return false}}function R(t){return t.replace(/^http/,"ws")}var l=new Map,X=({rpcUrlOrMoniker:t,rpcUrls:e})=>{if(l.has(t))return l.get(t);let r=h(t)?t:e?e[t]??s[t]:s[t];if(!r)throw new Error(`Unable to resolve RPC URL for input: "${t}". Ensure it's a valid URL or known moniker.`);let a=createSolanaRpc(r),n;try{n=createSolanaRpcSubscriptions(R(r));}catch{}let o={rpc:a,...n?{rpcSubscriptions:n}:{}};return l.set(t,o),o},G=()=>{l.clear();};function v(t){try{return new URL(t),!0}catch{return false}}var c=new Map,Z=({rpcUrlOrMoniker:t,rpcUrls:e})=>{if(c.has(t))return c.get(t);let r=v(t)?t:e?e[t]??s[t]:s[t];if(!r)throw new Error(`Unable to resolve RPC URL for input: "${t}". Ensure it's a valid URL or known moniker.`);let a=createSolanaRpc(r);return c.set(t,a),a},O=()=>{c.clear();};function g(){return filterUniqueByKey(getWallets().get().map(getOrCreateUiWalletForStandardWallet),"name").filter(t=>{try{return !t||!Array.isArray(t.chains)||!t.features||!Array.isArray(t.features)||!["standard:connect","standard:disconnect","standard:events","solana:signAndSendTransaction","solana:signTransaction","solana:signMessage"].every(a=>t.features.includes(a))?!1:t.chains.every(a=>{try{if(typeof a!="string")return !1;let n=a.split(":");return n.length>=1&&n[0]==="solana"}catch(n){return console.warn("Error parsing chain:",a,n),!1}})}catch(e){return console.warn("Error filtering wallet:",e),false}})}function it(){let t=lastConnectedConnectorHelpers.getLastConnectedConnector(),r=g().find(a=>a.accounts.find(n=>n.address.toLowerCase()===t?.address?.toLowerCase()));if(!r)throw new Error("Connector not provided. Cannot perform chain check.");return r}var u=new Map,P="https://image-api.bonfida.com",N=t=>/^[a-z0-9-]+\.sol$/.test(t.toLowerCase()),L=async t=>{try{let e=await fetch(`${P}/image?domain=${encodeURIComponent(t)}`);if(!e.ok)return null;let r=await e.json();return r.result&&Array.isArray(r.result)&&r.result.length>0?r.result.find(n=>n.domain===t)?.image??r.result[0]?.image??null:null}catch(e){return console.warn("Failed to fetch SNS avatar:",e),null}},i=t=>`https://api.dicebear.com/7.x/identicon/svg?seed=${encodeURIComponent(t)}`,M=async t=>{if(!t)return i("default");let e=t.trim();if(!e)return i("default");let r=e.toLowerCase(),a=u.get(r);if(a!==void 0)return a;let n;try{if(N(e)){let o=await L(e);o?n=o:n=i(e);}else isAddress(e),n=i(e);}catch(o){console.warn("Error resolving avatar:",o),n=i(e);}return u.set(r,n),n},ut=()=>{u.clear();},pt=()=>u.size,ft=async t=>{try{await M(t);}catch(e){console.warn("Failed to preload avatar:",e);}};var p=new Map,$="https://sns-api.bonfida.com",I=async t=>{try{let e=await fetch(`${$}/v2/user/fav-domains/${t}`);if(!e.ok)return null;let r=await e.json();return r.result&&typeof r.result=="object"&&t in r.result?r.result[t]:null}catch(e){return console.warn("Failed to fetch SNS name:",e),null}},dt=async t=>{if(!t)return t||"";let e=t.trim();if(!isAddress(e))return t;let r=e.toLowerCase(),a=p.get(r);if(a!==void 0)return a;let n=t;try{let o=await I(e);o&&(n=o);}catch(o){console.warn("Error resolving address name:",o);}return p.set(r,n),n},St=()=>{p.clear();},Ct=()=>p.size;var B="https://explorer.solana.com",Rt=(t,e)=>{let r=m({cluster:String(e)})??"mainnet",a=B,n=r&&r!=="mainnet"?`?cluster=${r}`:"",o=t?t.startsWith("/")?t:`/${t}`:"/";return `${a}${o}${n}`};
|
|
2
|
+
export{ut as clearSolanaAvatarCache,G as clearSolanaClientCache,St as clearSolanaNameCache,O as clearSolanaRpcCache,X as createSolanaClientWithCache,Z as createSolanaRPC,s as defaultRpcUrlsByMoniker,T as getAvailableSolanaClusters,g as getAvailableSolanaConnectors,m as getCluster,it as getConnectedSolanaConnector,q as getRpcUrlForCluster,M as getSolanaAddressAvatar,dt as getSolanaAddressName,pt as getSolanaAvatarCacheSize,j as getSolanaClusters,Rt as getSolanaExplorerLink,Ct as getSolanaNameCacheSize,z as isSolanaChainList,W as isValidSolanaCluster,ft as preloadSolanaAvatar};
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tuwaio/orbit-solana",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Oleksandr Tkach",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
|
-
"description": "Layer 2 (L2) of the TUWA Ecosystem. Low-level Solana-specific communication primitives and RPC caching utilities powered strictly by
|
|
7
|
+
"description": "Layer 2 (L2) of the TUWA Ecosystem. Low-level Solana-specific communication primitives and RPC caching utilities powered strictly by @solana/kit.",
|
|
8
8
|
"main": "./dist/index.js",
|
|
9
9
|
"module": "./dist/index.mjs",
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
@@ -38,22 +38,23 @@
|
|
|
38
38
|
],
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"@tuwaio/orbit-core": ">=0.2",
|
|
41
|
-
"
|
|
41
|
+
"@solana/kit": ">=8.2",
|
|
42
42
|
"@wallet-standard/app": "1.x.x",
|
|
43
43
|
"@wallet-standard/ui-core": "1.x.x",
|
|
44
44
|
"@wallet-standard/ui-registry": "1.x.x"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
+
"@tuwaio/orbit-core": "^0.3.0",
|
|
47
48
|
"tsup": "^8.5.1",
|
|
48
49
|
"typescript": "^6.0.3",
|
|
49
|
-
"
|
|
50
|
+
"@solana/kit": "^8.2.0",
|
|
50
51
|
"@wallet-standard/app": "^1.1.1",
|
|
51
52
|
"@wallet-standard/ui-core": "^1.0.1",
|
|
52
|
-
"@wallet-standard/ui-registry": "^1.1.1"
|
|
53
|
-
"@tuwaio/orbit-core": "^0.2.15"
|
|
53
|
+
"@wallet-standard/ui-registry": "^1.1.1"
|
|
54
54
|
},
|
|
55
55
|
"scripts": {
|
|
56
56
|
"start": "tsup src/index.ts --watch",
|
|
57
|
-
"build": "tsup"
|
|
57
|
+
"build": "tsup",
|
|
58
|
+
"test": "vitest run"
|
|
58
59
|
}
|
|
59
60
|
}
|