@tuwaio/orbit-core 0.2.15 → 0.3.1

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,21 @@
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
+ - **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.
17
+ - **Connection persistence:** `lastConnectedConnectorHelpers` and `recentlyConnectedConnectorsListHelpers` keep connection history in `localStorage` and do nothing during SSR.
18
+ - **Runtime utilities:** `detectSafeApp` (Safe{Wallet} iframe detection), `waitFor`, `delay`, `filterUniqueByKey`, and `impersonatedHelpers` for development and testing.
16
19
 
17
20
  ---
18
21
 
@@ -24,71 +27,87 @@ pnpm add @tuwaio/orbit-core
24
27
 
25
28
  ---
26
29
 
27
- ## 🚀 Architectural Integration
30
+ ## 🚀 Usage
28
31
 
29
- ### Runtime Adapter Resolution
32
+ ### Resolving the active adapter
30
33
 
31
- Register and resolve chain-specific primitive adapters dynamically:
34
+ `BaseAdapter` describes what an adapter can do; add a `key` to register it for a chain family:
32
35
 
33
36
  ```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
- ];
37
+ import { type BaseAdapter, OrbitAdapter, selectAdapterByKey } from '@tuwaio/orbit-core';
47
38
 
48
- // Dynamically select target execution adapter
49
- const activeAdapter = selectAdapterByKey({
50
- adapterKey: OrbitAdapter.SOLANA,
51
- adapter: adapters,
52
- });
39
+ type ExplorerAdapter = BaseAdapter & { key: OrbitAdapter };
53
40
 
54
- if (activeAdapter) {
55
- console.log(activeAdapter.getExplorerUrl('tx/0x...', 'mainnet-beta'));
56
- }
41
+ const adapters: ExplorerAdapter[] = [
42
+ { key: OrbitAdapter.EVM, getExplorerUrl: (path) => `https://etherscan.io/${path ?? ''}` },
43
+ { key: OrbitAdapter.SOLANA, getExplorerUrl: (path) => `https://explorer.solana.com/${path ?? ''}` },
44
+ ];
45
+
46
+ const solanaAdapter = selectAdapterByKey({ adapterKey: OrbitAdapter.SOLANA, adapter: adapters });
47
+ solanaAdapter?.getExplorerUrl('tx/<signature>'); // "https://explorer.solana.com/tx/<signature>"
57
48
  ```
58
49
 
59
- ### Connection State Storage
50
+ If no adapter matches the key, `selectAdapterByKey` falls back to the first adapter in the array and logs a warning.
60
51
 
61
- Read and write connected connector metadata securely with `localStorage` fallback checks:
52
+ ### Persisting the last connection
62
53
 
63
54
  ```typescript
64
55
  import { lastConnectedConnectorHelpers } from '@tuwaio/orbit-core';
65
56
 
66
- // Persist metadata
67
57
  lastConnectedConnectorHelpers.setLastConnectedConnector({
68
58
  connectorType: 'evm:metamask',
69
59
  chainId: 1,
70
- address: '0x123...',
60
+ address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
71
61
  });
72
62
 
73
- // Retrieve connection metadata safely during client-side hydration
63
+ // Returns undefined on the server and when nothing is stored.
74
64
  const lastConnected = lastConnectedConnectorHelpers.getLastConnectedConnector();
75
- console.log(lastConnected?.address); // "0x123..."
76
65
  ```
77
66
 
67
+ ### Normalizing errors
68
+
69
+ ```typescript
70
+ import { normalizeError } from '@tuwaio/orbit-core';
71
+
72
+ declare function sendTransaction(): Promise<void>;
73
+
74
+ try {
75
+ await sendTransaction();
76
+ } catch (error) {
77
+ // `message` prefers viem's `shortMessage`; `raw` is a JSON-safe copy of the error details.
78
+ const { message, raw } = normalizeError(error);
79
+ }
80
+ ```
81
+
82
+ ### Validating addresses
83
+
84
+ ```typescript
85
+ import { isAddress } from '@tuwaio/orbit-core';
86
+
87
+ isAddress('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'); // true (auto-detected as EVM)
88
+ isAddress('So11111111111111111111111111111111111111112', 'solana'); // true
89
+ ```
90
+
91
+ `isAddress` checks the address format only (hex length or Base58 alphabet); it does not verify EVM checksums.
92
+
78
93
  ---
79
94
 
80
- ## 🔧 API & Module Architecture
95
+ ## 🗄️ Browser Storage
81
96
 
82
- `@tuwaio/orbit-core` exposes the following modules:
97
+ The storage helpers write the following `localStorage` keys. Clear them to reset the connection state of a user:
83
98
 
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`.
99
+ | Key | Written by |
100
+ | --------------------------------------------------- | ---------------------------------------- |
101
+ | `orbit-core:lastConnectedConnector` | `lastConnectedConnectorHelpers` |
102
+ | `orbit-core:recentlyConnectedConnectorsListHelpers` | `recentlyConnectedConnectorsListHelpers` |
103
+ | `satellite-connect:impersonatedAddress` | `impersonatedHelpers` |
89
104
 
