@solana/connector 0.1.3 → 0.1.5

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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +685 -1071
  3. package/dist/chunk-3STZXVXD.mjs +2185 -0
  4. package/dist/chunk-3STZXVXD.mjs.map +1 -0
  5. package/dist/chunk-I64FD2EH.js +312 -0
  6. package/dist/chunk-I64FD2EH.js.map +1 -0
  7. package/dist/{chunk-TIW3EQPC.js → chunk-JUZVCBAI.js} +127 -104
  8. package/dist/chunk-JUZVCBAI.js.map +1 -0
  9. package/dist/{chunk-7CKCRY25.js → chunk-NQXK7PGX.js} +75 -79
  10. package/dist/chunk-NQXK7PGX.js.map +1 -0
  11. package/dist/{chunk-HPENTIPE.mjs → chunk-QKVL45F6.mjs} +57 -57
  12. package/dist/chunk-QKVL45F6.mjs.map +1 -0
  13. package/dist/chunk-QL3IT3TS.mjs +299 -0
  14. package/dist/chunk-QL3IT3TS.mjs.map +1 -0
  15. package/dist/chunk-ULUYX23Q.js +2213 -0
  16. package/dist/chunk-ULUYX23Q.js.map +1 -0
  17. package/dist/{chunk-TKJSKXSA.mjs → chunk-VMSZJPR5.mjs} +42 -20
  18. package/dist/chunk-VMSZJPR5.mjs.map +1 -0
  19. package/dist/compat.d.mts +4 -2
  20. package/dist/compat.d.ts +4 -2
  21. package/dist/compat.js +3 -3
  22. package/dist/compat.mjs +1 -1
  23. package/dist/headless.d.mts +146 -18
  24. package/dist/headless.d.ts +146 -18
  25. package/dist/headless.js +144 -111
  26. package/dist/headless.mjs +3 -2
  27. package/dist/index.d.mts +6 -5
  28. package/dist/index.d.ts +6 -5
  29. package/dist/index.js +207 -126
  30. package/dist/index.mjs +4 -3
  31. package/dist/react.d.mts +707 -67
  32. package/dist/react.d.ts +707 -67
  33. package/dist/react.js +64 -16
  34. package/dist/react.mjs +2 -2
  35. package/dist/{transaction-signer-D3csM_Mf.d.mts → transaction-signer-D9d8nxwb.d.mts} +3 -1
  36. package/dist/{transaction-signer-D3csM_Mf.d.ts → transaction-signer-D9d8nxwb.d.ts} +3 -1
  37. package/dist/{wallet-standard-shim-Cg0GVGwu.d.mts → wallet-standard-shim--YcrQNRt.d.ts} +216 -6
  38. package/dist/{wallet-standard-shim-C1tisl9S.d.ts → wallet-standard-shim-Dx7H8Ctf.d.mts} +216 -6
  39. package/package.json +16 -12
  40. package/dist/chunk-5ZUVZZWU.mjs +0 -180
  41. package/dist/chunk-5ZUVZZWU.mjs.map +0 -1
  42. package/dist/chunk-7CKCRY25.js.map +0 -1
  43. package/dist/chunk-FTD7F7CS.js +0 -314
  44. package/dist/chunk-FTD7F7CS.js.map +0 -1
  45. package/dist/chunk-HPENTIPE.mjs.map +0 -1
  46. package/dist/chunk-MPZFJEJK.mjs +0 -298
  47. package/dist/chunk-MPZFJEJK.mjs.map +0 -1
  48. package/dist/chunk-SMUUAKC3.js +0 -186
  49. package/dist/chunk-SMUUAKC3.js.map +0 -1
  50. package/dist/chunk-TIW3EQPC.js.map +0 -1
  51. package/dist/chunk-TKJSKXSA.mjs.map +0 -1
package/README.md CHANGED
@@ -3,255 +3,139 @@ title: @solana/connector
3
3
  description: Production-ready wallet connector for Solana applications
4
4
  ---
5
5
 
6
- **ConnectorKit is your Solana wallet infrastructure.** A headless, framework-agnostic wallet connector built on Wallet Standard with powerful transaction signing, event system, and performance optimizations that just work.
6
+ **ConnectorKit is your Solana wallet infrastructure.** A headless, framework-agnostic wallet connector built on Wallet Standard that just work.
7
7
 
