@tuwaio/orbit-core 0.3.0 → 0.4.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 CHANGED
@@ -1,18 +1,22 @@
1
1
  # @tuwaio/orbit-core
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/@tuwaio/orbit-core.svg)](https://www.npmjs.com/package/@tuwaio/orbit-core)
4
- [![License](https://img.shields.io/npm/l/@tuwaio/orbit-core.svg)](./LICENSE)
4
+ [![License](https://img.shields.io/npm/l/@tuwaio/orbit-core.svg)](https://github.com/TuwaIO/orbit/blob/main/packages/orbit-core/LICENSE)
5
5
 
6
- `@tuwaio/orbit-core` is the Layer 1 (L1) core logic and foundational state wrapper layer of the TUWA Orbit multi-chain framework. It is completely **headless** and **framework-agnostic**, engineered to decouple raw blockchain connection interfaces from visual frontend layers. By establishing a unified type-safe interface, it enables consistent cross-chain connection management and persistent user account tracking.
6
+ `@tuwaio/orbit-core` is the Layer 1 (L1) package of **Orbit Utils**, the Stage 1 primitives layer of the TUWA ecosystem. It defines the chain-agnostic types that the Orbit chain packages and the higher TUWA layers (Satellite Connect, Pulsar) share, and ships small helpers for connector naming, address validation, error normalization and SSR-safe connection persistence.
7
+
8
+ The package has **zero runtime dependencies** and imports no Web3 SDK, so it runs in any framework, in the browser and on the server.
7
9
 
8
10
  ---
9
11
 
10
12
  ## 🏛️ Core Capabilities
11
13
 
12
- - **Unified Multi-Chain Primitives:** Establishes the structural `BaseAdapter` interface and the `OrbitAdapter` enum (EVM, Solana, Starknet) to serve as the abstract layer for multi-chain communication.
13
- - **Connection State Persistence:** Implements SSR-safe storage helpers (`lastConnectedConnectorHelpers`, `recentConnectedConnectorHelpers`) to track and resume wallet connection history via `localStorage`.
14
- - **Autonomy-Focused Utilities:** Technical utility helpers for formatting chain IDs, parsing connector names, and executing asynchronous operations (`waitFor`, `delay`).
15
- - **Account Impersonation Engine:** Built-in `impersonatedHelpers` for sandboxed testing and account auditing.
14
+ - **Multi-chain primitives:** the `OrbitAdapter` enum (`evm`, `solana`, `starknet`), the `BaseAdapter` contract, `ConnectorType` identifiers such as `"evm:metamask"` or `"solana:phantom"`, and `selectAdapterByKey` to pick the adapter of the active chain.
15
+ - **Connector helpers:** `getConnectorTypeFromName`, `getAdapterFromConnectorType`, `formatConnectorName`, `formatConnectorChainId`, `isSolanaChain`, `setChainId` and `getNetworkData`.
16
+ - **Solana chain IDs:** `SOLANA_CHAIN_IDS` holds the CAIP-2 chain IDs of mainnet, devnet and testnet, made of the genesis hash as CAIP-30 requires. `getSolanaChainId` and `getSolanaCluster` convert between these IDs and cluster monikers and read every form in use (`devnet`, `solana:devnet`, `solana:mainnet-beta`, the testnet ID from before the testnet genesis reset). `setChainId` and `formatConnectorChainId` return these IDs for Solana.
17
+ - **Validation and errors:** `isAddress` validates EVM (hex) and Solana (Base58) addresses. `normalizeError` turns any wallet, viem or RPC error into a JSON-serializable `TuwaErrorState` that is safe to persist.
18
+ - **Connection persistence:** `lastConnectedConnectorHelpers` and `recentlyConnectedConnectorsListHelpers` keep connection history in `localStorage` and do nothing during SSR.
19
+ - **Runtime utilities:** `detectSafeApp` (Safe{Wallet} iframe detection), `waitFor`, `delay`, `filterUniqueByKey`, and `impersonatedHelpers` for development and testing.
16
20
 
17
21
  ---
18
22
 
@@ -24,71 +28,99 @@ pnpm add @tuwaio/orbit-core
24
28
 
25
29
  ---
26
30
 
27
- ## 🚀 Architectural Integration
31
+ ## 🚀 Usage
28
32
 
29
- ### Runtime Adapter Resolution
33
+ ### Resolving the active adapter
30
34
 
31
- Register and resolve chain-specific primitive adapters dynamically:
35
+ `BaseAdapter` describes what an adapter can do; add a `key` to register it for a chain family:
32
36
 
33
37
  ```typescript
34
- import { OrbitAdapter, selectAdapterByKey, BaseAdapter } from '@tuwaio/orbit-core';
35
-
36
- // Configure primitive adapter mapping
37
- const adapters: BaseAdapter[] = [
38
- {
39
- key: OrbitAdapter.EVM,
40
- getExplorerUrl: (url) => `https://etherscan.io/${url}`,
41
- },
42
- {
43
- key: OrbitAdapter.SOLANA,
44
- getExplorerUrl: (url, cluster) => `https://solscan.io/${url}?cluster=${cluster}`,
45
- },
46
- ];
38
+ import { type BaseAdapter, OrbitAdapter, selectAdapterByKey } from '@tuwaio/orbit-core';
47
39
 
48
- // Dynamically select target execution adapter
49
- const activeAdapter = selectAdapterByKey({
50
- adapterKey: OrbitAdapter.SOLANA,
51
- adapter: adapters,
52
- });
40
+ type ExplorerAdapter = BaseAdapter & { key: OrbitAdapter };
53
41
 
54
- if (activeAdapter) {
55
- console.log(activeAdapter.getExplorerUrl('tx/0x...', 'mainnet-beta'));
56
- }
42
+ const adapters: ExplorerAdapter[] = [
43
+ { key: OrbitAdapter.EVM, getExplorerUrl: (path) => `https://etherscan.io/${path ?? ''}` },
44
+ { key: OrbitAdapter.SOLANA, getExplorerUrl: (path) => `https://explorer.solana.com/${path ?? ''}` },
45
+ ];
46
+
47
+ const solanaAdapter = selectAdapterByKey({ adapterKey: OrbitAdapter.SOLANA, adapter: adapters });
48
+ solanaAdapter?.getExplorerUrl('tx/<signature>'); // "https://explorer.solana.com/tx/<signature>"
57
49
  ```
58
50
 
59
- ### Connection State Storage
51
+ If no adapter matches the key, `selectAdapterByKey` falls back to the first adapter in the array and logs a warning.
60
52
 
61
- Read and write connected connector metadata securely with `localStorage` fallback checks:
53
+ ### Persisting the last connection
62
54
 
63
55
  ```typescript
64
56
  import { lastConnectedConnectorHelpers } from '@tuwaio/orbit-core';
65
57
 
66
- // Persist metadata
67
58
  lastConnectedConnectorHelpers.setLastConnectedConnector({
68
59
  connectorType: 'evm:metamask',
69
60
  chainId: 1,
70
- address: '0x123...',
61
+ address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
71
62
  });
72
63
 
73
- // Retrieve connection metadata safely during client-side hydration
64
+ // Returns undefined on the server and when nothing is stored.
74
65
  const lastConnected = lastConnectedConnectorHelpers.getLastConnectedConnector();
75
- console.log(lastConnected?.address); // "0x123..."
76
66
  ```
77
67
 
68
+ ### Identifying Solana clusters
69
+
70
+ ```typescript
71
+ import { getSolanaChainId, getSolanaCluster } from '@tuwaio/orbit-core';
72
+
73
+ getSolanaChainId('devnet'); // "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
74
+ getSolanaChainId('solana:mainnet-beta'); // "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
75
+ getSolanaCluster('solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1'); // "devnet"
76
+ ```
77
+
78
+ Use the CAIP-2 ID wherever a chain is identified: SIWX messages, transaction records, APIs. Use the cluster moniker for RPC URLs and for Wallet Standard calls, which name the cluster `solana:devnet`.
79
+
80
+ ### Normalizing errors
81
+
82
+ ```typescript
83
+ import { normalizeError } from '@tuwaio/orbit-core';
84
+
85
+ declare function sendTransaction(): Promise<void>;
86
+
87
+ try {
88
+ await sendTransaction();
89
+ } catch (error) {
90
+ // `message` prefers viem's `shortMessage`; `raw` is a JSON-safe copy of the error details.
91
+ const { message, raw } = normalizeError(error);
92
+ }
93
+ ```
94
+
95
+ ### Validating addresses
96
+
97
+ ```typescript
98
+ import { isAddress } from '@tuwaio/orbit-core';
99
+
100
+ isAddress('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'); // true (auto-detected as EVM)
101
+ isAddress('So11111111111111111111111111111111111111112', 'solana'); // true
102
+ ```
103
+
104
+ `isAddress` checks the address format only (hex length or Base58 alphabet); it does not verify EVM checksums.
105
+
78
106
  ---
79
107
 
80
- ## 🔧 API & Module Architecture
108
+ ## 🗄️ Browser Storage
81
109
 
82
- `@tuwaio/orbit-core` exposes the following modules:
110
+ The storage helpers write the following `localStorage` keys. Clear them to reset the connection state of a user:
83
111
 
84
- - **Core Primitives:** `OrbitAdapter`, `BaseAdapter`, `ConnectorType`, `RecentlyConnectedConnectorData`.
85
- - **Registry Resolvers:** `selectAdapterByKey`, `getAdapterFromConnectorType`, `getConnectorTypeFromName`.
86
- - **Formatters:** `formatConnectorName`, `formatConnectorChainId`.
87
- - **Storage Helpers:** `lastConnectedConnectorHelpers`, `recentConnectedConnectorHelpers`, `impersonatedHelpers`.
88
- - **Core Primitives:** `isSafeApp`, `delay`, `waitFor`, `filterUniqueByKey`.
112
+ | Key | Written by |
113
+ | --------------------------------------------------- | ---------------------------------------- |
114
+ | `orbit-core:lastConnectedConnector` | `lastConnectedConnectorHelpers` |
115
+ | `orbit-core:recentlyConnectedConnectorsListHelpers` | `recentlyConnectedConnectorsListHelpers` |
116
+ | `satellite-connect:impersonatedAddress` | `impersonatedHelpers` |
89
117
 
90
118
  ---
91
119
 
120
+ ## 📚 API Reference
121
+
122
+ Every export, with signatures and types generated from the source, is documented at **[orbit.docs.tuwa.io/packages/orbit-core](https://orbit.docs.tuwa.io/packages/orbit-core)**.
123
+
92
124
  ## 📄 License
93
125
 
94
- Licensed under the **Apache-2.0 License**. See the [LICENSE](./LICENSE) file for details.
126
+ Licensed under the **Apache-2.0 License**. See the [LICENSE](https://github.com/TuwaIO/orbit/blob/main/packages/orbit-core/LICENSE) file for details.
package/dist/index.d.mts CHANGED
@@ -48,8 +48,10 @@ declare enum OrbitAdapter {
48
48
  * For the Starknet L2 network.
49
49
  * Supports:
50
50
  * - Starknet Mainnet
51
- * - Testnet (Goerli)
51
+ * - Starknet Sepolia testnet
52
52
  * - Other Starknet deployments
53
+ *
54
+ * Reserved for future use: no Orbit chain package implements Starknet yet.
53
55
  */
54
56
  Starknet = "starknet"
55
57
  }
@@ -90,6 +92,10 @@ type OrbitGenericAdapter<A extends {
90
92
  }> = {
91
93
  adapter: A | A[];
92
94
  };
95
+ /**
96
+ * Minimal contract shared by chain adapters: explorer links plus optional name-service lookups.
97
+ * Combine it with a `key: OrbitAdapter` property to register an adapter for {@link selectAdapterByKey}.
98
+ */
93
99
  type BaseAdapter = {
94
100
  /**
95
101
  * Generates blockchain explorer URL
@@ -114,7 +120,7 @@ type ConnectorType = `${OrbitAdapter}:${string}`;
114
120
  *
115
121
  * @example
116
122
  * ```typescript
117
- * const chainIds: ChainIdentifierArray = ['ethereum', 1, 'solana:mainnet-beta'];
123
+ * const chainIds: ChainIdentifierArray = ['ethereum', 1, 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'];
118
124
  * ```
119
125
  */
120
126
  type ChainIdentifierArray = readonly (string | number)[];
@@ -128,24 +134,25 @@ type ChainIdentifierArray = readonly (string | number)[];
128
134
  declare function isAddress(value: string, type?: 'evm' | 'solana' | 'auto'): boolean;
129
135
 
130
136
  /**
131
- * Checks whether the given chain ID belongs to a Solana network.
132
- * Supports common Solana network names: 'devnet', 'testnet', 'mainnet-beta', 'mainnet'.
137
+ * Checks whether the given chain ID belongs to a Solana network: a cluster moniker (`mainnet`, `mainnet-beta`,
138
+ * `devnet`, `testnet`, `localnet`), a Wallet Standard chain such as `solana:devnet`, or a CAIP-2 chain ID with the
139
+ * genesis hash. See {@link getSolanaCluster}.
133
140
  *
134
- * @param {number | string} chainId - The chain ID or chain name.
135
- * @returns {boolean} - True if the chain ID corresponds to a Solana network, false otherwise.
141
+ * @param chainId - The chain ID or chain name.
142
+ * @returns `true` if the chain ID corresponds to a known Solana network, `false` otherwise.
136
143
  */
137
144
  declare function isSolanaChain(chainId: number | string): boolean;
138
145
  /**
139
- * Sets the chain ID to a Solana-specific format if the chain is a Solana network.
146
+ * Turns a Solana chain, in any form accepted by {@link isSolanaChain}, into its CAIP-2 chain ID with the genesis hash
147
+ * (see {@link getSolanaChainId}): `devnet` and `solana:devnet` become `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1`. Other
148
+ * chain IDs are returned unchanged.
140
149
  *
141
- * @param {number | string} chainId - The original chain ID or name.
142
- * @returns {string | number} - The formatted chain ID prefixed with 'solana:' if Solana, otherwise the original.
150
+ * @param chainId - The original chain ID or name.
151
+ * @returns The CAIP-2 chain ID for Solana networks, otherwise the original value.
143
152
  */
144
153
  declare function setChainId(chainId: number | string): string | number;
145
154
 
146
155
  /**
147
- * @name delay
148
- *
149
156
  * Ensures the global 'window' object is available (if running in a browser-like environment),
150
157
  * then pauses execution for a specified duration, and finally resolves the Promise with the given value.
151
158
  *
@@ -188,8 +195,38 @@ declare const delay: <T>(value: T, ms: number) => Promise<T>;
188
195
  */
189
196
  declare function filterUniqueByKey<T>(array: T[], key: keyof T): T[];
190
197
 
198
+ /**
199
+ * Formats a chain ID for use in connector identifiers.
200
+ * Solana clusters become CAIP-2 chain IDs with the genesis hash (see {@link getSolanaChainId}); other string chain
201
+ * IDs are prefixed with the adapter key unless they already have it; numeric EVM chain IDs are kept as is.
202
+ *
203
+ * @example
204
+ * ```typescript
205
+ * formatConnectorChainId('devnet', OrbitAdapter.SOLANA); // "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
206
+ * formatConnectorChainId(1, OrbitAdapter.EVM); // 1
207
+ * ```
208
+ *
209
+ * @param chainId - Numeric EVM chain ID or string chain identifier.
210
+ * @param connectedAdapter - Adapter of the connected wallet.
211
+ * @returns The CAIP-2 chain ID for known Solana clusters, `"<adapter>:<chainId>"` for other string chain IDs, otherwise
212
+ * the numeric chain ID unchanged.
213
+ */
191
214
  declare function formatConnectorChainId(chainId: string | number, connectedAdapter: OrbitAdapter): string | number;
192
215
 
216
+ /**
217
+ * Normalizes a wallet connector display name into a stable identifier.
218
+ * Known names are mapped explicitly (e.g. "Trust Wallet" → "trust", "Base Account" → "coinbase");
219
+ * any other name has its whitespace removed and is lowercased.
220
+ *
221
+ * @example
222
+ * ```typescript
223
+ * formatConnectorName('Trust Wallet'); // "trust"
224
+ * formatConnectorName('Rabby Wallet'); // "rabbywallet"
225
+ * ```
226
+ *
227
+ * @param connectorName - Display name reported by the wallet connector.
228
+ * @returns The normalized connector identifier.
229
+ */
193
230
  declare const formatConnectorName: (connectorName: string) => string;
194
231
 
195
232
  /**
@@ -245,6 +282,15 @@ declare function getAdapterFromConnectorType(connectorType: ConnectorType): Orbi
245
282
  */
246
283
  declare function getConnectorTypeFromName(adapter: OrbitAdapter, name: string): string;
247
284
 
285
+ /**
286
+ * Returns the default network and educational links for an adapter, e.g. to render a
287
+ * "What is a wallet?" section in a connect modal.
288
+ *
289
+ * @param adapter - The adapter to describe.
290
+ * @returns Default chain (`chainId`: `1` for EVM, {@link SOLANA_CHAIN_IDS}`.mainnet` for Solana; `name`) and `links`
291
+ * (`aboutNetwork`, `choseWallet`, `about`) for EVM and Solana, or `undefined` for adapters without network data (e.g.
292
+ * Starknet).
293
+ */
248
294
  declare const getNetworkData: (adapter: OrbitAdapter) => {
249
295
  chain: {
250
296
  chainId: number;
@@ -257,7 +303,7 @@ declare const getNetworkData: (adapter: OrbitAdapter) => {
257
303
  };
258
304
  } | {
259
305
  chain: {
260
- chainId: string;
306
+ chainId: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
261
307
  name: string;
262
308
  };
263
309
  links: {
@@ -317,14 +363,22 @@ declare const impersonatedHelpers: {
317
363
  * @returns The impersonated address or undefined if not set or in SSR context
318
364
  */
319
365
  getImpersonated: () => string | null | undefined;
366
+ /**
367
+ * Removes the impersonated address from localStorage.
368
+ *
369
+ * @returns undefined in SSR context, void in browser
370
+ */
320
371
  removeImpersonated: () => void;
321
372
  };
322
373
 
323
374
  /**
324
375
  * Checks if the current window is running inside a Safe App iframe
325
376
  * by attempting postMessage communication with the parent window.
377
+ * Side effect: posts a `getSafeInfo` message to `window.parent` and listens for the reply until `timeout`.
326
378
  *
327
- * @returns Promise that resolves to true if running inside Safe Wallet, false otherwise
379
+ * @param timeout - How long to wait for the Safe response, in milliseconds. Defaults to 1000.
380
+ * @returns Promise that resolves to true if running inside Safe Wallet, false otherwise (also on the server,
381
+ * outside an iframe, or when not served over HTTPS)
328
382
  */
329
383
  declare function detectSafeApp(timeout?: number): Promise<boolean>;
330
384
  /**
@@ -338,9 +392,15 @@ declare const isInSecureIframe: boolean;
338
392
  */
339
393
  declare const isSafeApp: boolean;
340
394
 
395
+ /**
396
+ * Connection data persisted by {@link lastConnectedConnectorHelpers}.
397
+ */
341
398
  type LastConnectedConnector = {
399
+ /** Connector identifier, e.g. "evm:metamask". */
342
400
  connectorType: ConnectorType;
401
+ /** Chain the wallet was connected to (numeric EVM chain ID or Solana chain identifier). */
343
402
  chainId: number | string;
403
+ /** Connected wallet address, if known. */
344
404
  address?: string;
345
405
  };
346
406
  /**
@@ -360,7 +420,7 @@ declare const lastConnectedConnectorHelpers: {
360
420
  /**
361
421
  * Stores the last connected wallet data in localStorage.
362
422
  *
363
- * @param data - Object containing the wallet type and chain ID.
423
+ * @param data - Connector type, chain ID and optional address of the connected wallet.
364
424
  * @returns undefined in SSR context, void in browser
365
425
  */
366
426
  setLastConnectedConnector: ({ connectorType, chainId, address }: LastConnectedConnector) => void;
@@ -692,6 +752,72 @@ declare const selectAdapterByKey: <A extends {
692
752
  adapterKey: OrbitAdapter;
693
753
  } & OrbitGenericAdapter<A>) => A | undefined;
694
754
 
755
+ /**
756
+ * CAIP-2 chain IDs of the public Solana clusters. By CAIP-30, the reference is the first 32 characters of the base58
757
+ * genesis hash of the cluster.
758
+ *
759
+ * Wallet Standard wallets name the same clusters `solana:mainnet`, `solana:devnet` and `solana:testnet`: pass those to
760
+ * wallet calls, and these IDs everywhere a chain is identified (sessions, transactions, APIs).
761
+ */
762
+ declare const SOLANA_CHAIN_IDS: {
763
+ readonly mainnet: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
764
+ readonly devnet: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1";
765
+ readonly testnet: "solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";
766
+ };
767
+ /**
768
+ * A Solana cluster moniker recognized by {@link getSolanaCluster}.
769
+ */
770
+ type SolanaCluster = keyof typeof SOLANA_CHAIN_IDS | 'localnet';
771
+ /**
772
+ * Returns the cluster of a Solana chain identifier, in any of its forms: a cluster moniker (`devnet`, `mainnet-beta`),
773
+ * a Wallet Standard chain (`solana:devnet`), a CAIP-2 chain ID with the genesis hash
774
+ * (`solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1`) or its bare reference. `mainnet-beta` is reported as `mainnet`; the
775
+ * testnet ID from before the testnet genesis reset (`solana:4uhcVJyU9pJkvQyS88uRfhDSfZSm8DoR`) as `testnet`.
776
+ *
777
+ * @example
778
+ * ```typescript
779
+ * getSolanaCluster('solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1'); // "devnet"
780
+ * getSolanaCluster('solana:mainnet-beta'); // "mainnet"
781
+ * getSolanaCluster(1); // undefined
782
+ * ```
783
+ *
784
+ * @param chainId - Chain identifier to read. Monikers are case-sensitive, as in the Wallet Standard.
785
+ * @returns `mainnet`, `devnet`, `testnet` or `localnet`, or `undefined` when the value is not a known Solana chain
786
+ * (numbers, other namespaces, custom clusters).
787
+ */
788
+ declare function getSolanaCluster(chainId: string | number): SolanaCluster | undefined;
789
+ /**
790
+ * Returns the CAIP-2 chain ID of a Solana chain identifier in any form accepted by {@link getSolanaCluster}: the
791
+ * genesis-hash ID from {@link SOLANA_CHAIN_IDS} for the public clusters, and `solana:localnet` for `localnet`, which
792
+ * has no fixed genesis hash.
793
+ *
794
+ * @example
795
+ * ```typescript
796
+ * getSolanaChainId('devnet'); // "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
797
+ * getSolanaChainId('solana:mainnet-beta'); // "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
798
+ * getSolanaChainId('eip155:1'); // undefined
799
+ * ```
800
+ *
801
+ * @param chainId - Chain identifier to convert.
802
+ * @returns The CAIP-2 chain ID, or `undefined` when the value is not a known Solana chain.
803
+ */
804
+ declare function getSolanaChainId(chainId: string | number): string | undefined;
805
+
806
+ /**
807
+ * Polls a predicate until it returns a truthy value.
808
+ *
809
+ * @example
810
+ * ```typescript
811
+ * // Wait up to 10 seconds (50 × 200 ms) for an injected provider.
812
+ * await waitFor(() => typeof window !== 'undefined' && 'ethereum' in window);
813
+ * ```
814
+ *
815
+ * @param predicate - Condition to check on every attempt.
816
+ * @param maxChecks - Maximum number of attempts. Defaults to 50.
817
+ * @param checkIntervalMs - Delay between attempts in milliseconds. Defaults to 200.
818
+ * @returns A promise that resolves as soon as the predicate is truthy.
819
+ * @throws {Error} "Predicate not fulfilled in time" if the predicate is still falsy after `maxChecks` attempts.
820
+ */
695
821
  declare function waitFor(predicate: () => boolean | undefined, maxChecks?: number, checkIntervalMs?: number): Promise<void>;
696
822
 
697
- export { type BaseAdapter, type ChainIdentifierArray, type ConnectorType, OrbitAdapter, type OrbitGenericAdapter, type RecentlyConnectedConnectorData, type RecentlyConnectedConnectorsList, type TuwaErrorState, delay, detectSafeApp, filterUniqueByKey, formatConnectorChainId, formatConnectorName, getAdapterFromConnectorType, getConnectorTypeFromName, getNetworkData, getParsedStorageItem, impersonatedHelpers, isAddress, isInSecureIframe, isSafeApp, isSolanaChain, lastConnectedConnectorHelpers, normalizeError, recentlyConnectedConnectorsListHelpers, selectAdapterByKey, setChainId, waitFor };
823
+ export { type BaseAdapter, type ChainIdentifierArray, type ConnectorType, type LastConnectedConnector, OrbitAdapter, type OrbitGenericAdapter, type RecentlyConnectedConnectorData, type RecentlyConnectedConnectorsList, SOLANA_CHAIN_IDS, type SolanaCluster, type TuwaErrorState, delay, detectSafeApp, filterUniqueByKey, formatConnectorChainId, formatConnectorName, getAdapterFromConnectorType, getConnectorTypeFromName, getNetworkData, getParsedStorageItem, getSolanaChainId, getSolanaCluster, impersonatedHelpers, isAddress, isInSecureIframe, isSafeApp, isSolanaChain, lastConnectedConnectorHelpers, normalizeError, recentlyConnectedConnectorsListHelpers, selectAdapterByKey, setChainId, waitFor };
package/dist/index.d.ts CHANGED
@@ -48,8 +48,10 @@ declare enum OrbitAdapter {
48
48
  * For the Starknet L2 network.
49
49
  * Supports:
50
50
  * - Starknet Mainnet
51
- * - Testnet (Goerli)
51
+ * - Starknet Sepolia testnet
52
52
  * - Other Starknet deployments
53
+ *
54
+ * Reserved for future use: no Orbit chain package implements Starknet yet.
53
55
  */
54
56
  Starknet = "starknet"
55
57
  }
@@ -90,6 +92,10 @@ type OrbitGenericAdapter<A extends {
90
92
  }> = {
91
93
  adapter: A | A[];
92
94
  };
95
+ /**
96
+ * Minimal contract shared by chain adapters: explorer links plus optional name-service lookups.
97
+ * Combine it with a `key: OrbitAdapter` property to register an adapter for {@link selectAdapterByKey}.
98
+ */
93
99
  type BaseAdapter = {
94
100
  /**
95
101
  * Generates blockchain explorer URL
@@ -114,7 +120,7 @@ type ConnectorType = `${OrbitAdapter}:${string}`;
114
120
  *
115
121
  * @example
116
122
  * ```typescript
117
- * const chainIds: ChainIdentifierArray = ['ethereum', 1, 'solana:mainnet-beta'];
123
+ * const chainIds: ChainIdentifierArray = ['ethereum', 1, 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'];
118
124
  * ```
119
125
  */
120
126
  type ChainIdentifierArray = readonly (string | number)[];
@@ -128,24 +134,25 @@ type ChainIdentifierArray = readonly (string | number)[];
128
134
  declare function isAddress(value: string, type?: 'evm' | 'solana' | 'auto'): boolean;
129
135
 
130
136
  /**
131
- * Checks whether the given chain ID belongs to a Solana network.
132
- * Supports common Solana network names: 'devnet', 'testnet', 'mainnet-beta', 'mainnet'.
137
+ * Checks whether the given chain ID belongs to a Solana network: a cluster moniker (`mainnet`, `mainnet-beta`,
138
+ * `devnet`, `testnet`, `localnet`), a Wallet Standard chain such as `solana:devnet`, or a CAIP-2 chain ID with the
139
+ * genesis hash. See {@link getSolanaCluster}.
133
140
  *
134
- * @param {number | string} chainId - The chain ID or chain name.
135
- * @returns {boolean} - True if the chain ID corresponds to a Solana network, false otherwise.
141
+ * @param chainId - The chain ID or chain name.
142
+ * @returns `true` if the chain ID corresponds to a known Solana network, `false` otherwise.
136
143
  */
137
144
  declare function isSolanaChain(chainId: number | string): boolean;
138
145
  /**
139
- * Sets the chain ID to a Solana-specific format if the chain is a Solana network.
146
+ * Turns a Solana chain, in any form accepted by {@link isSolanaChain}, into its CAIP-2 chain ID with the genesis hash
147
+ * (see {@link getSolanaChainId}): `devnet` and `solana:devnet` become `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1`. Other
148
+ * chain IDs are returned unchanged.
140
149
  *
141
- * @param {number | string} chainId - The original chain ID or name.
142
- * @returns {string | number} - The formatted chain ID prefixed with 'solana:' if Solana, otherwise the original.
150
+ * @param chainId - The original chain ID or name.
151
+ * @returns The CAIP-2 chain ID for Solana networks, otherwise the original value.
143
152
  */
144
153
  declare function setChainId(chainId: number | string): string | number;
145
154
 
146
155
  /**
147
- * @name delay
148
- *
149
156
  * Ensures the global 'window' object is available (if running in a browser-like environment),
150
157
  * then pauses execution for a specified duration, and finally resolves the Promise with the given value.
151
158
  *
@@ -188,8 +195,38 @@ declare const delay: <T>(value: T, ms: number) => Promise<T>;
188
195
  */
189
196
  declare function filterUniqueByKey<T>(array: T[], key: keyof T): T[];
190
197
 
198
+ /**
199
+ * Formats a chain ID for use in connector identifiers.
200
+ * Solana clusters become CAIP-2 chain IDs with the genesis hash (see {@link getSolanaChainId}); other string chain
201
+ * IDs are prefixed with the adapter key unless they already have it; numeric EVM chain IDs are kept as is.
202
+ *
203
+ * @example
204
+ * ```typescript
205
+ * formatConnectorChainId('devnet', OrbitAdapter.SOLANA); // "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
206
+ * formatConnectorChainId(1, OrbitAdapter.EVM); // 1
207
+ * ```
208
+ *
209
+ * @param chainId - Numeric EVM chain ID or string chain identifier.
210
+ * @param connectedAdapter - Adapter of the connected wallet.
211
+ * @returns The CAIP-2 chain ID for known Solana clusters, `"<adapter>:<chainId>"` for other string chain IDs, otherwise
212
+ * the numeric chain ID unchanged.
213
+ */
191
214
  declare function formatConnectorChainId(chainId: string | number, connectedAdapter: OrbitAdapter): string | number;
192
215
 
216
+ /**
217
+ * Normalizes a wallet connector display name into a stable identifier.
218
+ * Known names are mapped explicitly (e.g. "Trust Wallet" → "trust", "Base Account" → "coinbase");
219
+ * any other name has its whitespace removed and is lowercased.
220
+ *
221
+ * @example
222
+ * ```typescript
223
+ * formatConnectorName('Trust Wallet'); // "trust"
224
+ * formatConnectorName('Rabby Wallet'); // "rabbywallet"
225
+ * ```
226
+ *
227
+ * @param connectorName - Display name reported by the wallet connector.
228
+ * @returns The normalized connector identifier.
229
+ */
193
230
  declare const formatConnectorName: (connectorName: string) => string;
194
231
 
195
232
  /**
@@ -245,6 +282,15 @@ declare function getAdapterFromConnectorType(connectorType: ConnectorType): Orbi
245
282
  */
246
283
  declare function getConnectorTypeFromName(adapter: OrbitAdapter, name: string): string;
247
284
 
285
+ /**
286
+ * Returns the default network and educational links for an adapter, e.g. to render a
287
+ * "What is a wallet?" section in a connect modal.
288
+ *
289
+ * @param adapter - The adapter to describe.
290
+ * @returns Default chain (`chainId`: `1` for EVM, {@link SOLANA_CHAIN_IDS}`.mainnet` for Solana; `name`) and `links`
291
+ * (`aboutNetwork`, `choseWallet`, `about`) for EVM and Solana, or `undefined` for adapters without network data (e.g.
292
+ * Starknet).
293
+ */
248
294
  declare const getNetworkData: (adapter: OrbitAdapter) => {
249
295
  chain: {
250
296
  chainId: number;
@@ -257,7 +303,7 @@ declare const getNetworkData: (adapter: OrbitAdapter) => {
257
303
  };
258
304
  } | {
259
305
  chain: {
260
- chainId: string;
306
+ chainId: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
261
307
  name: string;
262
308
  };
263
309
  links: {
@@ -317,14 +363,22 @@ declare const impersonatedHelpers: {
317
363
  * @returns The impersonated address or undefined if not set or in SSR context
318
364
  */
319
365
  getImpersonated: () => string | null | undefined;
366
+ /**
367
+ * Removes the impersonated address from localStorage.
368
+ *
369
+ * @returns undefined in SSR context, void in browser
370
+ */
320
371
  removeImpersonated: () => void;
321
372
  };
322
373
 
323
374
  /**
324
375
  * Checks if the current window is running inside a Safe App iframe
325
376
  * by attempting postMessage communication with the parent window.
377
+ * Side effect: posts a `getSafeInfo` message to `window.parent` and listens for the reply until `timeout`.
326
378
  *
327
- * @returns Promise that resolves to true if running inside Safe Wallet, false otherwise
379
+ * @param timeout - How long to wait for the Safe response, in milliseconds. Defaults to 1000.
380
+ * @returns Promise that resolves to true if running inside Safe Wallet, false otherwise (also on the server,
381
+ * outside an iframe, or when not served over HTTPS)
328
382
  */
329
383
  declare function detectSafeApp(timeout?: number): Promise<boolean>;
330
384
  /**
@@ -338,9 +392,15 @@ declare const isInSecureIframe: boolean;
338
392
  */
339
393
  declare const isSafeApp: boolean;
340
394
 
395
+ /**
396
+ * Connection data persisted by {@link lastConnectedConnectorHelpers}.
397
+ */
341
398
  type LastConnectedConnector = {
399
+ /** Connector identifier, e.g. "evm:metamask". */
342
400
  connectorType: ConnectorType;
401
+ /** Chain the wallet was connected to (numeric EVM chain ID or Solana chain identifier). */
343
402
  chainId: number | string;
403
+ /** Connected wallet address, if known. */
344
404
  address?: string;
345
405
  };
346
406
  /**
@@ -360,7 +420,7 @@ declare const lastConnectedConnectorHelpers: {
360
420
  /**
361
421
  * Stores the last connected wallet data in localStorage.
362
422
  *
363
- * @param data - Object containing the wallet type and chain ID.
423
+ * @param data - Connector type, chain ID and optional address of the connected wallet.
364
424
  * @returns undefined in SSR context, void in browser
365
425
  */
366
426
  setLastConnectedConnector: ({ connectorType, chainId, address }: LastConnectedConnector) => void;
@@ -692,6 +752,72 @@ declare const selectAdapterByKey: <A extends {
692
752
  adapterKey: OrbitAdapter;
693
753
  } & OrbitGenericAdapter<A>) => A | undefined;
694
754
 
755
+ /**
756
+ * CAIP-2 chain IDs of the public Solana clusters. By CAIP-30, the reference is the first 32 characters of the base58
757
+ * genesis hash of the cluster.
758
+ *
759
+ * Wallet Standard wallets name the same clusters `solana:mainnet`, `solana:devnet` and `solana:testnet`: pass those to
760
+ * wallet calls, and these IDs everywhere a chain is identified (sessions, transactions, APIs).
761
+ */
762
+ declare const SOLANA_CHAIN_IDS: {
763
+ readonly mainnet: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
764
+ readonly devnet: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1";
765
+ readonly testnet: "solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";
766
+ };
767
+ /**
768
+ * A Solana cluster moniker recognized by {@link getSolanaCluster}.
769
+ */
770
+ type SolanaCluster = keyof typeof SOLANA_CHAIN_IDS | 'localnet';
771
+ /**
772
+ * Returns the cluster of a Solana chain identifier, in any of its forms: a cluster moniker (`devnet`, `mainnet-beta`),
773
+ * a Wallet Standard chain (`solana:devnet`), a CAIP-2 chain ID with the genesis hash
774
+ * (`solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1`) or its bare reference. `mainnet-beta` is reported as `mainnet`; the
775
+ * testnet ID from before the testnet genesis reset (`solana:4uhcVJyU9pJkvQyS88uRfhDSfZSm8DoR`) as `testnet`.
776
+ *
777
+ * @example
778
+ * ```typescript
779
+ * getSolanaCluster('solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1'); // "devnet"
780
+ * getSolanaCluster('solana:mainnet-beta'); // "mainnet"
781
+ * getSolanaCluster(1); // undefined
782
+ * ```
783
+ *
784
+ * @param chainId - Chain identifier to read. Monikers are case-sensitive, as in the Wallet Standard.
785
+ * @returns `mainnet`, `devnet`, `testnet` or `localnet`, or `undefined` when the value is not a known Solana chain
786
+ * (numbers, other namespaces, custom clusters).
787
+ */
788
+ declare function getSolanaCluster(chainId: string | number): SolanaCluster | undefined;
789
+ /**
790
+ * Returns the CAIP-2 chain ID of a Solana chain identifier in any form accepted by {@link getSolanaCluster}: the
791
+ * genesis-hash ID from {@link SOLANA_CHAIN_IDS} for the public clusters, and `solana:localnet` for `localnet`, which
792
+ * has no fixed genesis hash.
793
+ *
794
+ * @example
795
+ * ```typescript
796
+ * getSolanaChainId('devnet'); // "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
797
+ * getSolanaChainId('solana:mainnet-beta'); // "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
798
+ * getSolanaChainId('eip155:1'); // undefined
799
+ * ```
800
+ *
801
+ * @param chainId - Chain identifier to convert.
802
+ * @returns The CAIP-2 chain ID, or `undefined` when the value is not a known Solana chain.
803
+ */
804
+ declare function getSolanaChainId(chainId: string | number): string | undefined;
805
+
806
+ /**
807
+ * Polls a predicate until it returns a truthy value.
808
+ *
809
+ * @example
810
+ * ```typescript
811
+ * // Wait up to 10 seconds (50 × 200 ms) for an injected provider.
812
+ * await waitFor(() => typeof window !== 'undefined' && 'ethereum' in window);
813
+ * ```
814
+ *
815
+ * @param predicate - Condition to check on every attempt.
816
+ * @param maxChecks - Maximum number of attempts. Defaults to 50.
817
+ * @param checkIntervalMs - Delay between attempts in milliseconds. Defaults to 200.
818
+ * @returns A promise that resolves as soon as the predicate is truthy.
819
+ * @throws {Error} "Predicate not fulfilled in time" if the predicate is still falsy after `maxChecks` attempts.
820
+ */
695
821
  declare function waitFor(predicate: () => boolean | undefined, maxChecks?: number, checkIntervalMs?: number): Promise<void>;
696
822
 
697
- export { type BaseAdapter, type ChainIdentifierArray, type ConnectorType, OrbitAdapter, type OrbitGenericAdapter, type RecentlyConnectedConnectorData, type RecentlyConnectedConnectorsList, type TuwaErrorState, delay, detectSafeApp, filterUniqueByKey, formatConnectorChainId, formatConnectorName, getAdapterFromConnectorType, getConnectorTypeFromName, getNetworkData, getParsedStorageItem, impersonatedHelpers, isAddress, isInSecureIframe, isSafeApp, isSolanaChain, lastConnectedConnectorHelpers, normalizeError, recentlyConnectedConnectorsListHelpers, selectAdapterByKey, setChainId, waitFor };
823
+ export { type BaseAdapter, type ChainIdentifierArray, type ConnectorType, type LastConnectedConnector, OrbitAdapter, type OrbitGenericAdapter, type RecentlyConnectedConnectorData, type RecentlyConnectedConnectorsList, SOLANA_CHAIN_IDS, type SolanaCluster, type TuwaErrorState, delay, detectSafeApp, filterUniqueByKey, formatConnectorChainId, formatConnectorName, getAdapterFromConnectorType, getConnectorTypeFromName, getNetworkData, getParsedStorageItem, getSolanaChainId, getSolanaCluster, impersonatedHelpers, isAddress, isInSecureIframe, isSafeApp, isSolanaChain, lastConnectedConnectorHelpers, normalizeError, recentlyConnectedConnectorsListHelpers, selectAdapterByKey, setChainId, waitFor };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var c=(o=>(o.EVM="evm",o.SOLANA="solana",o.Starknet="starknet",o))(c||{});function f(e){return /^0x[a-fA-F0-9]{40}$/.test(e.trim())}function u(e){return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(e.trim())}function A(e,n="auto"){if(!e)return false;let t=e.trim();switch(n){case "evm":return f(t);case "solana":return u(t);default:return f(t)||u(t)}}function l(e){return typeof e=="string"?["devnet","testnet","mainnet-beta","mainnet"].includes(e):false}function S(e){return l(e)?`solana:${e}`:e}var R=(e,n)=>new Promise(t=>{let o=()=>{setTimeout(()=>t(e),n);};typeof window<"u"?o():setTimeout(o,0);});function h(e,n){let t=new Set;return e.filter(o=>{let s=o[n];return t.has(s)?false:(t.add(s),true)})}function O(e,n){return typeof e=="string"?`${n}:${e}`:e}var m=new Map([["Impersonated Connector","impersonatedwallet"],["Safe","safe"],["Trust","trust"],["Trust Wallet","trust"],["Brave \u041A\u043E\u0448\u0435\u043B\u0435\u043A","brave"],["Brave Wallet","brave"],["Base Account","coinbase"]]),I=e=>m.get(e)??e.replace(/\s+/g,"").toLowerCase();function G(e){return e?.split(":")[0]??"evm"}function P(e,n){return `${e}:${n.replace(/\s+/g,"").toLowerCase()}`}var Y=e=>{switch(e){case "evm":return {chain:{chainId:1,name:"Ethereum"},links:{aboutNetwork:"https://ethereum.org/developers/docs/intro-to-ethereum/",choseWallet:"https://ethereum.org/wallets/find-wallet/",about:"https://ethereum.org/wallets/"}};case "solana":return {chain:{chainId:"solana:mainnet",name:"Solana"},links:{aboutNetwork:"https://solana.com/en/learn/what-is-solana",choseWallet:"https://solana.com/en/solana-wallets",about:"https://solana.com/en/learn/what-is-a-wallet"}}}};function a(e){if(typeof window>"u")return;let n=window.localStorage.getItem(e);if(n)try{return JSON.parse(n)}catch(t){console.error(`Error parsing ${e} from localStorage:`,t);return}}var v={impersonatedAddress:typeof window<"u"?window.localStorage.getItem("satellite-connect:impersonatedAddress")??"":"",setImpersonated:e=>typeof window<"u"?window.localStorage.setItem("satellite-connect:impersonatedAddress",e):void 0,getImpersonated:()=>typeof window<"u"?window.localStorage.getItem("satellite-connect:impersonatedAddress"):void 0,removeImpersonated:()=>typeof window<"u"?window.localStorage.removeItem("satellite-connect:impersonatedAddress"):void 0};async function V(e=1e3){return typeof window>"u"||window===window.parent||window.location.protocol!=="https:"?false:new Promise(n=>{let t=setTimeout(()=>{window.removeEventListener("message",o),n(false);},e);function o(i){i.data&&typeof i.data=="object"&&("safeAddress"in i.data||i.data.data&&"safeAddress"in i.data.data||i.data.method==="getInfo")&&(clearTimeout(t),window.removeEventListener("message",o),n(true));}window.addEventListener("message",o);let s=Math.trunc(Math.random()*1e6);window.parent.postMessage({id:s,method:"getSafeInfo",env:{sdkVersion:"1.0.0"}},"*");})}var g=typeof window<"u"&&window!==window.parent&&window.location.protocol==="https:",B=g;var d={STORAGE_KEY:"orbit-core:lastConnectedConnector",lastConnectedConnector:a("orbit-core:lastConnectedConnector"),setLastConnectedConnector:({connectorType:e,chainId:n,address:t})=>typeof window<"u"?window.localStorage.setItem(d.STORAGE_KEY,JSON.stringify({connectorType:e,chainId:n,address:t})):void 0,getLastConnectedConnector:()=>a(d.STORAGE_KEY),removeLastConnectedConnector:()=>typeof window<"u"?window.localStorage.removeItem(d.STORAGE_KEY):void 0};var w=["code","name","shortMessage","details","cause","metaMessages","data","reason","method","transaction","receipt","action","version"];function y(){let e=new WeakSet;return (n,t)=>{if(t===null||typeof t!="object")return typeof t=="function"||typeof t=="symbol"?void 0:typeof t=="bigint"?t.toString():t;if(e.has(t))return "[Circular]";if(e.add(t),t instanceof Error){let o={name:t.name,message:t.message};t.stack&&(o.stack=t.stack);for(let s of Object.keys(t))s in o||(o[s]=t[s]);return o}return t}}function C(e){let n={};if(e&&typeof e=="object"){for(let t of w)t in e&&(n[t]=e[t]);"message"in e&&(n.message=e.message),"stack"in e&&(n.stack=e.stack);}return n}function p(e){try{let n=y(),t=JSON.stringify(e,n);return JSON.parse(t)}catch{return {_serializationError:"Failed to serialize error object"}}}function W(e){if(e==null)return {message:"Unknown error",raw:{originalType:"null"}};if(typeof e=="string")return {message:e,raw:{message:e,originalType:"string"}};if(e instanceof Error){let n=("shortMessage"in e&&typeof e.shortMessage=="string"?e.shortMessage:e.message)||"Unknown error",t=C(e),o=p(e);return {message:n,raw:{...o,...t,originalType:e.name||"Error"}}}return typeof e=="object"?{message:("message"in e&&typeof e.message=="string"?e.message:"shortMessage"in e&&typeof e.shortMessage=="string"?e.shortMessage:"Unknown error")||"Unknown error",raw:{...p(e),originalType:"object"}}:{message:String(e),raw:{value:String(e),originalType:typeof e}}}var r={STORAGE_KEY:"orbit-core:recentlyConnectedConnectorsListHelpers",recentlyConnectedConnectorsList:a("orbit-core:recentlyConnectedConnectorsListHelpers"),setRecentlyConnectedConnectorsList:e=>typeof window<"u"?window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(e)):void 0,getRecentlyConnectedConnectorsList:()=>a(r.STORAGE_KEY),addConnector:(e,n)=>{if(typeof window>"u")return;let o={...r.getRecentlyConnectedConnectorsList()||{},[e]:n};window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(o));},removeConnector:e=>{if(typeof window>"u")return;let n=r.getRecentlyConnectedConnectorsList();if(!n||!(e in n))return;let{[e]:t,...o}=n;window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(o));},hasConnector:e=>{if(typeof window>"u")return;let n=r.getRecentlyConnectedConnectorsList();return n?e in n:false},getConnector:e=>typeof window>"u"?void 0:r.getRecentlyConnectedConnectorsList()?.[e],getConnectorCount:()=>{if(typeof window>"u")return 0;let e=r.getRecentlyConnectedConnectorsList();return e?Object.keys(e).length:0},getConnectorsSortedByTime:()=>{if(typeof window>"u")return [];let e=r.getRecentlyConnectedConnectorsList();return e?Object.entries(e).sort(([,n],[,t])=>t.disconnectedTimestamp-n.disconnectedTimestamp):[]},removeConnectorsOlderThan:e=>{if(typeof window>"u")return;let n=r.getRecentlyConnectedConnectorsList();if(!n)return;let t=Object.fromEntries(Object.entries(n).filter(([,o])=>o.disconnectedTimestamp>=e));window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(t));},removeRecentlyConnectedConnectorsList:()=>typeof window<"u"?window.localStorage.removeItem(r.STORAGE_KEY):void 0};var X=({adapterKey:e,adapter:n})=>{if(Array.isArray(n)){if(n.length===0){console.error("Adapter selection failed: The provided adapters array is empty.");return}let t=n.find(o=>o.key===e);return t||(console.warn(`No adapter found for key: "${e}". Falling back to the first available adapter: "${n[0].key}".`),n[0])}return n};async function ne(e,n=50,t=200){for(let o=0;o<n;o++){if(e())return;await new Promise(s=>setTimeout(s,t));}throw new Error("Predicate not fulfilled in time")}
2
- exports.OrbitAdapter=c;exports.delay=R;exports.detectSafeApp=V;exports.filterUniqueByKey=h;exports.formatConnectorChainId=O;exports.formatConnectorName=I;exports.getAdapterFromConnectorType=G;exports.getConnectorTypeFromName=P;exports.getNetworkData=Y;exports.getParsedStorageItem=a;exports.impersonatedHelpers=v;exports.isAddress=A;exports.isInSecureIframe=g;exports.isSafeApp=B;exports.isSolanaChain=l;exports.lastConnectedConnectorHelpers=d;exports.normalizeError=W;exports.recentlyConnectedConnectorsListHelpers=r;exports.selectAdapterByKey=X;exports.setChainId=S;exports.waitFor=ne;
1
+ 'use strict';var c=(o=>(o.EVM="evm",o.SOLANA="solana",o.Starknet="starknet",o))(c||{});function m(e){return /^0x[a-fA-F0-9]{40}$/.test(e.trim())}function g(e){return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(e.trim())}function x(e,n="auto"){if(!e)return false;let t=e.trim();switch(n){case "evm":return m(t);case "solana":return g(t);default:return m(t)||g(t)}}var u={mainnet:"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",devnet:"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",testnet:"solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z"},f="solana:",w={mainnet:"mainnet","mainnet-beta":"mainnet",devnet:"devnet",testnet:"testnet",localnet:"localnet","5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp":"mainnet",EtWTRABZaYq6iMfeYKouRu166VU2xqa1:"devnet","4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z":"testnet","4uhcVJyU9pJkvQyS88uRfhDSfZSm8DoR":"testnet"};function l(e){if(typeof e!="string")return;let n=e.startsWith(f)?e.slice(f.length):e;return Object.hasOwn(w,n)?w[n]:void 0}function d(e){let n=l(e);if(n)return n==="localnet"?`${f}localnet`:u[n]}function O(e){return l(e)!==void 0}function L(e){return d(e)??e}var N=(e,n)=>new Promise(t=>{let o=()=>{setTimeout(()=>t(e),n);};typeof window<"u"?o():setTimeout(o,0);});function K(e,n){let t=new Set;return e.filter(o=>{let s=o[n];return t.has(s)?false:(t.add(s),true)})}function P(e,n){if(typeof e!="string")return e;if(n==="solana"){let t=d(e);if(t)return t}return e.startsWith(`${n}:`)?e:`${n}:${e}`}var C=new Map([["Impersonated Connector","impersonatedwallet"],["Safe","safe"],["Trust","trust"],["Trust Wallet","trust"],["Brave \u041A\u043E\u0448\u0435\u043B\u0435\u043A","brave"],["Brave Wallet","brave"],["Base Account","coinbase"]]),j=e=>C.get(e)??e.replace(/\s+/g,"").toLowerCase();function F(e){return e?.split(":")[0]??"evm"}function $(e,n){return `${e}:${n.replace(/\s+/g,"").toLowerCase()}`}var B=e=>{switch(e){case "evm":return {chain:{chainId:1,name:"Ethereum"},links:{aboutNetwork:"https://ethereum.org/developers/docs/intro-to-ethereum/",choseWallet:"https://ethereum.org/wallets/find-wallet/",about:"https://ethereum.org/wallets/"}};case "solana":return {chain:{chainId:u.mainnet,name:"Solana"},links:{aboutNetwork:"https://solana.com/en/learn/what-is-solana",choseWallet:"https://solana.com/en/solana-wallets",about:"https://solana.com/en/learn/what-is-a-wallet"}}}};function a(e){if(typeof window>"u")return;let n=window.localStorage.getItem(e);if(n)try{return JSON.parse(n)}catch(t){console.error(`Error parsing ${e} from localStorage:`,t);return}}var Q={impersonatedAddress:typeof window<"u"?window.localStorage.getItem("satellite-connect:impersonatedAddress")??"":"",setImpersonated:e=>typeof window<"u"?window.localStorage.setItem("satellite-connect:impersonatedAddress",e):void 0,getImpersonated:()=>typeof window<"u"?window.localStorage.getItem("satellite-connect:impersonatedAddress"):void 0,removeImpersonated:()=>typeof window<"u"?window.localStorage.removeItem("satellite-connect:impersonatedAddress"):void 0};async function ee(e=1e3){return typeof window>"u"||window===window.parent||window.location.protocol!=="https:"?false:new Promise(n=>{let t=setTimeout(()=>{window.removeEventListener("message",o),n(false);},e);function o(i){i.data&&typeof i.data=="object"&&("safeAddress"in i.data||i.data.data&&"safeAddress"in i.data.data||i.data.method==="getInfo")&&(clearTimeout(t),window.removeEventListener("message",o),n(true));}window.addEventListener("message",o);let s=Math.trunc(Math.random()*1e6);window.parent.postMessage({id:s,method:"getSafeInfo",env:{sdkVersion:"1.0.0"}},"*");})}var S=typeof window<"u"&&window!==window.parent&&window.location.protocol==="https:",ne=S;var p={STORAGE_KEY:"orbit-core:lastConnectedConnector",lastConnectedConnector:a("orbit-core:lastConnectedConnector"),setLastConnectedConnector:({connectorType:e,chainId:n,address:t})=>typeof window<"u"?window.localStorage.setItem(p.STORAGE_KEY,JSON.stringify({connectorType:e,chainId:n,address:t})):void 0,getLastConnectedConnector:()=>a(p.STORAGE_KEY),removeLastConnectedConnector:()=>typeof window<"u"?window.localStorage.removeItem(p.STORAGE_KEY):void 0};var A=["code","name","shortMessage","details","cause","metaMessages","data","reason","method","transaction","receipt","action","version"];function R(){let e=new WeakSet;return (n,t)=>{if(t===null||typeof t!="object")return typeof t=="function"||typeof t=="symbol"?void 0:typeof t=="bigint"?t.toString():t;if(e.has(t))return "[Circular]";if(e.add(t),t instanceof Error){let o={name:t.name,message:t.message};t.stack&&(o.stack=t.stack);for(let s of Object.keys(t))s in o||(o[s]=t[s]);return o}return t}}function b(e){let n={};if(e&&typeof e=="object"){for(let t of A)t in e&&(n[t]=e[t]);"message"in e&&(n.message=e.message),"stack"in e&&(n.stack=e.stack);}return n}function y(e){try{let n=R(),t=JSON.stringify(e,n);return JSON.parse(t)}catch{return {_serializationError:"Failed to serialize error object"}}}function se(e){if(e==null)return {message:"Unknown error",raw:{originalType:"null"}};if(typeof e=="string")return {message:e,raw:{message:e,originalType:"string"}};if(e instanceof Error){let n=("shortMessage"in e&&typeof e.shortMessage=="string"?e.shortMessage:e.message)||"Unknown error",t=b(e),o=y(e);return {message:n,raw:{...o,...t,originalType:e.name||"Error"}}}return typeof e=="object"?{message:("message"in e&&typeof e.message=="string"?e.message:"shortMessage"in e&&typeof e.shortMessage=="string"?e.shortMessage:"Unknown error")||"Unknown error",raw:{...y(e),originalType:"object"}}:{message:String(e),raw:{value:String(e),originalType:typeof e}}}var r={STORAGE_KEY:"orbit-core:recentlyConnectedConnectorsListHelpers",recentlyConnectedConnectorsList:a("orbit-core:recentlyConnectedConnectorsListHelpers"),setRecentlyConnectedConnectorsList:e=>typeof window<"u"?window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(e)):void 0,getRecentlyConnectedConnectorsList:()=>a(r.STORAGE_KEY),addConnector:(e,n)=>{if(typeof window>"u")return;let o={...r.getRecentlyConnectedConnectorsList()||{},[e]:n};window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(o));},removeConnector:e=>{if(typeof window>"u")return;let n=r.getRecentlyConnectedConnectorsList();if(!n||!(e in n))return;let{[e]:t,...o}=n;window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(o));},hasConnector:e=>{if(typeof window>"u")return;let n=r.getRecentlyConnectedConnectorsList();return n?e in n:false},getConnector:e=>typeof window>"u"?void 0:r.getRecentlyConnectedConnectorsList()?.[e],getConnectorCount:()=>{if(typeof window>"u")return 0;let e=r.getRecentlyConnectedConnectorsList();return e?Object.keys(e).length:0},getConnectorsSortedByTime:()=>{if(typeof window>"u")return [];let e=r.getRecentlyConnectedConnectorsList();return e?Object.entries(e).sort(([,n],[,t])=>t.disconnectedTimestamp-n.disconnectedTimestamp):[]},removeConnectorsOlderThan:e=>{if(typeof window>"u")return;let n=r.getRecentlyConnectedConnectorsList();if(!n)return;let t=Object.fromEntries(Object.entries(n).filter(([,o])=>o.disconnectedTimestamp>=e));window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(t));},removeRecentlyConnectedConnectorsList:()=>typeof window<"u"?window.localStorage.removeItem(r.STORAGE_KEY):void 0};var de=({adapterKey:e,adapter:n})=>{if(Array.isArray(n)){if(n.length===0){console.error("Adapter selection failed: The provided adapters array is empty.");return}let t=n.find(o=>o.key===e);return t||(console.warn(`No adapter found for key: "${e}". Falling back to the first available adapter: "${n[0].key}".`),n[0])}return n};async function ue(e,n=50,t=200){for(let o=0;o<n;o++){if(e())return;await new Promise(s=>setTimeout(s,t));}throw new Error("Predicate not fulfilled in time")}
2
+ exports.OrbitAdapter=c;exports.SOLANA_CHAIN_IDS=u;exports.delay=N;exports.detectSafeApp=ee;exports.filterUniqueByKey=K;exports.formatConnectorChainId=P;exports.formatConnectorName=j;exports.getAdapterFromConnectorType=F;exports.getConnectorTypeFromName=$;exports.getNetworkData=B;exports.getParsedStorageItem=a;exports.getSolanaChainId=d;exports.getSolanaCluster=l;exports.impersonatedHelpers=Q;exports.isAddress=x;exports.isInSecureIframe=S;exports.isSafeApp=ne;exports.isSolanaChain=O;exports.lastConnectedConnectorHelpers=p;exports.normalizeError=se;exports.recentlyConnectedConnectorsListHelpers=r;exports.selectAdapterByKey=de;exports.setChainId=L;exports.waitFor=ue;
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- var c=(o=>(o.EVM="evm",o.SOLANA="solana",o.Starknet="starknet",o))(c||{});function f(e){return /^0x[a-fA-F0-9]{40}$/.test(e.trim())}function u(e){return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(e.trim())}function A(e,n="auto"){if(!e)return false;let t=e.trim();switch(n){case "evm":return f(t);case "solana":return u(t);default:return f(t)||u(t)}}function l(e){return typeof e=="string"?["devnet","testnet","mainnet-beta","mainnet"].includes(e):false}function S(e){return l(e)?`solana:${e}`:e}var R=(e,n)=>new Promise(t=>{let o=()=>{setTimeout(()=>t(e),n);};typeof window<"u"?o():setTimeout(o,0);});function h(e,n){let t=new Set;return e.filter(o=>{let s=o[n];return t.has(s)?false:(t.add(s),true)})}function O(e,n){return typeof e=="string"?`${n}:${e}`:e}var m=new Map([["Impersonated Connector","impersonatedwallet"],["Safe","safe"],["Trust","trust"],["Trust Wallet","trust"],["Brave \u041A\u043E\u0448\u0435\u043B\u0435\u043A","brave"],["Brave Wallet","brave"],["Base Account","coinbase"]]),I=e=>m.get(e)??e.replace(/\s+/g,"").toLowerCase();function G(e){return e?.split(":")[0]??"evm"}function P(e,n){return `${e}:${n.replace(/\s+/g,"").toLowerCase()}`}var Y=e=>{switch(e){case "evm":return {chain:{chainId:1,name:"Ethereum"},links:{aboutNetwork:"https://ethereum.org/developers/docs/intro-to-ethereum/",choseWallet:"https://ethereum.org/wallets/find-wallet/",about:"https://ethereum.org/wallets/"}};case "solana":return {chain:{chainId:"solana:mainnet",name:"Solana"},links:{aboutNetwork:"https://solana.com/en/learn/what-is-solana",choseWallet:"https://solana.com/en/solana-wallets",about:"https://solana.com/en/learn/what-is-a-wallet"}}}};function a(e){if(typeof window>"u")return;let n=window.localStorage.getItem(e);if(n)try{return JSON.parse(n)}catch(t){console.error(`Error parsing ${e} from localStorage:`,t);return}}var v={impersonatedAddress:typeof window<"u"?window.localStorage.getItem("satellite-connect:impersonatedAddress")??"":"",setImpersonated:e=>typeof window<"u"?window.localStorage.setItem("satellite-connect:impersonatedAddress",e):void 0,getImpersonated:()=>typeof window<"u"?window.localStorage.getItem("satellite-connect:impersonatedAddress"):void 0,removeImpersonated:()=>typeof window<"u"?window.localStorage.removeItem("satellite-connect:impersonatedAddress"):void 0};async function V(e=1e3){return typeof window>"u"||window===window.parent||window.location.protocol!=="https:"?false:new Promise(n=>{let t=setTimeout(()=>{window.removeEventListener("message",o),n(false);},e);function o(i){i.data&&typeof i.data=="object"&&("safeAddress"in i.data||i.data.data&&"safeAddress"in i.data.data||i.data.method==="getInfo")&&(clearTimeout(t),window.removeEventListener("message",o),n(true));}window.addEventListener("message",o);let s=Math.trunc(Math.random()*1e6);window.parent.postMessage({id:s,method:"getSafeInfo",env:{sdkVersion:"1.0.0"}},"*");})}var g=typeof window<"u"&&window!==window.parent&&window.location.protocol==="https:",B=g;var d={STORAGE_KEY:"orbit-core:lastConnectedConnector",lastConnectedConnector:a("orbit-core:lastConnectedConnector"),setLastConnectedConnector:({connectorType:e,chainId:n,address:t})=>typeof window<"u"?window.localStorage.setItem(d.STORAGE_KEY,JSON.stringify({connectorType:e,chainId:n,address:t})):void 0,getLastConnectedConnector:()=>a(d.STORAGE_KEY),removeLastConnectedConnector:()=>typeof window<"u"?window.localStorage.removeItem(d.STORAGE_KEY):void 0};var w=["code","name","shortMessage","details","cause","metaMessages","data","reason","method","transaction","receipt","action","version"];function y(){let e=new WeakSet;return (n,t)=>{if(t===null||typeof t!="object")return typeof t=="function"||typeof t=="symbol"?void 0:typeof t=="bigint"?t.toString():t;if(e.has(t))return "[Circular]";if(e.add(t),t instanceof Error){let o={name:t.name,message:t.message};t.stack&&(o.stack=t.stack);for(let s of Object.keys(t))s in o||(o[s]=t[s]);return o}return t}}function C(e){let n={};if(e&&typeof e=="object"){for(let t of w)t in e&&(n[t]=e[t]);"message"in e&&(n.message=e.message),"stack"in e&&(n.stack=e.stack);}return n}function p(e){try{let n=y(),t=JSON.stringify(e,n);return JSON.parse(t)}catch{return {_serializationError:"Failed to serialize error object"}}}function W(e){if(e==null)return {message:"Unknown error",raw:{originalType:"null"}};if(typeof e=="string")return {message:e,raw:{message:e,originalType:"string"}};if(e instanceof Error){let n=("shortMessage"in e&&typeof e.shortMessage=="string"?e.shortMessage:e.message)||"Unknown error",t=C(e),o=p(e);return {message:n,raw:{...o,...t,originalType:e.name||"Error"}}}return typeof e=="object"?{message:("message"in e&&typeof e.message=="string"?e.message:"shortMessage"in e&&typeof e.shortMessage=="string"?e.shortMessage:"Unknown error")||"Unknown error",raw:{...p(e),originalType:"object"}}:{message:String(e),raw:{value:String(e),originalType:typeof e}}}var r={STORAGE_KEY:"orbit-core:recentlyConnectedConnectorsListHelpers",recentlyConnectedConnectorsList:a("orbit-core:recentlyConnectedConnectorsListHelpers"),setRecentlyConnectedConnectorsList:e=>typeof window<"u"?window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(e)):void 0,getRecentlyConnectedConnectorsList:()=>a(r.STORAGE_KEY),addConnector:(e,n)=>{if(typeof window>"u")return;let o={...r.getRecentlyConnectedConnectorsList()||{},[e]:n};window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(o));},removeConnector:e=>{if(typeof window>"u")return;let n=r.getRecentlyConnectedConnectorsList();if(!n||!(e in n))return;let{[e]:t,...o}=n;window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(o));},hasConnector:e=>{if(typeof window>"u")return;let n=r.getRecentlyConnectedConnectorsList();return n?e in n:false},getConnector:e=>typeof window>"u"?void 0:r.getRecentlyConnectedConnectorsList()?.[e],getConnectorCount:()=>{if(typeof window>"u")return 0;let e=r.getRecentlyConnectedConnectorsList();return e?Object.keys(e).length:0},getConnectorsSortedByTime:()=>{if(typeof window>"u")return [];let e=r.getRecentlyConnectedConnectorsList();return e?Object.entries(e).sort(([,n],[,t])=>t.disconnectedTimestamp-n.disconnectedTimestamp):[]},removeConnectorsOlderThan:e=>{if(typeof window>"u")return;let n=r.getRecentlyConnectedConnectorsList();if(!n)return;let t=Object.fromEntries(Object.entries(n).filter(([,o])=>o.disconnectedTimestamp>=e));window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(t));},removeRecentlyConnectedConnectorsList:()=>typeof window<"u"?window.localStorage.removeItem(r.STORAGE_KEY):void 0};var X=({adapterKey:e,adapter:n})=>{if(Array.isArray(n)){if(n.length===0){console.error("Adapter selection failed: The provided adapters array is empty.");return}let t=n.find(o=>o.key===e);return t||(console.warn(`No adapter found for key: "${e}". Falling back to the first available adapter: "${n[0].key}".`),n[0])}return n};async function ne(e,n=50,t=200){for(let o=0;o<n;o++){if(e())return;await new Promise(s=>setTimeout(s,t));}throw new Error("Predicate not fulfilled in time")}
2
- export{c as OrbitAdapter,R as delay,V as detectSafeApp,h as filterUniqueByKey,O as formatConnectorChainId,I as formatConnectorName,G as getAdapterFromConnectorType,P as getConnectorTypeFromName,Y as getNetworkData,a as getParsedStorageItem,v as impersonatedHelpers,A as isAddress,g as isInSecureIframe,B as isSafeApp,l as isSolanaChain,d as lastConnectedConnectorHelpers,W as normalizeError,r as recentlyConnectedConnectorsListHelpers,X as selectAdapterByKey,S as setChainId,ne as waitFor};
1
+ var c=(o=>(o.EVM="evm",o.SOLANA="solana",o.Starknet="starknet",o))(c||{});function m(e){return /^0x[a-fA-F0-9]{40}$/.test(e.trim())}function g(e){return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(e.trim())}function x(e,n="auto"){if(!e)return false;let t=e.trim();switch(n){case "evm":return m(t);case "solana":return g(t);default:return m(t)||g(t)}}var u={mainnet:"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",devnet:"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",testnet:"solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z"},f="solana:",w={mainnet:"mainnet","mainnet-beta":"mainnet",devnet:"devnet",testnet:"testnet",localnet:"localnet","5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp":"mainnet",EtWTRABZaYq6iMfeYKouRu166VU2xqa1:"devnet","4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z":"testnet","4uhcVJyU9pJkvQyS88uRfhDSfZSm8DoR":"testnet"};function l(e){if(typeof e!="string")return;let n=e.startsWith(f)?e.slice(f.length):e;return Object.hasOwn(w,n)?w[n]:void 0}function d(e){let n=l(e);if(n)return n==="localnet"?`${f}localnet`:u[n]}function O(e){return l(e)!==void 0}function L(e){return d(e)??e}var N=(e,n)=>new Promise(t=>{let o=()=>{setTimeout(()=>t(e),n);};typeof window<"u"?o():setTimeout(o,0);});function K(e,n){let t=new Set;return e.filter(o=>{let s=o[n];return t.has(s)?false:(t.add(s),true)})}function P(e,n){if(typeof e!="string")return e;if(n==="solana"){let t=d(e);if(t)return t}return e.startsWith(`${n}:`)?e:`${n}:${e}`}var C=new Map([["Impersonated Connector","impersonatedwallet"],["Safe","safe"],["Trust","trust"],["Trust Wallet","trust"],["Brave \u041A\u043E\u0448\u0435\u043B\u0435\u043A","brave"],["Brave Wallet","brave"],["Base Account","coinbase"]]),j=e=>C.get(e)??e.replace(/\s+/g,"").toLowerCase();function F(e){return e?.split(":")[0]??"evm"}function $(e,n){return `${e}:${n.replace(/\s+/g,"").toLowerCase()}`}var B=e=>{switch(e){case "evm":return {chain:{chainId:1,name:"Ethereum"},links:{aboutNetwork:"https://ethereum.org/developers/docs/intro-to-ethereum/",choseWallet:"https://ethereum.org/wallets/find-wallet/",about:"https://ethereum.org/wallets/"}};case "solana":return {chain:{chainId:u.mainnet,name:"Solana"},links:{aboutNetwork:"https://solana.com/en/learn/what-is-solana",choseWallet:"https://solana.com/en/solana-wallets",about:"https://solana.com/en/learn/what-is-a-wallet"}}}};function a(e){if(typeof window>"u")return;let n=window.localStorage.getItem(e);if(n)try{return JSON.parse(n)}catch(t){console.error(`Error parsing ${e} from localStorage:`,t);return}}var Q={impersonatedAddress:typeof window<"u"?window.localStorage.getItem("satellite-connect:impersonatedAddress")??"":"",setImpersonated:e=>typeof window<"u"?window.localStorage.setItem("satellite-connect:impersonatedAddress",e):void 0,getImpersonated:()=>typeof window<"u"?window.localStorage.getItem("satellite-connect:impersonatedAddress"):void 0,removeImpersonated:()=>typeof window<"u"?window.localStorage.removeItem("satellite-connect:impersonatedAddress"):void 0};async function ee(e=1e3){return typeof window>"u"||window===window.parent||window.location.protocol!=="https:"?false:new Promise(n=>{let t=setTimeout(()=>{window.removeEventListener("message",o),n(false);},e);function o(i){i.data&&typeof i.data=="object"&&("safeAddress"in i.data||i.data.data&&"safeAddress"in i.data.data||i.data.method==="getInfo")&&(clearTimeout(t),window.removeEventListener("message",o),n(true));}window.addEventListener("message",o);let s=Math.trunc(Math.random()*1e6);window.parent.postMessage({id:s,method:"getSafeInfo",env:{sdkVersion:"1.0.0"}},"*");})}var S=typeof window<"u"&&window!==window.parent&&window.location.protocol==="https:",ne=S;var p={STORAGE_KEY:"orbit-core:lastConnectedConnector",lastConnectedConnector:a("orbit-core:lastConnectedConnector"),setLastConnectedConnector:({connectorType:e,chainId:n,address:t})=>typeof window<"u"?window.localStorage.setItem(p.STORAGE_KEY,JSON.stringify({connectorType:e,chainId:n,address:t})):void 0,getLastConnectedConnector:()=>a(p.STORAGE_KEY),removeLastConnectedConnector:()=>typeof window<"u"?window.localStorage.removeItem(p.STORAGE_KEY):void 0};var A=["code","name","shortMessage","details","cause","metaMessages","data","reason","method","transaction","receipt","action","version"];function R(){let e=new WeakSet;return (n,t)=>{if(t===null||typeof t!="object")return typeof t=="function"||typeof t=="symbol"?void 0:typeof t=="bigint"?t.toString():t;if(e.has(t))return "[Circular]";if(e.add(t),t instanceof Error){let o={name:t.name,message:t.message};t.stack&&(o.stack=t.stack);for(let s of Object.keys(t))s in o||(o[s]=t[s]);return o}return t}}function b(e){let n={};if(e&&typeof e=="object"){for(let t of A)t in e&&(n[t]=e[t]);"message"in e&&(n.message=e.message),"stack"in e&&(n.stack=e.stack);}return n}function y(e){try{let n=R(),t=JSON.stringify(e,n);return JSON.parse(t)}catch{return {_serializationError:"Failed to serialize error object"}}}function se(e){if(e==null)return {message:"Unknown error",raw:{originalType:"null"}};if(typeof e=="string")return {message:e,raw:{message:e,originalType:"string"}};if(e instanceof Error){let n=("shortMessage"in e&&typeof e.shortMessage=="string"?e.shortMessage:e.message)||"Unknown error",t=b(e),o=y(e);return {message:n,raw:{...o,...t,originalType:e.name||"Error"}}}return typeof e=="object"?{message:("message"in e&&typeof e.message=="string"?e.message:"shortMessage"in e&&typeof e.shortMessage=="string"?e.shortMessage:"Unknown error")||"Unknown error",raw:{...y(e),originalType:"object"}}:{message:String(e),raw:{value:String(e),originalType:typeof e}}}var r={STORAGE_KEY:"orbit-core:recentlyConnectedConnectorsListHelpers",recentlyConnectedConnectorsList:a("orbit-core:recentlyConnectedConnectorsListHelpers"),setRecentlyConnectedConnectorsList:e=>typeof window<"u"?window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(e)):void 0,getRecentlyConnectedConnectorsList:()=>a(r.STORAGE_KEY),addConnector:(e,n)=>{if(typeof window>"u")return;let o={...r.getRecentlyConnectedConnectorsList()||{},[e]:n};window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(o));},removeConnector:e=>{if(typeof window>"u")return;let n=r.getRecentlyConnectedConnectorsList();if(!n||!(e in n))return;let{[e]:t,...o}=n;window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(o));},hasConnector:e=>{if(typeof window>"u")return;let n=r.getRecentlyConnectedConnectorsList();return n?e in n:false},getConnector:e=>typeof window>"u"?void 0:r.getRecentlyConnectedConnectorsList()?.[e],getConnectorCount:()=>{if(typeof window>"u")return 0;let e=r.getRecentlyConnectedConnectorsList();return e?Object.keys(e).length:0},getConnectorsSortedByTime:()=>{if(typeof window>"u")return [];let e=r.getRecentlyConnectedConnectorsList();return e?Object.entries(e).sort(([,n],[,t])=>t.disconnectedTimestamp-n.disconnectedTimestamp):[]},removeConnectorsOlderThan:e=>{if(typeof window>"u")return;let n=r.getRecentlyConnectedConnectorsList();if(!n)return;let t=Object.fromEntries(Object.entries(n).filter(([,o])=>o.disconnectedTimestamp>=e));window.localStorage.setItem(r.STORAGE_KEY,JSON.stringify(t));},removeRecentlyConnectedConnectorsList:()=>typeof window<"u"?window.localStorage.removeItem(r.STORAGE_KEY):void 0};var de=({adapterKey:e,adapter:n})=>{if(Array.isArray(n)){if(n.length===0){console.error("Adapter selection failed: The provided adapters array is empty.");return}let t=n.find(o=>o.key===e);return t||(console.warn(`No adapter found for key: "${e}". Falling back to the first available adapter: "${n[0].key}".`),n[0])}return n};async function ue(e,n=50,t=200){for(let o=0;o<n;o++){if(e())return;await new Promise(s=>setTimeout(s,t));}throw new Error("Predicate not fulfilled in time")}
2
+ export{c as OrbitAdapter,u as SOLANA_CHAIN_IDS,N as delay,ee as detectSafeApp,K as filterUniqueByKey,P as formatConnectorChainId,j as formatConnectorName,F as getAdapterFromConnectorType,$ as getConnectorTypeFromName,B as getNetworkData,a as getParsedStorageItem,d as getSolanaChainId,l as getSolanaCluster,Q as impersonatedHelpers,x as isAddress,S as isInSecureIframe,ne as isSafeApp,O as isSolanaChain,p as lastConnectedConnectorHelpers,se as normalizeError,r as recentlyConnectedConnectorsListHelpers,de as selectAdapterByKey,L as setChainId,ue as waitFor};
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@tuwaio/orbit-core",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "private": false,
5
5
  "author": "Oleksandr Tkach",
6
6
  "license": "Apache-2.0",
7
- "description": "Layer 1 (L1) of the TUWA Ecosystem. Framework-agnostic library for abstracting core multi-chain types, errors, and localStorage helper utilities.",
7
+ "description": "L1 core of Orbit Utils (TUWA): zero-dependency, framework-agnostic multi-chain types, connector and address helpers, error normalization and SSR-safe connection persistence.",
8
8
  "main": "./dist/index.js",
9
9
  "module": "./dist/index.mjs",
10
10
  "types": "./dist/index.d.ts",
@@ -16,9 +16,14 @@
16
16
  "socket.json"
17
17
  ],
18
18
  "keywords": [
19
+ "tuwa",
20
+ "orbit",
19
21
  "web3",
22
+ "multi-chain",
23
+ "evm",
24
+ "solana",
20
25
  "typescript",
21
- "core",
26
+ "framework-agnostic",
22
27
  "headless"
23
28
  ],
24
29
  "repository": {
@@ -38,7 +43,7 @@
38
43
  ],
39
44
  "devDependencies": {
40
45
  "tsup": "^8.5.1",
41
- "typescript": "^6.0.3"
46
+ "typescript": "6.0.3"
42
47
  },
43
48
  "scripts": {
44
49
  "start": "tsup src/index.ts --watch",