90
105
  ---
91
106
 
107
+ ## 📚 API Reference
108
+
109
+ 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)**.
110
+
92
111
  ## 📄 License
93
112
 
94
- Licensed under the **Apache-2.0 License**. See the [LICENSE](./LICENSE) file for details.
113
+ 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
@@ -128,8 +134,22 @@ type ChainIdentifierArray = readonly (string | number)[];
128
134
  declare function isAddress(value: string, type?: 'evm' | 'solana' | 'auto'): boolean;
129
135
 
130
136
  /**
131
- * @name delay
137
+ * Checks whether the given chain ID belongs to a Solana network.
138
+ * Supports common Solana network names: 'devnet', 'testnet', 'mainnet-beta', 'mainnet'.
132
139
  *
140
+ * @param {number | string} chainId - The chain ID or chain name.
141
+ * @returns {boolean} - True if the chain ID corresponds to a Solana network, false otherwise.
142
+ */
143
+ declare function isSolanaChain(chainId: number | string): boolean;
144
+ /**
145
+ * Sets the chain ID to a Solana-specific format if the chain is a Solana network.
146
+ *
147
+ * @param {number | string} chainId - The original chain ID or name.
148
+ * @returns {string | number} - The formatted chain ID prefixed with 'solana:' if Solana, otherwise the original.
149
+ */
150
+ declare function setChainId(chainId: number | string): string | number;
151
+
152
+ /**
133
153
  * Ensures the global 'window' object is available (if running in a browser-like environment),
134
154
  * then pauses execution for a specified duration, and finally resolves the Promise with the given value.
135
155
  *
@@ -172,8 +192,36 @@ declare const delay: <T>(value: T, ms: number) => Promise<T>;
172
192
  */
173
193
  declare function filterUniqueByKey<T>(array: T[], key: keyof T): T[];
174
194
 
195
+ /**
196
+ * Formats a chain ID for use in connector identifiers.
197
+ * String chain IDs (e.g. Solana cluster names) are prefixed with the adapter key; numeric EVM chain IDs are kept as is.
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * formatConnectorChainId('devnet', OrbitAdapter.SOLANA); // "solana:devnet"
202
+ * formatConnectorChainId(1, OrbitAdapter.EVM); // 1
203
+ * ```
204
+ *
205
+ * @param chainId - Numeric EVM chain ID or string chain identifier.
206
+ * @param connectedAdapter - Adapter of the connected wallet.
207
+ * @returns `"<adapter>:<chainId>"` for string chain IDs, otherwise the numeric chain ID unchanged.
208
+ */
175
209
  declare function formatConnectorChainId(chainId: string | number, connectedAdapter: OrbitAdapter): string | number;
176
210
 
211
+ /**
212
+ * Normalizes a wallet connector display name into a stable identifier.
213
+ * Known names are mapped explicitly (e.g. "Trust Wallet" → "trust", "Base Account" → "coinbase");
214
+ * any other name has its whitespace removed and is lowercased.
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * formatConnectorName('Trust Wallet'); // "trust"
219
+ * formatConnectorName('Rabby Wallet'); // "rabbywallet"
220
+ * ```
221
+ *
222
+ * @param connectorName - Display name reported by the wallet connector.
223
+ * @returns The normalized connector identifier.
224
+ */
177
225
  declare const formatConnectorName: (connectorName: string) => string;
178
226
 
179
227
  /**
@@ -229,6 +277,14 @@ declare function getAdapterFromConnectorType(connectorType: ConnectorType): Orbi
229
277
  */
230
278
  declare function getConnectorTypeFromName(adapter: OrbitAdapter, name: string): string;
231
279
 