8
8
  ![npm](https://img.shields.io/npm/v/@solana/connector)
9
- ![Bundle Size](https://img.shields.io/bundlephobia/minzip/@solana/connector)
9
+ ![Bundle Size](https://img.shields.io/badge/bundle-~45KB-gzip-green)
10
10
  ![TypeScript](https://img.shields.io/badge/TypeScript-100%25-blue)
11
- ![Test Coverage](https://img.shields.io/badge/coverage-80%25+-green)
12
11
 
13
12
  ### Why ConnectorKit?
14
13
 
15
- - **Clean Transaction API**: Unified interface for signing and sending—no more wallet-specific logic
16
- - **Production Ready**: Event system, health checks, error boundaries, and monitoring built-in
17
- - **Better Performance**: 40-60% fewer re-renders via optimized state management
18
- - **Universal Compatibility**: Drop-in replacement for @solana/wallet-adapter
19
- - **Framework Agnostic**: React, Vue, Svelte, or vanilla JavaScript
20
-
21
- ### Architecture
22
-
23
- - **Language**: TypeScript with full type safety
24
- - **Standard**: Built on Wallet Standard protocol
25
- - **Frameworks**: React hooks + headless core for any framework
26
- - **Mobile**: Solana Mobile Wallet Adapter integration
27
- - **Storage**: Enhanced persistence with SSR support
28
-
29
- ### Features
30
-
31
- - Wallet Standard compliance with multi-wallet support
32
- - Clean transaction signer abstraction
33
- - Comprehensive event system for analytics
34
- - Connection pooling for better performance
35
- - Health checks and diagnostics
36
- - Auto-connect and account management
37
- - Network switching (mainnet, devnet, testnet, custom)
38
- - Browser polyfills for universal compatibility
39
- - Debug panel for development
40
- - Wallet Adapter compatibility bridge
41
- - 80%+ test coverage
14
+ - **Wallet Standard First**: Built on the official Wallet Standard protocol for universal wallet compatibility
15
+ - **Modern & Legacy Support**: Works with both `@solana/kit` (web3.js 2.0) and `@solana/web3.js` (legacy)
16
+ - **Framework Agnostic**: React hooks + headless core for Vue, Svelte, or vanilla JavaScript
17
+ - **Production Ready**: Event system for analytics, health checks for diagnostics, error boundaries for React apps
18
+ - **Enhanced Storage**: Automatic validation, SSR fallback, and error handling out of the box
19
+ - **Mobile Support**: Built-in Solana Mobile Wallet Adapter integration
42
20
 
43
21
  ---
44
22
 
45
23
  ## Quick Start
46
24
 
47
- Install ConnectorKit:
25
+ ### 1. Install
48
26
 
49
27
  ```bash
50
- pnpm add @solana/connector
51
- # or
52
28
  npm install @solana/connector
53
29
  # or
30
+ pnpm add @solana/connector
31
+ # or
54
32
  yarn add @solana/connector
33
+ # or
34
+ bun add @solana/connector
55
35
  ```
56
36
 
57
- Basic usage:
37
+ ### 2. Setup Provider (once in your app root)
58
38
 
59
39
  ```typescript
60
- import {
61
- ConnectorProvider,
62
- getDefaultConfig,
63
- useConnector,
64
- useAccount,
65
- useTransactionSigner
66
- } from '@solana/connector';
67
-
68
- // 1. Wrap your app
69
- function App() {
70
- return (
71
- <ConnectorProvider config={getDefaultConfig({ appName: "My App" })}>
72
- <WalletButton />
73
- </ConnectorProvider>
74
- );
75
- }
76
-
77
- // 2. Connect wallet
78
- function WalletButton() {
79
- const { wallets, select, connected, disconnect } = useConnector();
80
- const { address, formatted } = useAccount();
81
-
82
- if (!connected) {
83
- return wallets.map(w => (
84
- <button key={w.name} onClick={() => select(w.name)}>
85
- Connect {w.name}
86
- </button>
87
- ));
88
- }
89
-
90
- return (
91
- <>
92
- <span>{formatted}</span>
93
- <button onClick={disconnect}>Disconnect</button>
94
- </>
95
- );
96
- }
97
-
98
- // 3. Sign transactions
99
- function SendTransaction() {
100
- const { signer, ready } = useTransactionSigner();
101
-
102
- const handleSend = async () => {
103
- const signature = await signer.signAndSendTransaction(transaction);
104
- };
40
+ 'use client';
41
+
42
+ import { useMemo } from 'react';
43
+ import { AppProvider } from '@solana/connector/react';
44
+ import { getDefaultConfig, getDefaultMobileConfig } from '@solana/connector/headless';
45
+
46
+ export function Providers({ children }: { children: React.ReactNode }) {
47
+ const connectorConfig = useMemo(() => {
48
+ // Optional: Get custom RPC URL from environment variable
49
+ const customRpcUrl = process.env.SOLANA_RPC_URL;
50
+
51
+ // Optional: Create custom cluster configuration
52
+ const clusters = customRpcUrl
53
+ ? [
54
+ {
55
+ id: 'solana:mainnet' as const,
56
+ label: 'Mainnet (Custom RPC)',
57
+ name: 'mainnet-beta' as const,
58
+ url: customRpcUrl,
59
+ },
60
+ {
61
+ id: 'solana:devnet' as const,
62
+ label: 'Devnet',
63
+ name: 'devnet' as const,
64
+ url: 'https://api.devnet.solana.com',
65
+ },
66
+ ]
67
+ : undefined;
68
+
69
+ return getDefaultConfig({
70
+ appName: 'My App',
71
+ appUrl: 'https://myapp.com',
72
+ autoConnect: true,
73
+ enableMobile: true,
74
+ clusters,
75
+ });
76
+ }, []);
105
77
 
106
- return <button onClick={handleSend} disabled={!ready}>Send</button>;
78
+ const mobile = useMemo(
79
+ () =>
80
+ getDefaultMobileConfig({
81
+ appName: 'My App',
82
+ appUrl: 'https://myapp.com',
83
+ }),
84
+ [],
85
+ );
86
+
87
+ return (
88
+ <AppProvider connectorConfig={connectorConfig} mobile={mobile}>
89
+ {children}
90
+ </AppProvider>
91
+ );
107
92
  }
108
93
  ```
109
94
 
110
- **[→ Getting Started](#core-hooks)** - Learn the core hooks
111
-
112
- **[→ Transaction Signer](#transaction-signer)** - Sign and send transactions
113
-
114
- **[→ Event System](#event-system)** - Track wallet events for analytics
115
-
116
- **[→ Framework Guides](#headless-client-vue-svelte-vanilla-js)** - Use with Vue, Svelte, or vanilla JS
117
-
118
- ---
119
-
120
- ## Documentation
121
-
122
- ### Getting Started
123
-
124
- - [Installation](#quick-start)
125
- - [Quick Start Guide](#quick-start)
126
- - [TypeScript SDK](#typescript-sdk)
127
- - [Core Hooks](#core-hooks)
128
- - [Local Development](#local-development)
129
-
130
- ### Production Features
131
-
132
- - [Transaction Signer](#transaction-signer) - Clean signing API
133
- - [Event System](#event-system) - Analytics and monitoring
134
- - [Debug Panel](#debug-panel) - Development tools
135
- - [Connection Pooling](#connection-pooling) - Performance optimization
136
- - [Health Checks](#health-checks) - Diagnostics
137
- - [Wallet Adapter Compatibility](#wallet-adapter-compatibility) - Drop-in replacement
138
-
139
- ### Configuration & Usage
140
-
141
- - [Configuration](#configuration) - Setup options
142
- - [Network Selection](#network-selection) - Cluster management
143
- - [Custom Storage](#custom-storage) - Persistence options
144
- - [Mobile Wallet Adapter](#mobile-wallet-adapter) - Mobile support
145
- - [Advanced Usage](#advanced-usage) - Framework-specific guides
146
-
147
- ### Reference
148
-
149
- - [Complete API Reference](#complete-api-reference)
150
- - [Configuration Functions](#configuration-functions)
151
- - [Transaction Signing API](#transaction-signing-api-new)
152
- - [Event System API](#event-system-api-new)
153
- - [Health Check API](#health-check-api-new)
154
- - [Connection Pool API](#connection-pool-api-new)
155
- - [Utility Functions](#utility-functions)
156
- - [TypeScript Types](#types)
157
-
158
- ### Testing & Performance
159
-
160
- - [Testing](#testing) - Test suite and utilities
161
- - [Performance](#performance) - Bundle size and optimization
162
- - [Browser Compatibility](#browser-compatibility)
163
-
164
- ### Migration & Examples
165
-
166
- - [Migration from wallet-adapter](#migration-from-solanawallet-adapter)
167
- - [Examples](#examples)
168
- - [Supported Wallets](#supported-wallets)
169
-
170
- ---
171
-
172
- ## TypeScript SDK
173
-
174
- ConnectorKit provides React hooks and a headless core for any framework:
95
+ ### 3. Use Hooks (in any component)
175
96
 
176
97
  ```typescript
177
- // React
178
- import { useConnector, useTransactionSigner, useAccount } from '@solana/connector';
179
-
180
- // Headless (Vue, Svelte, vanilla JS)
181
- import { ConnectorClient, getDefaultConfig } from '@solana/connector/headless';
182
-
183
- const client = new ConnectorClient(getDefaultConfig({ appName: 'My App' }));
184
- await client.select('Phantom');
185
- ```
186
-
187
- **[→ API Reference](#complete-api-reference)** - Full TypeScript API documentation
188
-
189
- **[→ Core Hooks](#core-hooks)** - React hooks reference
98
+ 'use client';
190
99
 
191
- **[→ Headless Guide](#headless-client-vue-svelte-vanilla-js)** - Use without React
100
+ import { useConnector, useAccount } from '@solana/connector';
192
101
 
193
- ---
194
-
195
- ## Local Development
196
-
197
- ### Prerequisites
198
-
199
- - Node.js 20+ (or 18+)
200
- - pnpm, npm, or yarn
201
- - TypeScript 5.0+
202
-
203
- ### Installation
204
-
205
- ```bash
206
- git clone https://github.com/your-org/connectorkit.git
207
- cd connectorkit
208
- pnpm install
209
- ```
210
-
211
- ### Build
212
-
213
- ```bash
214
- pnpm build
215
- ```
102
+ export function ConnectButton() {
103
+ const { wallets, select, disconnect, connected, connecting, selectedWallet, selectedAccount } = useConnector();
104
+ const { address, formatted, copy } = useAccount();
216
105
 
217
- ### Running Examples
218
-
219
- ```bash
220
- cd examples/react
221
- pnpm dev
222
- ```
223
-
224
- Or run the Vite example:
225
-
226
- ```bash
227
- cd examples/vite
228
- pnpm dev
229
- ```
230
-
231
- ### Local Testing
232
-
233
- Run all tests:
234
-
235
- ```bash
236
- pnpm test
237
- ```
106
+ if (connecting) {
107
+ return <button disabled>Connecting...</button>;
108
+ }
238
109
 
239
- Run tests in watch mode:
110
+ if (!connected) {
111
+ return (
112
+ <div>
113
+ {wallets.map(w => (
114
+ <button key={w.wallet.name} onClick={() => select(w.wallet.name)}>
115
+ Connect {w.wallet.name}
116
+ </button>
117
+ ))}
118
+ </div>
119
+ );
120
+ }
240
121
 
241
- ```bash
242
- pnpm test:watch
122
+ return (
123
+ <div>
124
+ <button onClick={copy}>{formatted}</button>
125
+ <button onClick={disconnect}>Disconnect</button>
126
+ </div>
127
+ );
128
+ }
243
129
  ```
244
130
 
245
- Generate coverage report:
246
-
247
- ```bash
248
- pnpm test:coverage
249
- ```
131
+ **That's it!** You're ready to go. Everything else below is optional.
250
132
 
251
133
  ---
252
134
 
253
135
  ## Core Hooks
254
136
 
137
+ These are the main hooks you'll use in your components.
138
+
255
139
  ### `useConnector()`
256
140
 
257
141
  Main hook for wallet connection and state.
@@ -264,6 +148,7 @@ function Component() {
264
148
  // State
265
149
  wallets, // WalletInfo[] - All available wallets
266
150
  selectedWallet, // Wallet | null - Currently connected wallet
151
+ selectedAccount, // string | null - Currently selected account address
267
152
  accounts, // AccountInfo[] - Connected accounts
268
153
  connected, // boolean - Connection status
269
154
  connecting, // boolean - Connecting in progress
@@ -275,6 +160,41 @@ function Component() {
275
160
  }
276
161
  ```
277
162
 
163
+ **Real Example** - Connect Button with wallet selection:
164
+
165
+ ```typescript
166
+ 'use client';
167
+
168
+ import { useConnector } from '@solana/connector';
169
+ import { useState } from 'react';
170
+
171
+ export function ConnectButton() {
172
+ const [isModalOpen, setIsModalOpen] = useState(false);
173
+ const { connected, connecting, selectedWallet, selectedAccount, wallets, select } = useConnector();
174
+
175
+ if (connecting) {
176
+ return <button disabled>Connecting...</button>;
177
+ }
178
+
179
+ if (connected && selectedAccount && selectedWallet) {
180
+ const shortAddress = `${selectedAccount.slice(0, 4)}...${selectedAccount.slice(-4)}`;
181
+ return (
182
+ <div>
183
+ <span>{shortAddress}</span>
184
+ <button onClick={() => select(selectedWallet.name)}>Switch Wallet</button>
185
+ </div>
186
+ );
187
+ }
188
+
189
+ return (
190
+ <>
191
+ <button onClick={() => setIsModalOpen(true)}>Connect Wallet</button>
192
+ {/* Wallet selection modal */}
193
+ </>
194
+ );
195
+ }
196
+ ```
197
+
278
198
  ### `useAccount()`
279
199
 
280
200
  Hook for working with the connected account.
@@ -295,6 +215,35 @@ function Component() {
295
215
  }
296
216
  ```
297
217
 
218
+ **Real Example** - Account Switcher for multi-account wallets:
219
+
220
+ ```typescript
221
+ 'use client';
222
+
223
+ import { useAccount } from '@solana/connector';
224
+
225
+ export function AccountSwitcher() {
226
+ const { accounts, address, selectAccount, connected } = useAccount();
227
+
228
+ if (!connected || accounts.length <= 1) {
229
+ return null;
230
+ }
231
+
232
+ return (
233
+ <select
234
+ value={address || ''}
235
+ onChange={e => selectAccount(e.target.value)}
236
+ >
237
+ {accounts.map(account => (
238
+ <option key={account.address} value={account.address}>
239
+ {account.address.slice(0, 6)}...{account.address.slice(-6)}
240
+ </option>
241
+ ))}
242
+ </select>
243
+ );
244
+ }
245
+ ```
246
+
298
247
  ### `useCluster()`
299
248
 
300
249
  Hook for managing Solana network/cluster.
@@ -315,359 +264,583 @@ function Component() {
315
264
  }
316
265
  ```
317
266
 
267
+ **Real Example** - Network Selector:
268
+
269
+ ```typescript
270
+ 'use client';
271
+
272
+ import { useCluster } from '@solana/connector';
273
+
274
+ export function ClusterSelector() {
275
+ const { cluster, clusters, setCluster } = useCluster();
276
+
277
+ return (
278
+ <select
279
+ value={cluster?.id || ''}
280
+ onChange={e => setCluster(e.target.value as SolanaClusterId)}
281
+ >
282
+ {clusters.map(c => (
283
+ <option key={c.id} value={c.id}>
284
+ {c.label}
285
+ </option>
286
+ ))}
287
+ </select>
288
+ );
289
+ }
290
+ ```
291
+
292
+ ### `useWalletInfo()`
293
+
294
+ Hook for accessing current wallet metadata.
295
+
296
+ ```typescript
297
+ import { useWalletInfo } from '@solana/connector';
298
+
299
+ function Component() {
300
+ const {
301
+ name, // string | null - Wallet name
302
+ icon, // string | undefined - Wallet icon URL
303
+ wallet, // WalletInfo | null - Full wallet info
304
+ connecting, // boolean - Connection in progress
305
+ } = useWalletInfo();
306
+ }
307
+ ```
308
+
318
309
  ---
319
310
 
320
- ## Production Features
311
+ ## Transaction Signing
312
+
313
+ ConnectorKit provides powerful transaction signing capabilities with support for both legacy `@solana/web3.js` and modern `@solana/kit` APIs.
321
314
 
322
- ### Transaction Signer
315
+ ### Modern API (`@solana/kit`)
323
316
 
324
- Clean, unified interface for transaction signing operations.
317
+ Use `useKitTransactionSigner()` for modern, type-safe transaction building:
325
318
 
326
319
  ```typescript
327
- import { useTransactionSigner } from '@solana/connector';
320
+ 'use client';
328
321
 
329
- function SendTx() {
330
- const { signer, ready, capabilities } = useTransactionSigner();
322
+ import { useState } from 'react';
323
+ import {
324
+ address,
325
+ createSolanaRpc,
326
+ pipe,
327
+ createTransactionMessage,
328
+ setTransactionMessageFeePayerSigner,
329
+ setTransactionMessageLifetimeUsingBlockhash,
330
+ appendTransactionMessageInstructions,
331
+ sendAndConfirmTransactionFactory,
332
+ getSignatureFromTransaction,
333
+ signTransactionMessageWithSigners,
334
+ createSolanaRpcSubscriptions,
335
+ lamports,
336
+ assertIsTransactionWithBlockhashLifetime,
337
+ } from '@solana/kit';
338
+ import { getTransferSolInstruction } from '@solana-program/system';
339
+ import { useKitTransactionSigner, useCluster, useConnectorClient, LAMPORTS_PER_SOL } from '@solana/connector';
340
+
341
+ export function ModernSolTransfer() {
342
+ const { signer, ready } = useKitTransactionSigner();
343
+ const { cluster } = useCluster();
344
+ const client = useConnectorClient();
345
+ const [signature, setSignature] = useState<string | null>(null);
331
346
 
332
- // Check capabilities
333
- console.log('Can sign:', capabilities.canSign);
334
- console.log('Can send:', capabilities.canSend);
335
- console.log('Can sign messages:', capabilities.canSignMessage);
336
- console.log('Batch support:', capabilities.supportsBatchSigning);
347
+ async function handleTransfer(recipientAddress: string, amount: number) {
348
+ if (!signer || !client) {
349
+ throw new Error('Wallet not connected');
350
+ }
337
351
 
338
- const handleSend = async () => {
339
- if (!signer) return;
352
+ // Get RPC URL from connector client
353
+ const rpcUrl = client.getRpcUrl();
354
+ if (!rpcUrl) {
355
+ throw new Error('No RPC endpoint configured');
356
+ }
340
357
 
341
- try {
342
- // Sign and send a transaction
343
- const signature = await signer.signAndSendTransaction(transaction);
344
- console.log('Success:', signature);
358
+ // Create RPC client using web3.js 2.0
359
+ const rpc = createSolanaRpc(rpcUrl);
360
+ const rpcSubscriptions = createSolanaRpcSubscriptions(rpcUrl.replace('http', 'ws'));
345
361
 
346
- // Or just sign without sending
347
- const signed = await signer.signTransaction(transaction);
362
+ // Get recent blockhash
363
+ const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
348
364
 
349
- // Or sign multiple transactions
350
- const signedBatch = await signer.signAllTransactions([tx1, tx2, tx3]);
365
+ // Convert SOL to lamports
366
+ const amountInLamports = lamports(BigInt(Math.floor(amount * Number(LAMPORTS_PER_SOL))));
351
367
 
352
- // Or sign and send multiple
353
- const signatures = await signer.signAndSendTransactions([tx1, tx2]);
368
+ // Create transfer instruction
369
+ const transferInstruction = getTransferSolInstruction({
370
+ source: signer,
371
+ destination: address(recipientAddress),
372
+ amount: amountInLamports,
373
+ });
354
374
 
355
- } catch (error) {
356
- if (error instanceof TransactionSignerError) {
357
- console.error('Signing error:', error.code, error.message);
358
- }
359
- }
360
- };
375
+ // Build transaction message
376
+ const transactionMessage = pipe(
377
+ createTransactionMessage({ version: 0 }),
378
+ tx => setTransactionMessageFeePayerSigner(signer, tx),
379
+ tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
380
+ tx => appendTransactionMessageInstructions([transferInstruction], tx),
381
+ );
361
382
 
362
- return (
363
- <button onClick={handleSend} disabled={!ready}>
364
- Send Transaction
365
- </button>
366
- );
367
- }
368
- ```
383
+ // Sign transaction
384
+ const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
369
385
 
370
- **Error Handling**:
386
+ // Send and confirm
387
+ assertIsTransactionWithBlockhashLifetime(signedTransaction);
388
+ await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction, {
389
+ commitment: 'confirmed',
390
+ });
371
391
 
372
- ```typescript
373
- import { isTransactionSignerError, TransactionSignerError } from '@solana/connector';
374
-
375
- try {
376
- await signer.signAndSendTransaction(tx);
377
- } catch (error) {
378
- if (isTransactionSignerError(error)) {
379
- switch (error.code) {
380
- case 'WALLET_NOT_CONNECTED':
381
- // Show connect prompt
382
- break;
383
- case 'FEATURE_NOT_SUPPORTED':
384
- // Show unsupported feature message
385
- break;
386
- case 'SIGNING_FAILED':
387
- // User rejected or signing failed
388
- break;
389
- case 'SEND_FAILED':
390
- // Transaction broadcast failed
391
- break;
392
- }
392
+ const transactionSignature = getSignatureFromTransaction(signedTransaction);
393
+ setSignature(transactionSignature);
393
394
  }
395
+
396
+ return (
397
+ <div>
398
+ {/* Your form UI */}
399
+ <button onClick={() => handleTransfer('...', 0.1)} disabled={!ready}>
400
+ Send SOL
401
+ </button>
402
+ {signature && <div>Transaction: {signature}</div>}
403
+ </div>
404
+ );
394
405
  }
395
406
  ```
396
407
 
397
- ### Event System
408
+ ### Legacy API (`@solana/web3.js`)
398
409
 
399
- Track all connector lifecycle events for analytics and monitoring.
410
+ Use `useTransactionSigner()` for legacy web3.js compatibility:
400
411
 
401
412
  ```typescript
402
- import { useConnectorClient } from '@solana/connector';
413
+ import { useTransactionSigner } from '@solana/connector';
414
+ import { Transaction, SystemProgram } from '@solana/web3.js';
403
415
 
404
- function AnalyticsTracker() {
405
- const client = useConnectorClient();
416
+ function SendTransaction() {
417
+ const { signer, ready } = useTransactionSigner();
406
418
 
407
- useEffect(() => {
408
- if (!client) return;
409
-
410
- // Subscribe to events
411
- const unsubscribe = client.on(event => {
412
- switch (event.type) {
413
- case 'wallet:connected':
414
- analytics.track('Wallet Connected', {
415
- wallet: event.wallet,
416
- account: event.account,
417
- timestamp: event.timestamp,
418
- });
419
- break;
420
-
421
- case 'wallet:disconnected':
422
- analytics.track('Wallet Disconnected');
423
- break;
424
-
425
- case 'cluster:changed':
426
- analytics.track('Network Changed', {
427
- from: event.previousCluster,
428
- to: event.cluster,
429
- });
430
- break;
431
-
432
- case 'error':
433
- errorTracker.captureException(event.error, {
434
- context: event.context,
435
- });
436
- break;
437
- }
438
- });
419
+ const handleSend = async () => {
420
+ if (!signer) return;
439
421
 
440
- return unsubscribe;
441
- }, [client]);
422
+ const transaction = new Transaction().add(
423
+ SystemProgram.transfer({
424
+ fromPubkey: signer.address,
425
+ toPubkey: recipientPubkey,
426
+ lamports: 1000000,
427
+ })
428
+ );
429
+
430
+ const signature = await signer.signAndSendTransaction(transaction);
431
+ console.log('Transaction sent:', signature);
432
+ };
442
433
 
443
- return null;
434
+ return <button onClick={handleSend} disabled={!ready}>Send</button>;
444
435
  }
445
436
  ```
446
437
 
447
- **Available Events**:
438
+ ---
439
+
440
+ ## UI Elements
448
441
 
449
- - `wallet:connected` - Wallet successfully connected
450
- - `wallet:disconnected` - Wallet disconnected
451
- - `wallet:changed` - Selected wallet changed
452
- - `account:changed` - Selected account changed
453
- - `cluster:changed` - Network/cluster changed
454
- - `wallets:detected` - New wallets detected
455
- - `connecting` - Connection attempt started
456
- - `connection:failed` - Connection attempt failed
457
- - `error` - Error occurred
442
+ ConnectorKit provides composable UI elements that handle data fetching and state management for you. Use the render prop pattern to customize the UI.
458
443
 
459
- ### Debug Panel
444
+ ### Available Elements
460
445
 
461
- Floating development panel for instant state visibility.
446
+ - `BalanceElement` - Display SOL balance with refresh
447
+ - `ClusterElement` - Network/cluster selector
448
+ - `TokenListElement` - List of SPL tokens
449
+ - `TransactionHistoryElement` - Recent transaction history
450
+ - `DisconnectElement` - Disconnect button
451
+ - `AccountElement` - Account display and switcher
452
+ - `WalletListElement` - List of available wallets
453
+
454
+ ### Example: Wallet Dropdown
462
455
 
463
456
  ```typescript
464
- import { ConnectorDebugPanel } from '@solana/connector';
465
-
466
- function App() {
467
- return (
468
- <ConnectorProvider config={config}>
469
- {/* Only visible in development mode */}
470
- {process.env.NODE_ENV === 'development' && <ConnectorDebugPanel />}
471
- <YourApp />
472
- </ConnectorProvider>
473
- );
457
+ 'use client';
458
+
459
+ import {
460
+ BalanceElement,
461
+ ClusterElement,
462
+ TokenListElement,
463
+ TransactionHistoryElement,
464
+ DisconnectElement,
465
+ } from '@solana/connector/react';
466
+
467
+ export function WalletDropdown() {
468
+ return (
469
+ <div className="wallet-dropdown">
470
+ {/* Balance */}
471
+ <BalanceElement
472
+ render={({ solBalance, isLoading, refetch }) => (
473
+ <div>
474
+ <div>Balance: {isLoading ? '...' : `${solBalance?.toFixed(4)} SOL`}</div>
475
+ <button onClick={refetch}>Refresh</button>
476
+ </div>
477
+ )}
478
+ />
479
+
480
+ {/* Network Selector */}
481
+ <ClusterElement
482
+ render={({ cluster, clusters, setCluster }) => (
483
+ <select value={cluster?.id} onChange={e => setCluster(e.target.value)}>
484
+ {clusters.map(c => (
485
+ <option key={c.id} value={c.id}>
486
+ {c.label}
487
+ </option>
488
+ ))}
489
+ </select>
490
+ )}
491
+ />
492
+
493
+ {/* Tokens */}
494
+ <TokenListElement
495
+ limit={5}
496
+ render={({ tokens, isLoading }) => (
497
+ <div>
498
+ {isLoading ? (
499
+ <div>Loading tokens...</div>
500
+ ) : (
501
+ tokens.map(token => (
502
+ <div key={token.mint}>
503
+ {token.symbol}: {token.formatted}
504
+ </div>
505
+ ))
506
+ )}
507
+ </div>
508
+ )}
509
+ />
510
+
511
+ {/* Transaction History */}
512
+ <TransactionHistoryElement
513
+ limit={5}
514
+ render={({ transactions, isLoading }) => (
515
+ <div>
516
+ {isLoading ? (
517
+ <div>Loading transactions...</div>
518
+ ) : (
519
+ transactions.map(tx => (
520
+ <a key={tx.signature} href={tx.explorerUrl} target="_blank">
521
+ {tx.type} - {tx.formattedTime}
522
+ </a>
523
+ ))
524
+ )}
525
+ </div>
526
+ )}
527
+ />
528
+
529
+ {/* Disconnect */}
530
+ <DisconnectElement
531
+ render={({ disconnect, disconnecting }) => (
532
+ <button onClick={disconnect} disabled={disconnecting}>
533
+ {disconnecting ? 'Disconnecting...' : 'Disconnect'}
534
+ </button>
535
+ )}
536
+ />
537
+ </div>
538
+ );
474
539
  }
475
540
  ```
476
541
 
477
- **Features**:
542
+ ---
478
543
 
479
- - Shows connection status (connected/disconnected/connecting)
480
- - Displays current account and wallet
481
- - Shows active cluster and RPC URL
482
- - Lists detected wallets
483
- - Health check information
484
- - Click to expand/collapse
485
- - Automatically excluded in production builds
544
+ ## Configuration
486
545
 
487
- **Custom positioning**:
546
+ ### Basic Configuration
488
547
 
489
548
  ```typescript
490
- <ConnectorDebugPanel
491
- position="top-left" // 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
492
- defaultOpen={true}
493
- zIndex={10000}
494
- />
495
- ```
549
+ import { getDefaultConfig } from '@solana/connector';
496
550
 
497
- ### Connection Pooling
551
+ const config = getDefaultConfig({
552
+ appName: 'My App', // Required
553
+ appUrl: 'https://myapp.com', // Optional: for mobile wallet adapter
554
+ autoConnect: true, // Auto-reconnect (default: true)
555
+ network: 'mainnet-beta', // Initial network (default: 'mainnet-beta')
556
+ enableMobile: true, // Mobile Wallet Adapter (default: true)
557
+ debug: false, // Debug logging
558
+ });
559
+ ```
498
560
 
499
- Reusable RPC connections for better performance.
561
+ ### Network Selection
500
562
 
501
563
  ```typescript
502
- import { ConnectionPool, createConnectionPool } from '@solana/connector/headless';
503
- import { Connection } from '@solana/web3.js';
504
-
505
- // Create custom pool
506
- const pool = createConnectionPool({
507
- maxSize: 10,
508
- createConnection: cluster => {
509
- return new Connection(cluster.endpoint, {
510
- commitment: 'confirmed',
511
- });
512
- },
564
+ const config = getDefaultConfig({
565
+ appName: 'My App',
566
+ network: 'devnet', // 'mainnet-beta' | 'devnet' | 'testnet' | 'localnet'
513
567
  });
568
+ ```
514
569
 
515
- // Get or create connection for a cluster
516
- const connection = pool.get(currentCluster);
517
- const balance = await connection.getBalance(publicKey);
570
+ ### Custom RPC Endpoints
518
571
 
519
- // Clear specific connection when settings change
520
- pool.clear('solana:mainnet');
572
+ ```typescript
573
+ import { getDefaultConfig } from '@solana/connector';
521
574
 
522
- // Get pool statistics
523
- const stats = pool.getStats();
524
- console.log(`Pool: ${stats.size}/${stats.maxSize}`);
525
- console.log(`Hit rate: ${(stats.hits / (stats.hits + stats.misses)) * 100}%`);
575
+ const config = getDefaultConfig({
576
+ appName: 'My App',
577
+ clusters: [
578
+ {
579
+ id: 'solana:mainnet' as const,
580
+ label: 'Mainnet (Custom RPC)',
581
+ name: 'mainnet-beta' as const,
582
+ url: 'https://my-custom-rpc.com',
583
+ },
584
+ {
585
+ id: 'solana:devnet' as const,
586
+ label: 'Devnet',
587
+ name: 'devnet' as const,
588
+ url: 'https://api.devnet.solana.com',
589
+ },
590
+ ],
591
+ });
526
592
  ```
527
593
 
528
- **Global pool** (simpler):
594
+ ### Mobile Wallet Adapter
529
595
 
530
596
  ```typescript
531
- import { getConnectionPool } from '@solana/connector/headless';
597
+ import { getDefaultMobileConfig } from '@solana/connector/headless';
598
+
599
+ const mobile = getDefaultMobileConfig({
600
+ appName: 'My App',
601
+ appUrl: 'https://myapp.com',
602
+ });
532
603
 
533
- const pool = getConnectionPool();
534
- const connection = pool.get(cluster);
604
+ <AppProvider connectorConfig={config} mobile={mobile}>
605
+ {children}
606
+ </AppProvider>
535
607
  ```
536
608
 
537
- ### Health Checks
609
+ ---
538
610
 
539
- Comprehensive diagnostics for debugging and monitoring.
611
+ ## Security Considerations
540
612
 
541
- ```typescript
542
- import { useConnectorClient } from '@solana/connector';
613
+ ### Token Image Privacy
543
614
 
544
- function HealthMonitor() {
545
- const client = useConnectorClient();
615
+ When using `useTokens()` or `useTransactions()`, token metadata (including logo URLs) is fetched from external APIs. By default, these image URLs are returned directly, which means when your users' browsers fetch these images, the image host can see:
546
616
 
547
- if (!client) return null;
617
+ - User IP addresses
618
+ - Request timing (when users viewed their tokens)
619
+ - User agent and browser information
548
620
 
549
- const health = client.getHealth();
621
+ This could potentially be exploited by malicious token creators who set tracking URLs in their token metadata.
550
622
 
551
- return (
552
- <div>
553
- <h3>Connector Health</h3>
554
- <div>Initialized: {health.initialized ? '✓' : '✗'}</div>
555
- <div>Wallet Standard: {health.walletStandardAvailable ? '✓' : '✗'}</div>
556
- <div>Storage: {health.storageAvailable ? '✓' : '✗'}</div>
557
- <div>Wallets Detected: {health.walletsDetected}</div>
623
+ ### Image Proxy Configuration
558
624
 
559
- {health.errors.length > 0 && (
560
- <div className="errors">
561
- {health.errors.map(err => <div key={err}>{err}</div>)}
562
- </div>
563
- )}
564
- </div>
565
- );
566
- }
625
+ To protect user privacy, you can configure an image proxy that fetches images on behalf of your users:
626
+
627
+ ```typescript
628
+ const config = getDefaultConfig({
629
+ appName: 'My App',
630
+ imageProxy: '/_next/image?w=64&q=75&url=', // Next.js Image Optimization
631
+ });
632
+ ```
633
+
634
+ When `imageProxy` is set, all token image URLs returned by `useTokens()` and `useTransactions()` will be automatically transformed:
635
+
636
+ ```
637
+ // Original URL from token metadata
638
+ https://raw.githubusercontent.com/.../token-logo.png
639
+
640
+ // Transformed URL (when imageProxy is set)
641
+ /_next/image?w=64&q=75&url=https%3A%2F%2Fraw.githubusercontent.com%2F...%2Ftoken-logo.png
567
642
  ```
568
643
 
569
- ### Wallet Adapter Compatibility
644
+ ### Common Proxy Options
570
645
 
571
- Drop-in replacement for libraries expecting @solana/wallet-adapter.
646
+ | Service | Configuration |
647
+ |---------|---------------|
648
+ | **Next.js Image** | `imageProxy: '/_next/image?w=64&q=75&url='` |
649
+ | **Cloudflare** | `imageProxy: '/cdn-cgi/image/width=64,quality=75/'` |
650
+ | **imgproxy** | `imageProxy: 'https://imgproxy.example.com/insecure/fill/64/64/'` |
651
+ | **Custom API** | `imageProxy: '/api/image-proxy?url='` |
652
+
653
+ ### Custom Proxy API Route (Next.js Example)
572
654
 
573
655
  ```typescript
574
- import { useTransactionSigner, useConnector } from '@solana/connector';
575
- import { createWalletAdapterCompat } from '@solana/connector/compat';
656
+ // app/api/image-proxy/route.ts
657
+ import { NextRequest, NextResponse } from 'next/server';
658
+ import dns from 'dns/promises';
659
+
660
+ // Allowlist of permitted domains for image fetching
661
+ const ALLOWED_DOMAINS = [
662
+ 'raw.githubusercontent.com',
663
+ 'arweave.net',
664
+ 'ipfs.io',
665
+ 'cloudflare-ipfs.com',
666
+ 'nftstorage.link',
667
+ // Add other trusted image domains as needed
668
+ ];
669
+
670
+ // Check if an IP address falls within private/reserved ranges
671
+ function isPrivateOrReservedIP(ip: string): boolean {
672
+ // IPv4 private/reserved ranges
673
+ const ipv4PrivateRanges = [
674
+ /^127\./, // 127.0.0.0/8 (loopback)
675
+ /^10\./, // 10.0.0.0/8 (private)
676
+ /^172\.(1[6-9]|2[0-9]|3[0-1])\./, // 172.16.0.0/12 (private)
677
+ /^192\.168\./, // 192.168.0.0/16 (private)
678
+ /^169\.254\./, // 169.254.0.0/16 (link-local/metadata)
679
+ /^0\./, // 0.0.0.0/8 (current network)
680
+ /^100\.(6[4-9]|[7-9][0-9]|1[0-1][0-9]|12[0-7])\./, // 100.64.0.0/10 (CGNAT)
681
+ /^192\.0\.0\./, // 192.0.0.0/24 (IETF protocol assignments)
682
+ /^192\.0\.2\./, // 192.0.2.0/24 (TEST-NET-1)
683
+ /^198\.51\.100\./, // 198.51.100.0/24 (TEST-NET-2)
684
+ /^203\.0\.113\./, // 203.0.113.0/24 (TEST-NET-3)
685
+ /^224\./, // 224.0.0.0/4 (multicast)
686
+ /^240\./, // 240.0.0.0/4 (reserved)
687
+ /^255\.255\.255\.255$/, // broadcast
688
+ ];
689
+
690
+ // IPv6 private/reserved ranges
691
+ const ipv6PrivatePatterns = [
692
+ /^::1$/, // loopback
693
+ /^fe80:/i, // link-local
694
+ /^fc00:/i, // unique local (fc00::/7)
695
+ /^fd/i, // unique local (fd00::/8)
696
+ /^::ffff:(127\.|10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.|169\.254\.)/i, // IPv4-mapped
697
+ ];
698
+
699
+ // Check IPv4
700
+ for (const range of ipv4PrivateRanges) {
701
+ if (range.test(ip)) return true;
702
+ }
703
+
704
+ // Check IPv6
705
+ for (const pattern of ipv6PrivatePatterns) {
706
+ if (pattern.test(ip)) return true;
707
+ }
576
708
 
577
- function JupiterIntegration() {
578
- const { signer } = useTransactionSigner();
579
- const { disconnect } = useConnector();
709
+ return false;
710
+ }
580
711
 
581
- // Create wallet-adapter compatible interface
582
- const walletAdapter = createWalletAdapterCompat(signer, {
583
- disconnect: async () => {
584
- await disconnect();
585
- },
586
- onError: (error, operation) => {
587
- console.error(`Wallet adapter error in ${operation}:`, error);
712
+ // Validate and parse the URL
713
+ function validateUrl(urlString: string): URL | null {
714
+ try {
715
+ const parsed = new URL(urlString);
716
+ // Only allow http and https protocols
717
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
718
+ return null;
719
+ }
720
+ return parsed;
721
+ } catch {
722
+ return null;
588
723
  }
589
- });
724
+ }
590
725
 
591
- // Use with Jupiter, Serum, or any wallet-adapter library
592
- return <JupiterTerminal wallet={walletAdapter} />;
726
+ // Check if hostname is in the allowlist
727
+ function isAllowedDomain(hostname: string): boolean {
728
+ return ALLOWED_DOMAINS.some(
729
+ (domain) => hostname === domain || hostname.endsWith(`.${domain}`)
730
+ );
593
731
  }
594
- ```
595
732
 
596
- **Compatible with**:
733
+ export async function GET(request: NextRequest) {
734
+ const urlParam = request.nextUrl.searchParams.get('url');
735
+
736
+ // (1) Ensure URL exists and parses correctly with http/https
737
+ if (!urlParam) {
738
+ return new NextResponse('Missing URL parameter', { status: 400 });
739
+ }
597
740
 
598
- - Jupiter Aggregator
599
- - Serum DEX
600
- - Raydium
601
- - Marinade Finance
602
- - Any library expecting @solana/wallet-adapter
741
+ const parsedUrl = validateUrl(urlParam);
742
+ if (!parsedUrl) {
743
+ return new NextResponse('Invalid URL or protocol', { status: 400 });
744
+ }
745
+
746
+ // (2) Enforce allowlist of permitted domains
747
+ if (!isAllowedDomain(parsedUrl.hostname)) {
748
+ return new NextResponse('Domain not allowed', { status: 403 });
749
+ }
750
+
751
+ // (3) Resolve hostname and check for private/reserved IPs
752
+ try {
753
+ const addresses = await dns.resolve(parsedUrl.hostname);
754
+ for (const ip of addresses) {
755
+ if (isPrivateOrReservedIP(ip)) {
756
+ return new NextResponse('Resolved IP is not allowed', { status: 403 });
757
+ }
758
+ }
759
+ } catch {
760
+ return new NextResponse('Failed to resolve hostname', { status: 400 });
761
+ }
762
+
763
+ // (4) All checks passed - perform the fetch
764
+ try {
765
+ const response = await fetch(parsedUrl.toString());
766
+ const buffer = await response.arrayBuffer();
767
+
768
+ return new NextResponse(buffer, {
769
+ headers: {
770
+ 'Content-Type': response.headers.get('Content-Type') || 'image/png',
771
+ 'Cache-Control': 'public, max-age=86400',
772
+ },
773
+ });
774
+ } catch {
775
+ return new NextResponse('Failed to fetch image', { status: 500 });
776
+ }
777
+ }
778
+ ```
603
779
 
604
780
  ---
605
781
 
606
- ## Configuration
782
+ ## CoinGecko API & Rate Limits
607
783
 
608
- ### Basic Configuration
784
+ The `useTokens()` hook fetches token prices from CoinGecko. CoinGecko has rate limits that may affect your application:
609
785
 
610
- ```typescript
611
- import { getDefaultConfig } from '@solana/connector';
786
+ ### Rate Limits (as of 2024)
612
787
 
613
- const config = getDefaultConfig({
614
- appName: 'My App', // Required
615
- autoConnect: true, // Auto-reconnect (default: true)
616
- network: 'mainnet-beta', // Initial network
617
- enableMobile: true, // Mobile Wallet Adapter (default: true)
618
- debug: false, // Debug logging
788
+ | Tier | Rate Limit | API Key Required |
789
+ |------|------------|------------------|
790
+ | **Free (Public)** | 10-30 requests/minute | No |
791
+ | **Demo** | 30 requests/minute | Yes (free) |
792
+ | **Analyst** | 500 requests/minute | Yes (paid) |
793
+ | **Pro** | 1000+ requests/minute | Yes (paid) |
619
794
 
620
- // NEW: Custom error handler
621
- onError: (error, errorInfo) => {
622
- console.error('Connector error:', error);
623
- errorTracker.captureException(error, errorInfo);
624
- },
625
- });
626
- ```
795
+ ### Handling Rate Limits
627
796
 
628
- ### Network Selection
797
+ ConnectorKit automatically handles rate limits with:
798
+ - **Exponential backoff**: Retries with increasing delays
799
+ - **Jitter**: Random delay added to prevent thundering herd
800
+ - **Retry-After header**: Honors server-specified wait times
801
+ - **Bounded timeout**: Won't block forever (default 30s max)
802
+
803
+ ### Adding a CoinGecko API Key
804
+
805
+ For higher rate limits, add a free Demo API key from [CoinGecko](https://www.coingecko.com/en/api/pricing):
629
806
 
630
807
  ```typescript
631
808
  const config = getDefaultConfig({
632
809
  appName: 'My App',
633
- network: 'devnet', // 'mainnet-beta' | 'devnet' | 'testnet' | 'localnet'
810
+ coingecko: {
811
+ apiKey: process.env.COINGECKO_API_KEY, // Demo or Pro API key
812
+ isPro: false, // Set to true for Pro API keys
813
+ },
634
814
  });
635
815
  ```
636
816
 
637
- ### Custom Clusters
817
+ ### Advanced Configuration
638
818
 
639
819
  ```typescript
640
- import { getDefaultConfig, createSolanaMainnet } from '@solana/connector';
641
-
642
820
  const config = getDefaultConfig({
643
821
  appName: 'My App',
644
- clusters: [
645
- createSolanaMainnet({
646
- endpoint: 'https://my-custom-rpc.com',
647
- }),
648
- ],
649
- customClusters: [
650
- // Add additional custom clusters
651
- ],
822
+ coingecko: {
823
+ // API key for higher rate limits (optional)
824
+ apiKey: process.env.COINGECKO_API_KEY,
825
+
826
+ // Set to true if using a Pro API key (default: false for Demo keys)
827
+ isPro: false,
828
+
829
+ // Maximum retry attempts on 429 (default: 3)
830
+ maxRetries: 3,
831
+
832
+ // Base delay for exponential backoff in ms (default: 1000)
833
+ baseDelay: 1000,
834
+
835
+ // Maximum total timeout in ms (default: 30000)
836
+ maxTimeout: 30000,
837
+ },
652
838
  });
653
839
  ```
654
840
 
655
- ### Mobile Wallet Adapter
841
+ ### Caching
656
842
 
657
- ```typescript
658
- <ConnectorProvider
659
- config={config}
660
- mobile={{
661
- appIdentity: {
662
- name: 'My App',
663
- uri: 'https://myapp.com',
664
- icon: 'https://myapp.com/icon.png'
665
- }
666
- }}
667
- >
668
- <App />
669
- </ConnectorProvider>
670
- ```
843
+ Token prices are cached for 60 seconds to minimize API calls. The retry logic only applies to uncached token IDs, so frequently-viewed tokens won't trigger additional API calls.
671
844
 
672
845
  ---
673
846
 
@@ -675,7 +848,7 @@ const config = getDefaultConfig({
675
848
 
676
849
  ### Headless Client (Vue, Svelte, Vanilla JS)
677
850
 
678
- Use `ConnectorClient` for non-React frameworks.
851
+ Use `ConnectorClient` for non-React frameworks:
679
852
 
680
853
  ```typescript
681
854
  import { ConnectorClient, getDefaultConfig } from '@solana/connector/headless';
@@ -695,15 +868,6 @@ const unsubscribe = client.subscribe(state => {
695
868
  console.log('State updated:', state);
696
869
  });
697
870
 
698
- // Subscribe to events (NEW!)
699
- const unsubEvents = client.on(event => {
700
- console.log('Event:', event.type, event);
701
- });
702
-
703
- // Check health (NEW!)
704
- const health = client.getHealth();
705
- console.log('Health:', health);
706
-
707
871
  // Disconnect
708
872
  await client.disconnect();
709
873
 
@@ -711,44 +875,15 @@ await client.disconnect();
711
875
  client.destroy();
712
876
  ```
713
877
 
714
- ### Unified Config (Armadura Integration)
715
-
716
- If you're using both ConnectorKit and Armadura:
717
-
718
- ```typescript
719
- import { createConfig, AppProvider } from '@solana/connector';
720
- import { ArmaProvider } from '@armadura/sdk';
721
-
722
- const config = createConfig({
723
- appName: 'My App',
724
- network: 'mainnet',
725
- rpcUrl: 'https://my-custom-rpc.com',
726
- autoConnect: true
727
- });
728
-
729
- function App() {
730
- return (
731
- <AppProvider config={config.connectorConfig}>
732
- <ArmaProvider
733
- config={{
734
- network: config.network,
735
- rpcUrl: config.rpcUrl,
736
- providers: [/* ... */]
737
- }}
738
- useConnector="auto"
739
- >
740
- {children}
741
- </ArmaProvider>
742
- </AppProvider>
743
- );
744
- }
745
- ```
878
+ ### Custom Storage (React Native, SSR)
746
879
 
747
- ### Custom Storage
880
+ Storage uses nanostores with built-in enhancements that are **automatically applied**:
748
881
 
749
- **Most users don't need to configure storage** - it works automatically with validation, error handling, and SSR fallback.
882
+ - Validation (Solana address format checking)
883
+ - Error handling (catches localStorage quota errors, private browsing)
884
+ - SSR fallback (uses memory storage when localStorage unavailable)
750
885
 
751
- Only customize for:
886
+ **Most users don't need to configure storage.** Only customize for:
752
887
 
753
888
  - React Native (custom storage backend)
754
889
  - Additional validation rules
@@ -759,7 +894,6 @@ import { getDefaultConfig, createEnhancedStorageWallet, EnhancedStorageAdapter }
759
894
 
760
895
  const config = getDefaultConfig({
761
896
  appName: 'My App',
762
-
763
897
  storage: {
764
898
  wallet: new EnhancedStorageAdapter(
765
899
  createEnhancedStorageWallet({
@@ -768,11 +902,11 @@ const config = getDefaultConfig({
768
902
  return walletName !== null && walletName.length > 0;
769
903
  },
770
904
  onError: error => {
905
+ // Custom error tracking
771
906
  Sentry.captureException(error);
772
907
  },
773
908
  }),
774
909
  ),
775
- // account and cluster use defaults if not specified
776
910
  },
777
911
  });
778
912
  ```
@@ -785,7 +919,7 @@ const config = getDefaultConfig({
785
919
 
786
920
  ```typescript
787
921
  // Full library - includes React and headless
788
- import { ConnectorProvider, useConnector } from '@solana/connector';
922
+ import { ConnectorProvider, useConnector, useAccount } from '@solana/connector';
789
923
  ```
790
924
 
791
925
  ### Headless Export (Framework Agnostic)
@@ -802,427 +936,58 @@ import { ConnectorClient, getDefaultConfig } from '@solana/connector/headless';
802
936
  import { useConnector, useAccount } from '@solana/connector/react';
803
937
  ```
804
938
 
805
- ### Compatibility Layer (NEW!)
806
-
807
- ```typescript
808
- // Wallet adapter compatibility bridge
809
- import { createWalletAdapterCompat } from '@solana/connector/compat';
810
- ```
811
-
812
939
  ---
813
940
 
814
- ## Testing
815
-
816
- The connector package includes a comprehensive test suite built with Vitest. All tests are located in `src/__tests__/` and co-located with source files.
817
-
818
- ### Running Tests
819
-
820
- ```bash
821
- # Run all tests
822
- pnpm test
823
-
824
- # Run tests in watch mode
825
- pnpm test:watch
826
-
827
- # Run tests with UI
828
- pnpm test:ui
829
-
830
- # Generate coverage report
831
- pnpm test:coverage
832
- ```
833
-
834
- ### Test Coverage
835
-
836
- The package maintains high test coverage:
837
-
838
- - **Lines**: 80%+
839
- - **Functions**: 80%+
840
- - **Branches**: 75%+
841
- - **Statements**: 80%+
842
-
843
- ### Test Structure
844
-
845
- ```
846
- src/
847
- ├── lib/
848
- │ ├── core/
849
- │ │ ├── state-manager.ts
850
- │ │ └── state-manager.test.ts # Unit tests
851
- │ └── connection/
852
- │ ├── connection-manager.ts
853
- │ └── connection-manager.test.ts # Unit tests
854
- ├── hooks/
855
- │ ├── use-account.ts
856
- │ └── use-account.test.tsx # React hook tests
857
- └── __tests__/
858
- ├── setup.ts # Global test setup
859
- ├── mocks/ # Mock implementations
860
- │ ├── wallet-standard-mock.ts # Mock wallets
861
- │ ├── storage-mock.ts # Mock storage
862
- │ └── window-mock.ts # Mock browser APIs
863
- ├── fixtures/ # Test data
864
- │ ├── wallets.ts # Wallet fixtures
865
- │ ├── accounts.ts # Account fixtures
866
- │ └── transactions.ts # Transaction fixtures
867
- ├── utils/ # Test helpers
868
- │ ├── test-helpers.ts # Common utilities
869
- │ ├── react-helpers.tsx # React test utils
870
- │ └── wait-for-state.ts # State helpers
871
- └── integration/ # Integration tests
872
- └── connector-flow.test.ts # Full workflows
873
- ```
874
-
875
- ### Writing Tests
876
-
877
- Example unit test:
878
-
879
- ```typescript
880
- import { describe, it, expect } from 'vitest';
881
- import { StateManager } from './state-manager';
882
-
883
- describe('StateManager', () => {
884
- it('should update state correctly', () => {
885
- const manager = new StateManager(initialState);
886
- manager.updateState({ connected: true });
887
-
888
- expect(manager.getSnapshot().connected).toBe(true);
889
- });
890
- });
891
- ```
892
-
893
- Example React hook test:
894
-
895
- ```typescript
896
- import { renderHook } from '@testing-library/react';
897
- import { useAccount } from './use-account';
898
- import { createHookWrapper } from '../__tests__/utils/react-helpers';
899
-
900
- describe('useAccount', () => {
901
- it('should return account information', () => {
902
- const { result } = renderHook(() => useAccount(), {
903
- wrapper: createHookWrapper(),
904
- });
905
-
906
- expect(result.current.address).toBeDefined();
907
- });
908
- });
909
- ```
910
-
911
- ### Test Utilities
912
-
913
- The package provides comprehensive test utilities:
914
-
915
- **Mock Wallets:**
916
-
917
- ```typescript
918
- import { createMockPhantomWallet, createMockSolflareWallet } from '../mocks/wallet-standard-mock';
919
-
920
- const wallet = createMockPhantomWallet({
921
- connectBehavior: 'success', // or 'error', 'timeout'
922
- });
923
- ```
924
-
925
- **Test Fixtures:**
926
-
927
- ```typescript
928
- import { createTestAccounts, TEST_ADDRESSES } from '../fixtures/accounts';
929
- import { createTestWallets } from '../fixtures/wallets';
930
-
931
- const accounts = createTestAccounts(3);
932
- const wallets = createTestWallets();
933
- ```
934
-
935
- **Test Helpers:**
936
-
937
- ```typescript
938
- import { waitForCondition, createEventCollector } from '../utils/test-helpers';
939
-
940
- // Wait for a condition
941
- await waitForCondition(() => state.connected, { timeout: 5000 });
942
-
943
- // Collect events
944
- const collector = createEventCollector();
945
- client.on(collector.collect);
946
- collector.assertEventEmitted('connected');
947
- ```
948
-
949
- ### Contributing Tests
941
+ ## API Reference
950
942
 
951
- All new features and bug fixes should include tests:
943
+ ### Hooks
952
944
 
953
- 1. Create test file next to source file with `.test.ts` or `.test.tsx` extension
954
- 2. Follow existing patterns in similar test files
955
- 3. Ensure tests pass locally before submitting
956
- 4. Maintain or improve coverage percentage
957
-
958
- For detailed testing guidelines, see [Testing Guide](src/__tests__/README.md).
959
-
960
- ---
961
-
962
- ## Complete API Reference
945
+ | Hook | Description | Returns |
946
+ |------|-------------|---------|
947
+ | `useConnector()` | Main wallet connection hook | `{ wallets, selectedWallet, accounts, connected, connecting, select, disconnect }` |
948
+ | `useAccount()` | Account management hook | `{ address, formatted, copy, copied, accounts, selectAccount }` |
949
+ | `useCluster()` | Network/cluster management hook | `{ cluster, clusters, setCluster, isMainnet, isDevnet, rpcUrl }` |
950
+ | `useWalletInfo()` | Wallet metadata hook | `{ name, icon, wallet, connecting }` |
951
+ | `useTransactionSigner()` | Legacy transaction signer (web3.js) | `{ signer, ready, address, capabilities }` |
952
+ | `useKitTransactionSigner()` | Modern transaction signer (@solana/kit) | `{ signer, ready, address }` |
953
+ | `useBalance()` | SOL balance hook | `{ solBalance, isLoading, refetch }` |
954
+ | `useTokens()` | SPL tokens hook | `{ tokens, isLoading, refetch }` |
955
+ | `useTransactions()` | Transaction history hook | `{ transactions, isLoading, refetch }` |
963
956
 
964
957
  ### Configuration Functions
965
958
 
966
- #### `getDefaultConfig(options)`
967
-
968
- ```typescript
969
- const config = getDefaultConfig({
970
- appName: string, // Required: App name
971
- appUrl?: string, // App URL for metadata
972
- autoConnect?: boolean, // Auto-reconnect (default: true)
973
- debug?: boolean, // Debug logging
974
- network?: 'mainnet' | 'mainnet-beta' // Initial network (default: mainnet-beta)
975
- | 'devnet' | 'testnet' | 'localnet',
976
- enableMobile?: boolean, // Mobile Wallet Adapter (default: true)
977
- storage?: ConnectorConfig['storage'], // Custom storage adapters
978
- clusters?: SolanaCluster[], // Override default clusters
979
- customClusters?: SolanaCluster[], // Add custom clusters
980
- persistClusterSelection?: boolean, // Persist cluster (default: true)
981
- enableErrorBoundary?: boolean, // Error boundaries (default: true)
982
- maxRetries?: number, // Retry attempts (default: 3)
983
- onError?: (error, errorInfo) => void // Error handler (NEW!)
984
- });
985
- ```
986
-
987
- ### Transaction Signing API (NEW!)
988
-
989
- #### `useTransactionSigner()`
990
-
991
- React hook for transaction operations.
992
-
993
- ```typescript
994
- interface UseTransactionSignerReturn {
995
- signer: TransactionSigner | null; // Signer instance
996
- ready: boolean; // Whether signer is ready
997
- address: string | null; // Current address
998
- capabilities: TransactionSignerCapabilities; // What signer can do
999
- }
1000
- ```
1001
-
1002
- #### `createTransactionSigner(config)`
1003
-
1004
- Create a transaction signer (headless).
1005
-
1006
- ```typescript
1007
- import { createTransactionSigner } from '@solana/connector/headless';
1008
-
1009
- const signer = createTransactionSigner({
1010
- wallet: connectedWallet,
1011
- account: selectedAccount,
1012
- cluster: currentCluster, // Optional
1013
- });
1014
- ```
1015
-
1016
- #### `TransactionSigner` Interface
1017
-
1018
- ```typescript
1019
- interface TransactionSigner {
1020
- readonly address: string;
1021
-
1022
- signTransaction(tx: any): Promise<any>;
1023
- signAllTransactions(txs: any[]): Promise<any[]>;
1024
- signAndSendTransaction(tx: any, options?: SendOptions): Promise<string>;
1025
- signAndSendTransactions(txs: any[], options?: SendOptions): Promise<string[]>;
1026
- signMessage?(message: Uint8Array): Promise<Uint8Array>;
1027
-
1028
- getCapabilities(): TransactionSignerCapabilities;
1029
- }
1030
- ```
1031
-
1032
- ### Event System API (NEW!)
1033
-
1034
- #### Event Types
1035
-
1036
- ```typescript
1037
- type ConnectorEvent =
1038
- | { type: 'wallet:connected'; wallet: string; account: string; timestamp: string }
1039
- | { type: 'wallet:disconnected'; timestamp: string }
1040
- | { type: 'cluster:changed'; cluster: string; previousCluster: string | null; timestamp: string }
1041
- | { type: 'wallets:detected'; count: number; timestamp: string }
1042
- | { type: 'connecting'; wallet: string; timestamp: string }
1043
- | { type: 'connection:failed'; wallet: string; error: string; timestamp: string }
1044
- | { type: 'error'; error: Error; context: string; timestamp: string };
1045
- ```
1046
-
1047
- #### Methods
1048
-
1049
- ```typescript
1050
- // Subscribe to events
1051
- const unsubscribe = client.on(event => {
1052
- console.log('Event:', event.type, event);
1053
- });
1054
-
1055
- // Unsubscribe
1056
- client.off(listener);
1057
-
1058
- // Unsubscribe all
1059
- client.offAll();
1060
- ```
1061
-
1062
- ### Health Check API (NEW!)
1063
-
1064
- ```typescript
1065
- interface ConnectorHealth {
1066
- initialized: boolean;
1067
- walletStandardAvailable: boolean;
1068
- storageAvailable: boolean;
1069
- walletsDetected: number;
1070
- errors: string[];
1071
- connectionState: {
1072
- connected: boolean;
1073
- connecting: boolean;
1074
- hasSelectedWallet: boolean;
1075
- hasSelectedAccount: boolean;
1076
- };
1077
- timestamp: string;
1078
- }
1079
-
1080
- // Get health status
1081
- const health = client.getHealth();
1082
- ```
1083
-
1084
- ### Connection Pool API (NEW!)
1085
-
1086
- ```typescript
1087
- class ConnectionPool {
1088
- get(cluster: SolanaCluster): ConnectionLike;
1089
- has(clusterId: string): boolean;
1090
- clear(clusterId: string): void;
1091
- clearAll(): void;
1092
- getStats(): ConnectionPoolStats;
1093
- resetStats(): void;
1094
- }
1095
-
1096
- // Create pool
1097
- const pool = createConnectionPool(options);
1098
-
1099
- // Get global pool
1100
- const pool = getConnectionPool();
1101
- ```
1102
-
1103
- ### Wallet Adapter Compat API (NEW!)
1104
-
1105
- ```typescript
1106
- // Create wallet-adapter compatible interface
1107
- createWalletAdapterCompat(
1108
- signer: TransactionSigner | null,
1109
- options: {
1110
- disconnect: () => Promise<void>;
1111
- transformTransaction?: (tx: any) => any;
1112
- onError?: (error: Error, operation: string) => void;
1113
- }
1114
- ): WalletAdapterCompatible
1115
-
1116
- // React hook version
1117
- useWalletAdapterCompat(
1118
- signer: TransactionSigner | null,
1119
- disconnect: () => Promise<void>,
1120
- options?: Omit<WalletAdapterCompatOptions, 'disconnect'>
1121
- ): WalletAdapterCompatible
1122
-
1123
- // Type guard
1124
- isWalletAdapterCompatible(obj: any): obj is WalletAdapterCompatible
1125
- ```
1126
-
1127
- ### Polyfill API (NEW!)
1128
-
1129
- ```typescript
1130
- import {
1131
- installPolyfills,
1132
- isPolyfillInstalled,
1133
- isCryptoAvailable,
1134
- getPolyfillStatus,
1135
- } from '@solana/connector/headless';
1136
-
1137
- // Install browser polyfills (automatic in React provider)
1138
- installPolyfills();
1139
-
1140
- // Check status
1141
- const installed = isPolyfillInstalled();
1142
- const cryptoAvailable = isCryptoAvailable();
1143
- const status = getPolyfillStatus();
1144
- ```
959
+ | Function | Description |
960
+ |----------|-------------|
961
+ | `getDefaultConfig(options)` | Create default connector configuration |
962
+ | `getDefaultMobileConfig(options)` | Create mobile wallet adapter configuration |
963
+ | `createConfig(options)` | Create unified config for ConnectorKit + Armadura |
1145
964
 
1146
965
  ### Utility Functions
1147
966
 
1148
- #### Formatting
967
+ | Function | Description |
968
+ |----------|-------------|
969
+ | `formatAddress(address, options?)` | Format Solana address |
970
+ | `formatSOL(lamports, options?)` | Format SOL amount |
971
+ | `copyAddressToClipboard(address)` | Copy address to clipboard |
972
+ | `getTransactionUrl(cluster, signature)` | Get Solana Explorer transaction URL |
973
+ | `getAddressUrl(cluster, address)` | Get Solana Explorer address URL |
1149
974
 
1150
- ```typescript
1151
- import { formatSOL, formatAddress } from '@solana/connector';
1152
-
1153
- // Format SOL amounts
1154
- formatSOL(1500000000, { decimals: 4 }); // "1.5000 SOL"
1155
-
1156
- // Format addresses
1157
- formatAddress(address, { length: 6 }); // "5Gv8yU...8x3kF"
1158
-
1159
- // Lightweight versions (smaller bundle, no Intl)
1160
- import { formatSOLSimple, formatAddressSimple } from '@solana/connector';
1161
- ```
1162
-
1163
- #### Clipboard
1164
-
1165
- ```typescript
1166
- import { copyAddressToClipboard, copyToClipboard } from '@solana/connector';
1167
-
1168
- await copyAddressToClipboard(address);
1169
- await copyToClipboard(text);
1170
- ```
1171
-
1172
- #### Cluster Utilities
1173
-
1174
- ```typescript
1175
- import {
1176
- getClusterRpcUrl,
1177
- getClusterExplorerUrl,
1178
- getTransactionUrl,
1179
- getAddressUrl,
1180
- isMainnetCluster,
1181
- isDevnetCluster,
1182
- } from '@solana/connector';
1183
-
1184
- const rpcUrl = getClusterRpcUrl(cluster);
1185
- const explorerUrl = getClusterExplorerUrl(cluster);
1186
- const txUrl = getTransactionUrl(cluster, signature);
1187
- const addrUrl = getAddressUrl(cluster, address);
1188
- ```
975
+ ---
1189
976
 
1190
- ### Types
977
+ ## Types
1191
978
 
1192
979
  ```typescript
1193
980
  import type {
1194
981
  // Configuration
1195
982
  ConnectorConfig,
1196
983
  DefaultConfigOptions,
1197
- ExtendedConnectorConfig,
1198
984
  UnifiedConfig,
1199
- MobileWalletAdapterConfig,
1200
985
 
1201
986
  // State & Info
1202
987
  ConnectorState,
1203
988
  ConnectorSnapshot,
1204
989
  WalletInfo,
1205
990
  AccountInfo,
1206
- ConnectorHealth, // NEW!
1207
-
1208
- // Events
1209
- ConnectorEvent, // NEW!
1210
- ConnectorEventListener, // NEW!
1211
-
1212
- // Transaction Signing
1213
- TransactionSigner, // NEW!
1214
- TransactionSignerConfig, // NEW!
1215
- TransactionSignerCapabilities, // NEW!
1216
- SignedTransaction, // NEW!
1217
-
1218
- // Connection Pooling
1219
- ConnectionLike, // NEW!
1220
- ConnectionPoolOptions, // NEW!
1221
- ConnectionPoolStats, // NEW!
1222
-
1223
- // Wallet Adapter Compat
1224
- WalletAdapterCompatible, // NEW!
1225
- WalletAdapterCompatOptions, // NEW!
1226
991
 
1227
992
  // Wallet Standard
1228
993
  Wallet,
@@ -1232,101 +997,17 @@ import type {
1232
997
  SolanaCluster,
1233
998
  SolanaClusterId,
1234
999
 
1235
- // Storage
1236
- StorageAdapter,
1237
-
1238
1000
  // Hook Returns
1239
1001
  UseClusterReturn,
1240
1002
  UseAccountReturn,
1241
1003
  UseWalletInfoReturn,
1242
- UseTransactionSignerReturn, // NEW!
1243
-
1244
- // Errors
1245
- WalletError,
1004
+ UseTransactionSignerReturn,
1005
+ UseKitTransactionSignerReturn,
1246
1006
  } from '@solana/connector';
1247
1007
  ```
1248
1008
 
1249
1009
  ---
1250
1010
 
1251
- ## Performance
1252
-
1253
- ### Bundle Size
1254
-
1255
- | Component | Size (gzipped) | Tree-Shakeable |
1256
- | -------------------- | -------------- | ------------------ |
1257
- | **Base Connector** | ~45KB | ✅ |
1258
- | + Polyfills | +2KB | ❌ (auto-included) |
1259
- | + Transaction Signer | +3KB | ✅ |
1260
- | + Connection Pool | +1.5KB | ✅ |
1261
- | + Debug Panel | +2KB | ✅ (dev-only) |
1262
- | + Event System | +0.5KB | ✅ |
1263
- | + Compat Layer | +2KB | ✅ |
1264
-
1265
- **Total**: ~48-53KB for typical production usage
1266
-
1267
- ### Runtime Performance
1268
-
1269
- - **40-60% fewer re-renders** via optimized state updates
1270
- - **Connection pooling** reduces memory usage and initialization overhead
1271
- - **Automatic tree-shaking** excludes unused features
1272
- - **Debug panel** automatically excluded in production builds
1273
-
1274
- ---
1275
-
1276
- ## Browser Compatibility
1277
-
1278
- Enhanced support for:
1279
-
1280
- - ✅ Chrome/Edge 90+
1281
- - ✅ Firefox 88+
1282
- - ✅ Safari 14+
1283
- - ✅ iOS Safari 14+
1284
- - ✅ Chrome Mobile 90+
1285
- - ✅ Samsung Internet 15+
1286
-
1287
- Automatic polyfills ensure compatibility across all environments.
1288
-
1289
- ---
1290
-
1291
- ## Migration from @solana/wallet-adapter
1292
-
1293
- Using the wallet-adapter compatibility bridge for gradual migration:
1294
-
1295
- ```typescript
1296
- // Before (wallet-adapter)
1297
- import { useWallet } from '@solana/wallet-adapter-react';
1298
-
1299
- const { publicKey, sendTransaction } = useWallet();
1300
- await sendTransaction(tx, connection);
1301
-
1302
- // After (connector-kit)
1303
- import { useTransactionSigner } from '@solana/connector';
1304
-
1305
- const { signer } = useTransactionSigner();
1306
- await signer.signAndSendTransaction(tx);
1307
-
1308
- // Or use compatibility bridge for existing integrations
1309
- import { createWalletAdapterCompat } from '@solana/connector/compat';
1310
-
1311
- const walletAdapter = createWalletAdapterCompat(signer, { disconnect });
1312
- // Pass walletAdapter to existing wallet-adapter code
1313
- ```
1314
-
1315
- ---
1316
-
1317
- ## Examples
1318
-
1319
- Check out the [examples directory](../../examples/react) for:
1320
-
1321
- - **React Example** - Complete wallet connection UI with shadcn/ui
1322
- - **Vite Example** - Lightweight setup with Vite
1323
- - **Transaction Signing** - Full transaction demos
1324
- - **Network Switching** - Cluster/network management
1325
- - **Account Management** - Multi-account support
1326
- - **Mobile Support** - Solana Mobile Wallet Adapter
1327
-
1328
- ---
1329
-
1330
1011
  ## Development
1331
1012
 
1332
1013
  ### Commands
@@ -1353,9 +1034,6 @@ pnpm test
1353
1034
  # Test in watch mode
1354
1035
  pnpm test:watch
1355
1036
 
1356
- # Test with UI
1357
- pnpm test:ui
1358
-
1359
1037
  # Coverage report
1360
1038
  pnpm test:coverage
1361
1039
 
@@ -1363,65 +1041,17 @@ pnpm test:coverage
1363
1041
  pnpm size
1364
1042
  ```
1365
1043
 
1366
- ### Project Structure
1367
-
1368
- ```
1369
- packages/connector/
1370
- ├── src/
1371
- │ ├── lib/
1372
- │ │ ├── core/ # Core functionality
1373
- │ │ │ ├── state-manager.ts
1374
- │ │ │ ├── event-emitter.ts
1375
- │ │ │ └── debug-metrics.ts
1376
- │ │ ├── connection/ # Connection management
1377
- │ │ │ ├── connection-manager.ts
1378
- │ │ │ └── connection-pool.ts
1379
- │ │ ├── transaction/ # Transaction signing
1380
- │ │ │ ├── transaction-signer.ts
1381
- │ │ │ └── signer-factory.ts
1382
- │ │ └── storage/ # Persistence layer
1383
- │ │ └── enhanced-storage.ts
1384
- │ ├── hooks/ # React hooks
1385
- │ │ ├── use-connector.ts
1386
- │ │ ├── use-account.ts
1387
- │ │ ├── use-cluster.ts
1388
- │ │ └── use-transaction-signer.ts
1389
- │ ├── components/ # React components
1390
- │ │ └── debug-panel.tsx
1391
- │ ├── compat/ # Wallet adapter compatibility
1392
- │ │ └── wallet-adapter-compat.ts
1393
- │ ├── __tests__/ # Test utilities
1394
- │ │ ├── mocks/
1395
- │ │ ├── fixtures/
1396
- │ │ └── utils/
1397
- │ └── index.ts # Main exports
1398
- ├── tsconfig.json
1399
- ├── tsup.config.ts
1400
- ├── vitest.config.ts
1401
- └── package.json
1402
- ```
1403
-
1404
- ### Contributing
1405
-
1406
- Contributions are welcome! Please:
1407
-
1408
- 1. Fork the repository
1409
- 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
1410
- 3. Make your changes
1411
- 4. Add tests for new functionality
1412
- 5. Ensure tests pass (`pnpm test`)
1413
- 6. Commit with conventional commits (`feat:`, `fix:`, `docs:`, etc.)
1414
- 7. Push to your fork and submit a pull request
1415
-
1416
- For detailed testing guidelines, see [Testing Guide](src/__tests__/README.md).
1417
-
1418
1044
  ---
1419
1045
 
1420
- ## Community & Support
1046
+ ## Examples
1421
1047
 
1422
- - **Questions?** Ask on [Solana Stack Exchange](https://solana.stackexchange.com/) (use the `connectorkit` tag)
1423
- - **Issues?** Report on [GitHub Issues](https://github.com/your-org/connectorkit/issues)
1424
- - **Discussions?** Join [GitHub Discussions](https://github.com/your-org/connectorkit/discussions)
1048
+ Check out the [examples directory](../../examples/next-js) for complete working examples:
1049
+
1050
+ - **Next.js Example** - Full-featured wallet connection UI with shadcn/ui
1051
+ - **Transaction Signing** - Modern and legacy transaction examples
1052
+ - **Network Switching** - Cluster/network management
1053
+ - **Account Management** - Multi-account support
1054
+ - **Mobile Support** - Solana Mobile Wallet Adapter
1425
1055
 
1426
1056
  ---
1427
1057
 
@@ -1439,22 +1069,6 @@ Compatible with all [Wallet Standard](https://github.com/wallet-standard/wallet-
1439
1069
 
1440
1070
  ---
1441
1071
 
1442
- ## Other Resources
1443
-
1444
- - [ConnectorKit Documentation](https://connectorkit.dev) - Full documentation site
1445
- - [API Reference](#complete-api-reference) - Complete TypeScript API
1446
- - [Examples](../../examples/react) - Working examples
1447
- - [Wallet Standard Spec](https://github.com/wallet-standard/wallet-standard) - Protocol specification
1448
- - [@solana/connector on NPM](https://www.npmjs.com/package/@solana/connector) - Package page
1449
-
1450
- ---
1451
-
1452
- ## Source
1453
-
1454
- - [GitHub Repository](https://github.com/your-org/connectorkit)
1455
- - [Examples Directory](../../examples)
1456
- - [Package Directory](../../packages/connector)
1457
-
1458
- Built with ❤️ for the Solana ecosystem.
1072
+ ## License
1459
1073
 
1460
- Licensed under MIT. See [LICENSE](../../LICENSE) for details.
1074
+ MIT