@solana/connector 0.0.0 → 0.1.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 +1460 -0
- package/dist/chunk-5ZUVZZWU.mjs +180 -0
- package/dist/chunk-5ZUVZZWU.mjs.map +1 -0
- package/dist/chunk-6PBQ5CXV.mjs +635 -0
- package/dist/chunk-6PBQ5CXV.mjs.map +1 -0
- package/dist/chunk-D4JGBIP7.js +314 -0
- package/dist/chunk-D4JGBIP7.js.map +1 -0
- package/dist/chunk-EGYXJT54.mjs +298 -0
- package/dist/chunk-EGYXJT54.mjs.map +1 -0
- package/dist/chunk-P4ZLJI4L.js +706 -0
- package/dist/chunk-P4ZLJI4L.js.map +1 -0
- package/dist/chunk-P5A3XNFF.js +2482 -0
- package/dist/chunk-P5A3XNFF.js.map +1 -0
- package/dist/chunk-SMUUAKC3.js +186 -0
- package/dist/chunk-SMUUAKC3.js.map +1 -0
- package/dist/chunk-TAAXHAV2.mjs +2419 -0
- package/dist/chunk-TAAXHAV2.mjs.map +1 -0
- package/dist/compat.d.mts +47 -0
- package/dist/compat.d.ts +47 -0
- package/dist/compat.js +98 -0
- package/dist/compat.js.map +1 -0
- package/dist/compat.mjs +94 -0
- package/dist/compat.mjs.map +1 -0
- package/dist/headless.d.mts +515 -0
- package/dist/headless.d.ts +515 -0
- package/dist/headless.js +445 -0
- package/dist/headless.js.map +1 -0
- package/dist/headless.mjs +4 -0
- package/dist/headless.mjs.map +1 -0
- package/dist/index.d.mts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +502 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +5 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react.d.mts +496 -0
- package/dist/react.d.ts +496 -0
- package/dist/react.js +65 -0
- package/dist/react.js.map +1 -0
- package/dist/react.mjs +4 -0
- package/dist/react.mjs.map +1 -0
- package/dist/transaction-signer-D3csM_Mf.d.mts +199 -0
- package/dist/transaction-signer-D3csM_Mf.d.ts +199 -0
- package/dist/wallet-standard-shim-C1tisl9S.d.ts +926 -0
- package/dist/wallet-standard-shim-Cg0GVGwu.d.mts +926 -0
- package/package.json +93 -10
- package/index.js +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,1460 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: @solana/connector
|
|
3
|
+
description: Production-ready wallet connector for Solana applications
|
|
4
|
+
---
|
|
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.
|
|
7
|
+
|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
### Why ConnectorKit?
|
|
14
|
+
|
|
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
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
Install ConnectorKit:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pnpm add @solana/connector
|
|
51
|
+
# or
|
|
52
|
+
npm install @solana/connector
|
|
53
|
+
# or
|
|
54
|
+
yarn add @solana/connector
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Basic usage:
|
|
58
|
+
|
|
59
|
+
```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
|
+
};
|
|
105
|
+
|
|
106
|
+
return <button onClick={handleSend} disabled={!ready}>Send</button>;
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
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:
|
|
175
|
+
|
|
176
|
+
```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
|
|
190
|
+
|
|
191
|
+
**[→ Headless Guide](#headless-client-vue-svelte-vanilla-js)** - Use without React
|
|
192
|
+
|
|
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
|
+
```
|
|
216
|
+
|
|
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
|
+
```
|
|
238
|
+
|
|
239
|
+
Run tests in watch mode:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
pnpm test:watch
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Generate coverage report:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
pnpm test:coverage
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Core Hooks
|
|
254
|
+
|
|
255
|
+
### `useConnector()`
|
|
256
|
+
|
|
257
|
+
Main hook for wallet connection and state.
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import { useConnector } from '@solana/connector';
|
|
261
|
+
|
|
262
|
+
function Component() {
|
|
263
|
+
const {
|
|
264
|
+
// State
|
|
265
|
+
wallets, // WalletInfo[] - All available wallets
|
|
266
|
+
selectedWallet, // Wallet | null - Currently connected wallet
|
|
267
|
+
accounts, // AccountInfo[] - Connected accounts
|
|
268
|
+
connected, // boolean - Connection status
|
|
269
|
+
connecting, // boolean - Connecting in progress
|
|
270
|
+
|
|
271
|
+
// Actions
|
|
272
|
+
select, // (walletName: string) => Promise<void>
|
|
273
|
+
disconnect, // () => Promise<void>
|
|
274
|
+
} = useConnector();
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### `useAccount()`
|
|
279
|
+
|
|
280
|
+
Hook for working with the connected account.
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
import { useAccount } from '@solana/connector';
|
|
284
|
+
|
|
285
|
+
function Component() {
|
|
286
|
+
const {
|
|
287
|
+
address, // string | null - Full wallet address
|
|
288
|
+
formatted, // string - Shortened address (e.g., "5Gv8...x3kF")
|
|
289
|
+
copy, // () => Promise<boolean> - Copy address to clipboard
|
|
290
|
+
copied, // boolean - True for 2s after copying
|
|
291
|
+
connected, // boolean - Connection status
|
|
292
|
+
accounts, // AccountInfo[] - All accounts
|
|
293
|
+
selectAccount, // (address: string) => Promise<void>
|
|
294
|
+
} = useAccount();
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### `useCluster()`
|
|
299
|
+
|
|
300
|
+
Hook for managing Solana network/cluster.
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
import { useCluster } from '@solana/connector';
|
|
304
|
+
|
|
305
|
+
function Component() {
|
|
306
|
+
const {
|
|
307
|
+
cluster, // SolanaCluster | null - Active cluster
|
|
308
|
+
clusters, // SolanaCluster[] - Available clusters
|
|
309
|
+
setCluster, // (id: SolanaClusterId) => Promise<void>
|
|
310
|
+
isMainnet, // boolean - Convenience flags
|
|
311
|
+
isDevnet, // boolean
|
|
312
|
+
rpcUrl, // string - RPC endpoint URL
|
|
313
|
+
explorerUrl, // string - Solana Explorer base URL
|
|
314
|
+
} = useCluster();
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Production Features
|
|
321
|
+
|
|
322
|
+
### Transaction Signer
|
|
323
|
+
|
|
324
|
+
Clean, unified interface for transaction signing operations.
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
import { useTransactionSigner } from '@solana/connector';
|
|
328
|
+
|
|
329
|
+
function SendTx() {
|
|
330
|
+
const { signer, ready, capabilities } = useTransactionSigner();
|
|
331
|
+
|
|
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);
|
|
337
|
+
|
|
338
|
+
const handleSend = async () => {
|
|
339
|
+
if (!signer) return;
|
|
340
|
+
|
|
341
|
+
try {
|
|
342
|
+
// Sign and send a transaction
|
|
343
|
+
const signature = await signer.signAndSendTransaction(transaction);
|
|
344
|
+
console.log('Success:', signature);
|
|
345
|
+
|
|
346
|
+
// Or just sign without sending
|
|
347
|
+
const signed = await signer.signTransaction(transaction);
|
|
348
|
+
|
|
349
|
+
// Or sign multiple transactions
|
|
350
|
+
const signedBatch = await signer.signAllTransactions([tx1, tx2, tx3]);
|
|
351
|
+
|
|
352
|
+
// Or sign and send multiple
|
|
353
|
+
const signatures = await signer.signAndSendTransactions([tx1, tx2]);
|
|
354
|
+
|
|
355
|
+
} catch (error) {
|
|
356
|
+
if (error instanceof TransactionSignerError) {
|
|
357
|
+
console.error('Signing error:', error.code, error.message);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
return (
|
|
363
|
+
<button onClick={handleSend} disabled={!ready}>
|
|
364
|
+
Send Transaction
|
|
365
|
+
</button>
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
**Error Handling**:
|
|
371
|
+
|
|
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
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Event System
|
|
398
|
+
|
|
399
|
+
Track all connector lifecycle events for analytics and monitoring.
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
import { useConnectorClient } from '@solana/connector';
|
|
403
|
+
|
|
404
|
+
function AnalyticsTracker() {
|
|
405
|
+
const client = useConnectorClient();
|
|
406
|
+
|
|
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
|
+
});
|
|
439
|
+
|
|
440
|
+
return unsubscribe;
|
|
441
|
+
}, [client]);
|
|
442
|
+
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
**Available Events**:
|
|
448
|
+
|
|
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
|
|
458
|
+
|
|
459
|
+
### Debug Panel
|
|
460
|
+
|
|
461
|
+
Floating development panel for instant state visibility.
|
|
462
|
+
|
|
463
|
+
```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
|
+
);
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
**Features**:
|
|
478
|
+
|
|
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
|
|
486
|
+
|
|
487
|
+
**Custom positioning**:
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
<ConnectorDebugPanel
|
|
491
|
+
position="top-left" // 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
|
|
492
|
+
defaultOpen={true}
|
|
493
|
+
zIndex={10000}
|
|
494
|
+
/>
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Connection Pooling
|
|
498
|
+
|
|
499
|
+
Reusable RPC connections for better performance.
|
|
500
|
+
|
|
501
|
+
```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
|
+
},
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
// Get or create connection for a cluster
|
|
516
|
+
const connection = pool.get(currentCluster);
|
|
517
|
+
const balance = await connection.getBalance(publicKey);
|
|
518
|
+
|
|
519
|
+
// Clear specific connection when settings change
|
|
520
|
+
pool.clear('solana:mainnet');
|
|
521
|
+
|
|
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}%`);
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
**Global pool** (simpler):
|
|
529
|
+
|
|
530
|
+
```typescript
|
|
531
|
+
import { getConnectionPool } from '@solana/connector/headless';
|
|
532
|
+
|
|
533
|
+
const pool = getConnectionPool();
|
|
534
|
+
const connection = pool.get(cluster);
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### Health Checks
|
|
538
|
+
|
|
539
|
+
Comprehensive diagnostics for debugging and monitoring.
|
|
540
|
+
|
|
541
|
+
```typescript
|
|
542
|
+
import { useConnectorClient } from '@solana/connector';
|
|
543
|
+
|
|
544
|
+
function HealthMonitor() {
|
|
545
|
+
const client = useConnectorClient();
|
|
546
|
+
|
|
547
|
+
if (!client) return null;
|
|
548
|
+
|
|
549
|
+
const health = client.getHealth();
|
|
550
|
+
|
|
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>
|
|
558
|
+
|
|
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
|
+
}
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
### Wallet Adapter Compatibility
|
|
570
|
+
|
|
571
|
+
Drop-in replacement for libraries expecting @solana/wallet-adapter.
|
|
572
|
+
|
|
573
|
+
```typescript
|
|
574
|
+
import { useTransactionSigner, useConnector } from '@solana/connector';
|
|
575
|
+
import { createWalletAdapterCompat } from '@solana/connector/compat';
|
|
576
|
+
|
|
577
|
+
function JupiterIntegration() {
|
|
578
|
+
const { signer } = useTransactionSigner();
|
|
579
|
+
const { disconnect } = useConnector();
|
|
580
|
+
|
|
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);
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
// Use with Jupiter, Serum, or any wallet-adapter library
|
|
592
|
+
return <JupiterTerminal wallet={walletAdapter} />;
|
|
593
|
+
}
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
**Compatible with**:
|
|
597
|
+
|
|
598
|
+
- Jupiter Aggregator
|
|
599
|
+
- Serum DEX
|
|
600
|
+
- Raydium
|
|
601
|
+
- Marinade Finance
|
|
602
|
+
- Any library expecting @solana/wallet-adapter
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
## Configuration
|
|
607
|
+
|
|
608
|
+
### Basic Configuration
|
|
609
|
+
|
|
610
|
+
```typescript
|
|
611
|
+
import { getDefaultConfig } from '@solana/connector';
|
|
612
|
+
|
|
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
|
|
619
|
+
|
|
620
|
+
// NEW: Custom error handler
|
|
621
|
+
onError: (error, errorInfo) => {
|
|
622
|
+
console.error('Connector error:', error);
|
|
623
|
+
errorTracker.captureException(error, errorInfo);
|
|
624
|
+
},
|
|
625
|
+
});
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Network Selection
|
|
629
|
+
|
|
630
|
+
```typescript
|
|
631
|
+
const config = getDefaultConfig({
|
|
632
|
+
appName: 'My App',
|
|
633
|
+
network: 'devnet', // 'mainnet-beta' | 'devnet' | 'testnet' | 'localnet'
|
|
634
|
+
});
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
### Custom Clusters
|
|
638
|
+
|
|
639
|
+
```typescript
|
|
640
|
+
import { getDefaultConfig, createSolanaMainnet } from '@solana/connector';
|
|
641
|
+
|
|
642
|
+
const config = getDefaultConfig({
|
|
643
|
+
appName: 'My App',
|
|
644
|
+
clusters: [
|
|
645
|
+
createSolanaMainnet({
|
|
646
|
+
endpoint: 'https://my-custom-rpc.com',
|
|
647
|
+
}),
|
|
648
|
+
],
|
|
649
|
+
customClusters: [
|
|
650
|
+
// Add additional custom clusters
|
|
651
|
+
],
|
|
652
|
+
});
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
### Mobile Wallet Adapter
|
|
656
|
+
|
|
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
|
+
```
|
|
671
|
+
|
|
672
|
+
---
|
|
673
|
+
|
|
674
|
+
## Advanced Usage
|
|
675
|
+
|
|
676
|
+
### Headless Client (Vue, Svelte, Vanilla JS)
|
|
677
|
+
|
|
678
|
+
Use `ConnectorClient` for non-React frameworks.
|
|
679
|
+
|
|
680
|
+
```typescript
|
|
681
|
+
import { ConnectorClient, getDefaultConfig } from '@solana/connector/headless';
|
|
682
|
+
|
|
683
|
+
// Create client
|
|
684
|
+
const client = new ConnectorClient(getDefaultConfig({ appName: 'My App' }));
|
|
685
|
+
|
|
686
|
+
// Get state
|
|
687
|
+
const state = client.getSnapshot();
|
|
688
|
+
console.log('Wallets:', state.wallets);
|
|
689
|
+
|
|
690
|
+
// Connect
|
|
691
|
+
await client.select('Phantom');
|
|
692
|
+
|
|
693
|
+
// Subscribe to changes
|
|
694
|
+
const unsubscribe = client.subscribe(state => {
|
|
695
|
+
console.log('State updated:', state);
|
|
696
|
+
});
|
|
697
|
+
|
|
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
|
+
// Disconnect
|
|
708
|
+
await client.disconnect();
|
|
709
|
+
|
|
710
|
+
// Cleanup
|
|
711
|
+
client.destroy();
|
|
712
|
+
```
|
|
713
|
+
|
|
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
|
+
```
|
|
746
|
+
|
|
747
|
+
### Custom Storage
|
|
748
|
+
|
|
749
|
+
**Most users don't need to configure storage** - it works automatically with validation, error handling, and SSR fallback.
|
|
750
|
+
|
|
751
|
+
Only customize for:
|
|
752
|
+
|
|
753
|
+
- React Native (custom storage backend)
|
|
754
|
+
- Additional validation rules
|
|
755
|
+
- Custom error tracking
|
|
756
|
+
|
|
757
|
+
```typescript
|
|
758
|
+
import { getDefaultConfig, createEnhancedStorageWallet, EnhancedStorageAdapter } from '@solana/connector';
|
|
759
|
+
|
|
760
|
+
const config = getDefaultConfig({
|
|
761
|
+
appName: 'My App',
|
|
762
|
+
|
|
763
|
+
storage: {
|
|
764
|
+
wallet: new EnhancedStorageAdapter(
|
|
765
|
+
createEnhancedStorageWallet({
|
|
766
|
+
validator: walletName => {
|
|
767
|
+
// Custom validation
|
|
768
|
+
return walletName !== null && walletName.length > 0;
|
|
769
|
+
},
|
|
770
|
+
onError: error => {
|
|
771
|
+
Sentry.captureException(error);
|
|
772
|
+
},
|
|
773
|
+
}),
|
|
774
|
+
),
|
|
775
|
+
// account and cluster use defaults if not specified
|
|
776
|
+
},
|
|
777
|
+
});
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
---
|
|
781
|
+
|
|
782
|
+
## Package Exports
|
|
783
|
+
|
|
784
|
+
### Main Export
|
|
785
|
+
|
|
786
|
+
```typescript
|
|
787
|
+
// Full library - includes React and headless
|
|
788
|
+
import { ConnectorProvider, useConnector } from '@solana/connector';
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
### Headless Export (Framework Agnostic)
|
|
792
|
+
|
|
793
|
+
```typescript
|
|
794
|
+
// Headless core only - no React
|
|
795
|
+
import { ConnectorClient, getDefaultConfig } from '@solana/connector/headless';
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
### React Export
|
|
799
|
+
|
|
800
|
+
```typescript
|
|
801
|
+
// React-specific exports only
|
|
802
|
+
import { useConnector, useAccount } from '@solana/connector/react';
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
### Compatibility Layer (NEW!)
|
|
806
|
+
|
|
807
|
+
```typescript
|
|
808
|
+
// Wallet adapter compatibility bridge
|
|
809
|
+
import { createWalletAdapterCompat } from '@solana/connector/compat';
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
---
|
|
813
|
+
|
|
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
|
|
950
|
+
|
|
951
|
+
All new features and bug fixes should include tests:
|
|
952
|
+
|
|
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
|
|
963
|
+
|
|
964
|
+
### Configuration Functions
|
|
965
|
+
|
|
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
|
+
```
|
|
1145
|
+
|
|
1146
|
+
### Utility Functions
|
|
1147
|
+
|
|
1148
|
+
#### Formatting
|
|
1149
|
+
|
|
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
|
+
```
|
|
1189
|
+
|
|
1190
|
+
### Types
|
|
1191
|
+
|
|
1192
|
+
```typescript
|
|
1193
|
+
import type {
|
|
1194
|
+
// Configuration
|
|
1195
|
+
ConnectorConfig,
|
|
1196
|
+
DefaultConfigOptions,
|
|
1197
|
+
ExtendedConnectorConfig,
|
|
1198
|
+
UnifiedConfig,
|
|
1199
|
+
MobileWalletAdapterConfig,
|
|
1200
|
+
|
|
1201
|
+
// State & Info
|
|
1202
|
+
ConnectorState,
|
|
1203
|
+
ConnectorSnapshot,
|
|
1204
|
+
WalletInfo,
|
|
1205
|
+
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
|
+
|
|
1227
|
+
// Wallet Standard
|
|
1228
|
+
Wallet,
|
|
1229
|
+
WalletAccount,
|
|
1230
|
+
|
|
1231
|
+
// Clusters
|
|
1232
|
+
SolanaCluster,
|
|
1233
|
+
SolanaClusterId,
|
|
1234
|
+
|
|
1235
|
+
// Storage
|
|
1236
|
+
StorageAdapter,
|
|
1237
|
+
|
|
1238
|
+
// Hook Returns
|
|
1239
|
+
UseClusterReturn,
|
|
1240
|
+
UseAccountReturn,
|
|
1241
|
+
UseWalletInfoReturn,
|
|
1242
|
+
UseTransactionSignerReturn, // NEW!
|
|
1243
|
+
|
|
1244
|
+
// Errors
|
|
1245
|
+
WalletError,
|
|
1246
|
+
} from '@solana/connector';
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
---
|
|
1250
|
+
|
|
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
|
+
## Development
|
|
1331
|
+
|
|
1332
|
+
### Commands
|
|
1333
|
+
|
|
1334
|
+
```bash
|
|
1335
|
+
# Install dependencies
|
|
1336
|
+
pnpm install
|
|
1337
|
+
|
|
1338
|
+
# Build package
|
|
1339
|
+
pnpm build
|
|
1340
|
+
|
|
1341
|
+
# Development mode with watch
|
|
1342
|
+
pnpm dev
|
|
1343
|
+
|
|
1344
|
+
# Type checking
|
|
1345
|
+
pnpm type-check
|
|
1346
|
+
|
|
1347
|
+
# Linting
|
|
1348
|
+
pnpm lint
|
|
1349
|
+
|
|
1350
|
+
# Run tests
|
|
1351
|
+
pnpm test
|
|
1352
|
+
|
|
1353
|
+
# Test in watch mode
|
|
1354
|
+
pnpm test:watch
|
|
1355
|
+
|
|
1356
|
+
# Test with UI
|
|
1357
|
+
pnpm test:ui
|
|
1358
|
+
|
|
1359
|
+
# Coverage report
|
|
1360
|
+
pnpm test:coverage
|
|
1361
|
+
|
|
1362
|
+
# Check bundle size
|
|
1363
|
+
pnpm size
|
|
1364
|
+
```
|
|
1365
|
+
|
|
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
|
+
---
|
|
1419
|
+
|
|
1420
|
+
## Community & Support
|
|
1421
|
+
|
|
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)
|
|
1425
|
+
|
|
1426
|
+
---
|
|
1427
|
+
|
|
1428
|
+
## Supported Wallets
|
|
1429
|
+
|
|
1430
|
+
Compatible with all [Wallet Standard](https://github.com/wallet-standard/wallet-standard) compliant wallets:
|
|
1431
|
+
|
|
1432
|
+
- **Phantom** - Browser extension and mobile
|
|
1433
|
+
- **Solflare** - Browser extension and mobile
|
|
1434
|
+
- **Backpack** - xNFT and wallet
|
|
1435
|
+
- **Glow** - Browser extension
|
|
1436
|
+
- **Brave Wallet** - Built-in browser wallet
|
|
1437
|
+
- **Solana Mobile** - All mobile wallet adapter compatible wallets
|
|
1438
|
+
- **Any Wallet Standard wallet** - Full compatibility
|
|
1439
|
+
|
|
1440
|
+
---
|
|
1441
|
+
|
|
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.
|
|
1459
|
+
|
|
1460
|
+
Licensed under MIT. See [LICENSE](../../LICENSE) for details.
|