280
+ /**
281
+ * Returns the default network and educational links for an adapter, e.g. to render a
282
+ * "What is a wallet?" section in a connect modal.
283
+ *
284
+ * @param adapter - The adapter to describe.
285
+ * @returns Default chain (`chainId`, `name`) and `links` (`aboutNetwork`, `choseWallet`, `about`) for EVM and Solana,
286
+ * or `undefined` for adapters without network data (e.g. Starknet).
287
+ */
232
288
  declare const getNetworkData: (adapter: OrbitAdapter) => {
233
289
  chain: {
234
290
  chainId: number;
@@ -301,14 +357,22 @@ declare const impersonatedHelpers: {
301
357
  * @returns The impersonated address or undefined if not set or in SSR context
302
358
  */
303
359
  getImpersonated: () => string | null | undefined;
360
+ /**
361
+ * Removes the impersonated address from localStorage.
362
+ *
363
+ * @returns undefined in SSR context, void in browser
364
+ */
304
365
  removeImpersonated: () => void;
305
366
  };
306
367
 
307
368
  /**
308
369
  * Checks if the current window is running inside a Safe App iframe
309
370
  * by attempting postMessage communication with the parent window.
371
+ * Side effect: posts a `getSafeInfo` message to `window.parent` and listens for the reply until `timeout`.
310
372
  *
311
- * @returns Promise that resolves to true if running inside Safe Wallet, false otherwise
373
+ * @param timeout - How long to wait for the Safe response, in milliseconds. Defaults to 1000.
374
+ * @returns Promise that resolves to true if running inside Safe Wallet, false otherwise (also on the server,
375
+ * outside an iframe, or when not served over HTTPS)
312
376
  */
313
377
  declare function detectSafeApp(timeout?: number): Promise<boolean>;
314
378
  /**
@@ -322,9 +386,15 @@ declare const isInSecureIframe: boolean;
322
386
  */
323
387
  declare const isSafeApp: boolean;
324
388
 
389
+ /**
390
+ * Connection data persisted by {@link lastConnectedConnectorHelpers}.
391
+ */
325
392
  type LastConnectedConnector = {
393
+ /** Connector identifier, e.g. "evm:metamask". */
326
394
  connectorType: ConnectorType;
395
+ /** Chain the wallet was connected to (numeric EVM chain ID or Solana chain identifier). */
327
396
  chainId: number | string;
397
+ /** Connected wallet address, if known. */
328
398
  address?: string;
329
399
  };
330
400
  /**
@@ -344,7 +414,7 @@ declare const lastConnectedConnectorHelpers: {
344
414
  /**
345
415
  * Stores the last connected wallet data in localStorage.
346
416
  *
347
- * @param data - Object containing the wallet type and chain ID.
417
+ * @param data - Connector type, chain ID and optional address of the connected wallet.
348
418
  * @returns undefined in SSR context, void in browser
349
419
  */
350
420
  setLastConnectedConnector: ({ connectorType, chainId, address }: LastConnectedConnector) => void;
@@ -676,22 +746,21 @@ declare const selectAdapterByKey: <A extends {
676
746
  adapterKey: OrbitAdapter;
677
747
  } & OrbitGenericAdapter<A>) => A | undefined;
678
748
 
679
- declare function waitFor(predicate: () => boolean | undefined, maxChecks?: number, checkIntervalMs?: number): Promise<void>;
680
-
681
749
  /**
682
- * Checks whether the given chain ID belongs to a Solana network.
683
- * Supports common Solana network names: 'devnet', 'testnet', 'mainnet-beta', 'mainnet'.
750
+ * Polls a predicate until it returns a truthy value.
684
751
  *
685
- * @param {number | string} chainId - The chain ID or chain name.
686
- * @returns {boolean} - True if the chain ID corresponds to a Solana network, false otherwise.
687
- */
688
- declare function isSolanaChain(chainId: number | string): boolean;
689
- /**
690
- * Sets the chain ID to a Solana-specific format if the chain is a Solana network.
752
+ * @example
753
+ * ```typescript
754
+ * // Wait up to 10 seconds (50 × 200 ms) for an injected provider.
755
+ * await waitFor(() => typeof window !== 'undefined' && 'ethereum' in window);
756
+ * ```
691
757
  *
692
- * @param {number | string} chainId - The original chain ID or name.
693
- * @returns {string | number} - The formatted chain ID prefixed with 'solana:' if Solana, otherwise the original.
758
+ * @param predicate - Condition to check on every attempt.
759
+ * @param maxChecks - Maximum number of attempts. Defaults to 50.
760
+ * @param checkIntervalMs - Delay between attempts in milliseconds. Defaults to 200.
761
+ * @returns A promise that resolves as soon as the predicate is truthy.
762
+ * @throws {Error} "Predicate not fulfilled in time" if the predicate is still falsy after `maxChecks` attempts.
694
763
  */
695
- declare function setChainId(chainId: number | string): string | number;
764
+ declare function waitFor(predicate: () => boolean | undefined, maxChecks?: number, checkIntervalMs?: number): Promise<void>;
696
765
 
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 };
766
+ export { type BaseAdapter, type ChainIdentifierArray, type ConnectorType, type LastConnectedConnector, 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 };
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
@@ -128,8 +134,22 @@ type ChainIdentifierArray = readonly (string | number)[];
128
134
  declare function isAddress(value: string, type?: 'evm' | 'solana' | 'auto'): boolean;
129
135
 
130
136
  /**
131
- * @name delay
137
+ * Checks whether the given chain ID belongs to a Solana network.
138
+ * Supports common Solana network names: 'devnet', 'testnet', 'mainnet-beta', 'mainnet'.
132
139
  *
140
+ * @param {number | string} chainId - The chain ID or chain name.
141
+ * @returns {boolean} - True if the chain ID corresponds to a Solana network, false otherwise.
142
+ */
143
+ declare function isSolanaChain(chainId: number | string): boolean;
144
+ /**
145
+ * Sets the chain ID to a Solana-specific format if the chain is a Solana network.
146
+ *
147
+ * @param {number | string} chainId - The original chain ID or name.
148
+ * @returns {string | number} - The formatted chain ID prefixed with 'solana:' if Solana, otherwise the original.
149
+ */
150
+ declare function setChainId(chainId: number | string): string | number;
151
+
152
+ /**
133
153
  * Ensures the global 'window' object is available (if running in a browser-like environment),
134
154
  * then pauses execution for a specified duration, and finally resolves the Promise with the given value.
135
155
  *
@@ -172,8 +192,36 @@ declare const delay: <T>(value: T, ms: number) => Promise<T>;
172
192
  */
173
193
  declare function filterUniqueByKey<T>(array: T[], key: keyof T): T[];
174
194
 
195
+ /**
196
+ * Formats a chain ID for use in connector identifiers.
197
+ * String chain IDs (e.g. Solana cluster names) are prefixed with the adapter key; numeric EVM chain IDs are kept as is.
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * formatConnectorChainId('devnet', OrbitAdapter.SOLANA); // "solana:devnet"
202
+ * formatConnectorChainId(1, OrbitAdapter.EVM); // 1
203
+ * ```
204
+ *
205
+ * @param chainId - Numeric EVM chain ID or string chain identifier.
206
+ * @param connectedAdapter - Adapter of the connected wallet.
207
+ * @returns `"<adapter>:<chainId>"` for string chain IDs, otherwise the numeric chain ID unchanged.
208
+ */
175
209
  declare function formatConnectorChainId(chainId: string | number, connectedAdapter: OrbitAdapter): string | number;
176
210
 
211
+ /**
212
+ * Normalizes a wallet connector display name into a stable identifier.
213
+ * Known names are mapped explicitly (e.g. "Trust Wallet" → "trust", "Base Account" → "coinbase");
214
+ * any other name has its whitespace removed and is lowercased.
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * formatConnectorName('Trust Wallet'); // "trust"
219
+ * formatConnectorName('Rabby Wallet'); // "rabbywallet"
220
+ * ```
221
+ *
222
+ * @param connectorName - Display name reported by the wallet connector.
223
+ * @returns The normalized connector identifier.
224
+ */
177
225
  declare const formatConnectorName: (connectorName: string) => string;
178
226
 
179
227
  /**
@@ -229,6 +277,14 @@ declare function getAdapterFromConnectorType(connectorType: ConnectorType): Orbi
229
277
  */
230
278
  declare function getConnectorTypeFromName(adapter: OrbitAdapter, name: string): string;
231
279
 
280
+ /**
281
+ * Returns the default network and educational links for an adapter, e.g. to render a
282
+ * "What is a wallet?" section in a connect modal.
283
+ *
284
+ * @param adapter - The adapter to describe.
285
+ * @returns Default chain (`chainId`, `name`) and `links` (`aboutNetwork`, `choseWallet`, `about`) for EVM and Solana,
286
+ * or `undefined` for adapters without network data (e.g. Starknet).
287
+ */
232
288
  declare const getNetworkData: (adapter: OrbitAdapter) => {
233
289
  chain: {
234
290
  chainId: number;
@@ -301,14 +357,22 @@ declare const impersonatedHelpers: {
301
357
  * @returns The impersonated address or undefined if not set or in SSR context
302
358
  */
303
359
  getImpersonated: () => string | null | undefined;
360
+ /**
361
+ * Removes the impersonated address from localStorage.
362
+ *
363
+ * @returns undefined in SSR context, void in browser
364
+ */
304
365
  removeImpersonated: () => void;
305
366
  };
306
367
 
307
368
  /**
308
369
  * Checks if the current window is running inside a Safe App iframe
309
370
  * by attempting postMessage communication with the parent window.
371
+ * Side effect: posts a `getSafeInfo` message to `window.parent` and listens for the reply until `timeout`.
310
372
  *
311
- * @returns Promise that resolves to true if running inside Safe Wallet, false otherwise
373
+ * @param timeout - How long to wait for the Safe response, in milliseconds. Defaults to 1000.
374
+ * @returns Promise that resolves to true if running inside Safe Wallet, false otherwise (also on the server,
375
+ * outside an iframe, or when not served over HTTPS)
312
376
  */
313
377
  declare function detectSafeApp(timeout?: number): Promise<boolean>;
314
378
  /**
@@ -322,9 +386,15 @@ declare const isInSecureIframe: boolean;
322
386
  */
323
387
  declare const isSafeApp: boolean;
324
388
 
389
+ /**
390
+ * Connection data persisted by {@link lastConnectedConnectorHelpers}.
391
+ */
325
392
  type LastConnectedConnector = {
393
+ /** Connector identifier, e.g. "evm:metamask". */
326
394
  connectorType: ConnectorType;
395
+ /** Chain the wallet was connected to (numeric EVM chain ID or Solana chain identifier). */
327
396
  chainId: number | string;
397
+ /** Connected wallet address, if known. */
328
398
  address?: string;
329
399
  };
330
400
  /**
@@ -344,7 +414,7 @@ declare const lastConnectedConnectorHelpers: {
344
414
  /**
345
415
  * Stores the last connected wallet data in localStorage.
346
416
  *
347
- * @param data - Object containing the wallet type and chain ID.
417
+ * @param data - Connector type, chain ID and optional address of the connected wallet.
348
418
  * @returns undefined in SSR context, void in browser
349
419
  */
350
420
  setLastConnectedConnector: ({ connectorType, chainId, address }: LastConnectedConnector) => void;
@@ -676,22 +746,21 @@ declare const selectAdapterByKey: <A extends {
676
746
  adapterKey: OrbitAdapter;
677
747
  } & OrbitGenericAdapter<A>) => A | undefined;
678
748
 
679
- declare function waitFor(predicate: () => boolean | undefined, maxChecks?: number, checkIntervalMs?: number): Promise<void>;
680
-
681
749
  /**
682
- * Checks whether the given chain ID belongs to a Solana network.
683
- * Supports common Solana network names: 'devnet', 'testnet', 'mainnet-beta', 'mainnet'.
750
+ * Polls a predicate until it returns a truthy value.
684
751
  *
685
- * @param {number | string} chainId - The chain ID or chain name.
686
- * @returns {boolean} - True if the chain ID corresponds to a Solana network, false otherwise.
687
- */
688
- declare function isSolanaChain(chainId: number | string): boolean;
689
- /**
690
- * Sets the chain ID to a Solana-specific format if the chain is a Solana network.
752
+ * @example
753
+ * ```typescript
754
+ * // Wait up to 10 seconds (50 × 200 ms) for an injected provider.
755
+ * await waitFor(() => typeof window !== 'undefined' && 'ethereum' in window);
756
+ * ```
691
757
  *
692
- * @param {number | string} chainId - The original chain ID or name.
693
- * @returns {string | number} - The formatted chain ID prefixed with 'solana:' if Solana, otherwise the original.
758
+ * @param predicate - Condition to check on every attempt.
759
+ * @param maxChecks - Maximum number of attempts. Defaults to 50.
760
+ * @param checkIntervalMs - Delay between attempts in milliseconds. Defaults to 200.
761
+ * @returns A promise that resolves as soon as the predicate is truthy.
762
+ * @throws {Error} "Predicate not fulfilled in time" if the predicate is still falsy after `maxChecks` attempts.
694
763
  */
695
- declare function setChainId(chainId: number | string): string | number;
764
+ declare function waitFor(predicate: () => boolean | undefined, maxChecks?: number, checkIntervalMs?: number): Promise<void>;
696
765
 
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 };
766
+ export { type BaseAdapter, type ChainIdentifierArray, type ConnectorType, type LastConnectedConnector, 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 };
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)}}var S=(e,n)=>new Promise(t=>{let o=()=>{setTimeout(()=>t(e),n);};typeof window<"u"?o():setTimeout(o,0);});function R(e,n){let t=new Set;return e.filter(o=>{let s=o[n];return t.has(s)?false:(t.add(s),true)})}function h(e,n){return typeof e=="string"?`${n}:${e}`:e}var l=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"]]),O=e=>l.get(e)??e.replace(/\s+/g,"").toLowerCase();function M(e){return e?.split(":")[0]??"evm"}function G(e,n){return `${e}:${n.replace(/\s+/g,"").toLowerCase()}`}var j=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 F={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 m=typeof window<"u"&&window!==window.parent&&window.location.protocol==="https:",D=m;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 g=["code","name","shortMessage","details","cause","metaMessages","data","reason","method","transaction","receipt","action","version"];function w(){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 y(e){let n={};if(e&&typeof e=="object"){for(let t of g)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=w(),t=JSON.stringify(e,n);return JSON.parse(t)}catch{return {_serializationError:"Failed to serialize error object"}}}function H(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=y(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 Z=({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 X(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")}function C(e){return typeof e=="string"?["devnet","testnet","mainnet-beta","mainnet"].includes(e):false}function ne(e){return C(e)?`solana:${e}`:e}
2
- exports.OrbitAdapter=c;exports.delay=S;exports.detectSafeApp=v;exports.filterUniqueByKey=R;exports.formatConnectorChainId=h;exports.formatConnectorName=O;exports.getAdapterFromConnectorType=M;exports.getConnectorTypeFromName=G;exports.getNetworkData=j;exports.getParsedStorageItem=a;exports.impersonatedHelpers=F;exports.isAddress=A;exports.isInSecureIframe=m;exports.isSafeApp=D;exports.isSolanaChain=C;exports.lastConnectedConnectorHelpers=d;exports.normalizeError=H;exports.recentlyConnectedConnectorsListHelpers=r;exports.selectAdapterByKey=Z;exports.setChainId=ne;exports.waitFor=X;
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;
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)}}var S=(e,n)=>new Promise(t=>{let o=()=>{setTimeout(()=>t(e),n);};typeof window<"u"?o():setTimeout(o,0);});function R(e,n){let t=new Set;return e.filter(o=>{let s=o[n];return t.has(s)?false:(t.add(s),true)})}function h(e,n){return typeof e=="string"?`${n}:${e}`:e}var l=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"]]),O=e=>l.get(e)??e.replace(/\s+/g,"").toLowerCase();function M(e){return e?.split(":")[0]??"evm"}function G(e,n){return `${e}:${n.replace(/\s+/g,"").toLowerCase()}`}var j=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 F={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 m=typeof window<"u"&&window!==window.parent&&window.location.protocol==="https:",D=m;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 g=["code","name","shortMessage","details","cause","metaMessages","data","reason","method","transaction","receipt","action","version"];function w(){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 y(e){let n={};if(e&&typeof e=="object"){for(let t of g)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=w(),t=JSON.stringify(e,n);return JSON.parse(t)}catch{return {_serializationError:"Failed to serialize error object"}}}function H(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=y(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 Z=({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 X(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")}function C(e){return typeof e=="string"?["devnet","testnet","mainnet-beta","mainnet"].includes(e):false}function ne(e){return C(e)?`solana:${e}`:e}
2
- export{c as OrbitAdapter,S as delay,v as detectSafeApp,R as filterUniqueByKey,h as formatConnectorChainId,O as formatConnectorName,M as getAdapterFromConnectorType,G as getConnectorTypeFromName,j as getNetworkData,a as getParsedStorageItem,F as impersonatedHelpers,A as isAddress,m as isInSecureIframe,D as isSafeApp,C as isSolanaChain,d as lastConnectedConnectorHelpers,H as normalizeError,r as recentlyConnectedConnectorsListHelpers,Z as selectAdapterByKey,ne as setChainId,X as waitFor};
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};
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@tuwaio/orbit-core",
3
- "version": "0.2.15",
3
+ "version": "0.3.1",
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,10 +43,11 @@
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",
45
- "build": "tsup"
50
+ "build": "tsup",
51
+ "test": "vitest run"
46
52
  }
47
53
  }