@solana/kit-plugin-wallet 0.0.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +401 -0
  3. package/dist/index.browser.cjs +622 -0
  4. package/dist/index.browser.cjs.map +1 -0
  5. package/dist/index.browser.mjs +614 -0
  6. package/dist/index.browser.mjs.map +1 -0
  7. package/dist/index.node.cjs +100 -0
  8. package/dist/index.node.cjs.map +1 -0
  9. package/dist/index.node.mjs +91 -0
  10. package/dist/index.node.mjs.map +1 -0
  11. package/dist/index.react-native.mjs +91 -0
  12. package/dist/index.react-native.mjs.map +1 -0
  13. package/dist/react/index.browser.cjs +77 -0
  14. package/dist/react/index.browser.cjs.map +1 -0
  15. package/dist/react/index.browser.mjs +59 -0
  16. package/dist/react/index.browser.mjs.map +1 -0
  17. package/dist/react/index.node.cjs +77 -0
  18. package/dist/react/index.node.cjs.map +1 -0
  19. package/dist/react/index.node.mjs +59 -0
  20. package/dist/react/index.node.mjs.map +1 -0
  21. package/dist/react/index.react-native.mjs +59 -0
  22. package/dist/react/index.react-native.mjs.map +1 -0
  23. package/dist/types/index.d.ts +4 -0
  24. package/dist/types/index.d.ts.map +1 -0
  25. package/dist/types/react/index.d.ts +235 -0
  26. package/dist/types/react/index.d.ts.map +1 -0
  27. package/dist/types/status.d.ts +31 -0
  28. package/dist/types/status.d.ts.map +1 -0
  29. package/dist/types/store.d.ts +16 -0
  30. package/dist/types/store.d.ts.map +1 -0
  31. package/dist/types/types.d.ts +384 -0
  32. package/dist/types/types.d.ts.map +1 -0
  33. package/dist/types/wallet.d.ts +133 -0
  34. package/dist/types/wallet.d.ts.map +1 -0
  35. package/package.json +103 -7
  36. package/src/__typetests__/wallet-typetest.ts +129 -0
  37. package/src/index.ts +3 -0
  38. package/src/react/__typetests__/index.ts +108 -0
  39. package/src/react/index.ts +301 -0
  40. package/src/status.ts +33 -0
  41. package/src/store.ts +990 -0
  42. package/src/types/global.d.ts +6 -0
  43. package/src/types.ts +407 -0
  44. package/src/wallet.ts +218 -0
@@ -0,0 +1,384 @@
1
+ import type { MessageSigner, ReadonlyUint8Array, SignatureBytes, TransactionSigner } from '@solana/kit';
2
+ import type { SolanaChain } from '@solana/wallet-standard-chains';
3
+ import type { SolanaSignInInput, SolanaSignInOutput } from '@solana/wallet-standard-features';
4
+ import type { IdentifierString } from '@wallet-standard/base';
5
+ import type { UiWallet, UiWalletAccount } from '@wallet-standard/ui';
6
+ /**
7
+ * The signer type for a connected wallet account.
8
+ *
9
+ * Always satisfies `TransactionSigner`. Additionally implements `MessageSigner`
10
+ * when the wallet supports `solana:signMessage`.
11
+ */
12
+ export type WalletSigner = TransactionSigner | (MessageSigner & TransactionSigner);
13
+ /**
14
+ * The connection status of the wallet plugin.
15
+ *
16
+ * - `pending` — not yet initialized. Initial state on both server and browser.
17
+ * On the server — and in React Native, which is treated the same way — this
18
+ * state is permanent. In the browser it resolves to `disconnected` or
19
+ * `reconnecting` once the storage check completes.
20
+ * - `disconnected` — initialized, no wallet connected.
21
+ * - `connecting` — a user-initiated connection request is in progress. When
22
+ * connecting to a different wallet while one is already connected, the
23
+ * existing connection is preserved until the new one succeeds — so
24
+ * {@link WalletState.connected} can be non-null during this state, and a
25
+ * failed attempt reverts to the previous connection.
26
+ * - `connected` — a wallet is connected.
27
+ * - `disconnecting` — a user-initiated disconnection request is in progress.
28
+ * - `reconnecting` — auto-connect in progress (connecting to persisted wallet).
29
+ */
30
+ export type WalletStatus = 'connected' | 'connecting' | 'disconnected' | 'disconnecting' | 'pending' | 'reconnecting';
31
+ /**
32
+ * A snapshot of the wallet plugin state at a point in time.
33
+ *
34
+ * Returned by {@link WalletNamespace.getState}. The same object reference
35
+ * is returned on successive calls as long as nothing has changed — a new
36
+ * object is only created when a field actually changes. This ensures
37
+ * `useSyncExternalStore` only triggers re-renders on meaningful state changes.
38
+ *
39
+ * @see {@link WalletNamespace.getState}
40
+ */
41
+ export type WalletState = {
42
+ /**
43
+ * The active connection, or `null` when disconnected.
44
+ *
45
+ * `signer` is `null` for read-only / watch-only wallets that do not
46
+ * support any signing feature.
47
+ *
48
+ * Independent of {@link status}: when {@link connect} or {@link signIn} is
49
+ * called for a different wallet while one is already connected, `connected`
50
+ * keeps describing the existing connection while `status` is `'connecting'`,
51
+ * and a failed attempt leaves it in place.
52
+ */
53
+ readonly connected: {
54
+ readonly account: UiWalletAccount;
55
+ /** The signer for the active account, or `null` for read-only wallets. */
56
+ readonly signer: WalletSigner | null;
57
+ readonly wallet: UiWallet;
58
+ } | null;
59
+ /** The current connection status. */
60
+ readonly status: WalletStatus;
61
+ /** All discovered wallets matching the configured chain and filter. */
62
+ readonly wallets: readonly UiWallet[];
63
+ };
64
+ /**
65
+ * Options accepted by each async wallet action.
66
+ *
67
+ * Currently only carries an `abortSignal`, but is kept as an object for
68
+ * consistency with the rest of the Kit ecosystem and to allow future
69
+ * additions without breaking the call-site shape.
70
+ *
71
+ * @see {@link WalletNamespace.connect}
72
+ * @see {@link WalletNamespace.disconnect}
73
+ * @see {@link WalletNamespace.signMessage}
74
+ * @see {@link WalletNamespace.signIn}
75
+ */
76
+ export type WalletActionOptions = {
77
+ /**
78
+ * An optional `AbortSignal` used to cancel the operation.
79
+ *
80
+ * Cancellation is pre-call only: the plugin calls
81
+ * `abortSignal.throwIfAborted()` at the start of each action and bails
82
+ * out before invoking the wallet. Once the underlying wallet-standard
83
+ * call has been dispatched, its result is returned even if the signal
84
+ * is aborted mid-flight — the wallet's side effect (an approved
85
+ * signature, a live connection, a broadcast transaction) is the source
86
+ * of truth, and throwing here would discard real user work without
87
+ * undoing what the wallet already did.
88
+ */
89
+ abortSignal?: AbortSignal;
90
+ };
91
+ /**
92
+ * A pluggable storage adapter for persisting the selected wallet account.
93
+ *
94
+ * Follows the Web Storage API shape (`getItem`/`setItem`/`removeItem`).
95
+ * `localStorage` and `sessionStorage` satisfy this interface directly.
96
+ * Async backends (IndexedDB, encrypted storage) may return `Promise`s.
97
+ *
98
+ * Writes are fire-and-forget: the plugin does not await `setItem`/`removeItem`
99
+ * and swallows any rejection (the live wallet connection is the source of
100
+ * truth, so a failed persist is non-fatal). A resolved action therefore does
101
+ * not guarantee the write has landed, and rapid successive writes are not
102
+ * ordered. This is intentional — persistence only records which account to
103
+ * silently reconnect to on the next load.
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * // Use sessionStorage
108
+ * walletSigner({ chain: 'solana:mainnet', storage: sessionStorage });
109
+ *
110
+ * // Custom async adapter
111
+ * walletSigner({
112
+ * chain: 'solana:mainnet',
113
+ * storage: {
114
+ * getItem: (key) => myStore.get(key),
115
+ * setItem: (key, value) => myStore.set(key, value),
116
+ * removeItem: (key) => myStore.delete(key),
117
+ * },
118
+ * });
119
+ * ```
120
+ */
121
+ export type WalletStorage = {
122
+ getItem(key: string): Promise<string | null> | string | null;
123
+ removeItem(key: string): Promise<void> | void;
124
+ setItem(key: string, value: string): Promise<void> | void;
125
+ };
126
+ /**
127
+ * Configuration for the wallet plugins.
128
+ *
129
+ * @see {@link walletSigner}
130
+ * @see {@link walletIdentity}
131
+ * @see {@link walletPayer}
132
+ * @see {@link walletWithoutSigner}
133
+ */
134
+ export type WalletPluginConfig = {
135
+ /**
136
+ * Whether to attempt silent reconnection on startup using the persisted
137
+ * wallet account from `storage`.
138
+ *
139
+ * Has no effect if `storage` is `null`.
140
+ *
141
+ * @default true
142
+ */
143
+ autoConnect?: boolean;
144
+ /**
145
+ * The chain this client targets (e.g. `'solana:mainnet'`).
146
+ *
147
+ * Accepts any {@link SolanaChain} (with literal autocomplete) and, as an
148
+ * escape hatch, any wallet-standard {@link IdentifierString} shape
149
+ * (`${string}:${string}`) for custom chains or non-Solana L2s. The plugin's
150
+ * runtime behavior is chain-agnostic — it passes the identifier to
151
+ * wallet-standard discovery (`uiWallet.chains.includes(chain)`) and to
152
+ * `createSignerFromWalletAccount`. Wallets that don't advertise the chain
153
+ * are filtered out, and accounts that can't produce a signer for the chain
154
+ * resolve to `signer: null` (matching the read-only-wallet contract).
155
+ *
156
+ * One client = one chain. To switch networks, create a separate client
157
+ * with a different chain and RPC endpoint.
158
+ */
159
+ chain: SolanaChain | (IdentifierString & {});
160
+ /**
161
+ * Optional filter function for wallet discovery. Called for each wallet
162
+ * that supports the configured chain and `standard:connect`. Return `true`
163
+ * to include the wallet, `false` to exclude it.
164
+ *
165
+ * @example
166
+ * ```ts
167
+ * // Require signAndSendTransaction
168
+ * filter: (w) => w.features.includes('solana:signAndSendTransaction')
169
+ *
170
+ * // Whitelist specific wallets
171
+ * filter: (w) => ['SomeWallet', 'SomeOtherWallet'].includes(w.name)
172
+ * ```
173
+ */
174
+ filter?: (wallet: UiWallet) => boolean;
175
+ /**
176
+ * Storage adapter for persisting the selected wallet account across page
177
+ * loads. Pass `null` to disable persistence entirely.
178
+ *
179
+ * When omitted in a browser environment, `localStorage` is used by default.
180
+ * On the server, storage is always skipped regardless of this option.
181
+ *
182
+ * @default localStorage (in browser)
183
+ * @see {@link WalletStorage}
184
+ */
185
+ storage?: WalletStorage | null;
186
+ /**
187
+ * Storage key used for persistence.
188
+ *
189
+ * @default 'kit-wallet'
190
+ */
191
+ storageKey?: string;
192
+ };
193
+ /**
194
+ * The `wallet` namespace exposed on the client as `client.wallet`.
195
+ *
196
+ * All wallet state is accessed via {@link getState}. Use {@link subscribe}
197
+ * to be notified of changes and integrate with framework primitives such as
198
+ * React's `useSyncExternalStore`.
199
+ *
200
+ * @see {@link ClientWithWallet}
201
+ */
202
+ export type WalletNamespace = {
203
+ /**
204
+ * Connect to a wallet. Calls `standard:connect`, then selects the first
205
+ * newly authorized account (or the first account if reconnecting). Creates
206
+ * and caches a signer for the active account.
207
+ *
208
+ * Resolving means the wallet is connected; any failure rejects. If a wallet
209
+ * is already connected, it stays connected until the new one is established:
210
+ * a failed attempt — a rejected prompt, no authorized accounts, or the
211
+ * wallet becoming unavailable — leaves the previous connection in place
212
+ * rather than disconnecting it.
213
+ *
214
+ * @returns All accounts from the wallet after connection.
215
+ * @throws The wallet's rejection error if the user declines the prompt.
216
+ * @throws `SolanaError(SOLANA_ERROR__WALLET__NOT_CONNECTED)` if the wallet
217
+ * authorizes no accounts, or unregisters (or drops a required
218
+ * feature/chain) while its connect prompt is open. Any previously
219
+ * connected wallet is left in place.
220
+ * @throws `DOMException` with `name: 'AbortError'` if a newer `connect` or
221
+ * `signIn` is started before this call resolves. The newer request wins
222
+ * and owns the resulting connection; this superseded call rejects so it
223
+ * can be ignored like any other aborted operation (e.g. an accidental
224
+ * double-click still connects — only the orphaned first promise rejects).
225
+ * @throws `options.abortSignal.reason` if the signal is already aborted
226
+ * when the action is called. Aborts after the wallet call has been
227
+ * dispatched do not take effect.
228
+ */
229
+ connect: (wallet: UiWallet, options?: WalletActionOptions) => Promise<readonly UiWalletAccount[]>;
230
+ /**
231
+ * Disconnect a wallet. Calls `standard:disconnect` if supported.
232
+ *
233
+ * `wallet` defaults to the active wallet. Passing a non-active, currently
234
+ * authorized wallet deauthorizes it (calling `standard:disconnect` if
235
+ * supported) while leaving the active connection untouched. A `wallet`
236
+ * that doesn't support `standard:disconnect`, or one that is already
237
+ * unauthorized/unregistered, is a forgiving no-op.
238
+ *
239
+ * @throws `options.abortSignal.reason` if the signal is already aborted
240
+ * when the action is called. Aborts after the wallet call has been
241
+ * dispatched do not take effect.
242
+ */
243
+ disconnect: (wallet?: UiWallet, options?: WalletActionOptions) => Promise<void>;
244
+ /**
245
+ * Get the current wallet state. Referentially stable — a new object is
246
+ * only created when a field actually changes, so React's
247
+ * `useSyncExternalStore` skips re-renders when nothing meaningful changed.
248
+ *
249
+ * @see {@link WalletState}
250
+ */
251
+ getState: () => WalletState;
252
+ /**
253
+ * Select an account, creating and caching a new signer for it.
254
+ *
255
+ * The account may belong to any currently authorized wallet, not only the
256
+ * active one. When it belongs to a different authorized wallet, the active
257
+ * connection switches to that wallet synchronously (no prompt), leaving the
258
+ * previously active wallet authorized. If the store is currently 'disconnected',
259
+ * this allows transitioning to 'connected' synchronously.
260
+ *
261
+ * @throws `SolanaError(SOLANA_ERROR__WALLET__ACCOUNT_NOT_AVAILABLE)` if the
262
+ * account's handle cannot be resolved to a currently authorized wallet, or
263
+ * the account is not among that wallet's accounts.
264
+ * @throws `SolanaError(SOLANA_ERROR__WALLET__NOT_CONNECTED)` if the account's
265
+ * wallet is currently disconnecting.
266
+ */
267
+ selectAccount: (account: UiWalletAccount) => void;
268
+ /**
269
+ * Sign In With Solana (SIWS-as-connect).
270
+ *
271
+ * Connects the wallet, calls `solana:signIn`, sets the returned account as
272
+ * active, and creates a signer. Resolving means the client is in the same
273
+ * state as if {@link connect} had been called; any failure to connect
274
+ * rejects rather than resolving while disconnected.
275
+ *
276
+ * All fields on `SolanaSignInInput` are optional — pass `{}` if no sign-in
277
+ * customization is needed.
278
+ *
279
+ * To sign in with the already-connected wallet, pass
280
+ * `getState().connected.wallet`.
281
+ *
282
+ * Like {@link connect}, a failed sign-in to a different wallet rejects and
283
+ * leaves any existing connection in place rather than disconnecting it.
284
+ *
285
+ * @returns The wallet's sign-in output, once the connection is established.
286
+ * @throws `WalletStandardError(WALLET_STANDARD_ERROR__FEATURES__WALLET_ACCOUNT_FEATURE_UNIMPLEMENTED)`
287
+ * if the wallet does not support `solana:signIn`.
288
+ * @throws `SolanaError(SOLANA_ERROR__WALLET__NOT_CONNECTED)` if the wallet
289
+ * unregisters (or drops a required feature/chain) while its sign-in prompt
290
+ * is open, or signs in with an account it does not expose. Any previously
291
+ * connected wallet is left in place.
292
+ * @throws `DOMException` with `name: 'AbortError'` if a newer `connect` or
293
+ * `signIn` is started before this call resolves. The newer request wins
294
+ * and owns the resulting connection; this superseded call rejects so it
295
+ * can be ignored like any other aborted operation.
296
+ * @throws `options.abortSignal.reason` if the signal is already aborted
297
+ * when the action is called. Aborts after the wallet call has been
298
+ * dispatched do not take effect.
299
+ */
300
+ signIn: (wallet: UiWallet, input: SolanaSignInInput, options?: WalletActionOptions) => Promise<SolanaSignInOutput>;
301
+ /**
302
+ * Sign an arbitrary message with the connected account.
303
+ *
304
+ * Calls the wallet's `solana:signMessage` feature directly (does not go
305
+ * through the cached signer), so message signing works even for wallets
306
+ * that don't support transaction signing.
307
+ *
308
+ * @throws `SolanaError(SOLANA_ERROR__WALLET__NOT_CONNECTED)` if no wallet is connected.
309
+ * @throws `WalletStandardError(WALLET_STANDARD_ERROR__FEATURES__WALLET_ACCOUNT_FEATURE_UNIMPLEMENTED)`
310
+ * if the wallet does not support `solana:signMessage`.
311
+ * @throws `options.abortSignal.reason` if the signal is already aborted
312
+ * when the action is called. Aborts after the wallet call has been
313
+ * dispatched do not take effect.
314
+ */
315
+ signMessage: (message: ReadonlyUint8Array, options?: WalletActionOptions) => Promise<SignatureBytes>;
316
+ /**
317
+ * Subscribe to any wallet state change. Compatible with React's
318
+ * `useSyncExternalStore` and similar framework primitives.
319
+ *
320
+ * @returns An unsubscribe function.
321
+ *
322
+ * @example
323
+ * ```ts
324
+ * const state = useSyncExternalStore(client.wallet.subscribe, client.wallet.getState);
325
+ * ```
326
+ */
327
+ subscribe: (listener: () => void) => () => void;
328
+ /**
329
+ * **Advanced.** Resolves once the initial connection attempt has settled —
330
+ * i.e. {@link getState}'s `status` is no longer `'pending'` or
331
+ * `'reconnecting'`.
332
+ *
333
+ * You only need this if your app **rebuilds the client at runtime** (for
334
+ * example, to change chain). Each freshly built client runs a silent
335
+ * auto-reconnect that briefly passes through `'pending'`/`'reconnecting'`;
336
+ * awaiting this lets you hold the previous UI until the new client is ready
337
+ * instead of flashing a "reconnecting" state on every swap. Most apps never
338
+ * call it — subscribe to `status` with {@link subscribe} instead.
339
+ *
340
+ * Does **not** wait for user-initiated `connect`/`disconnect`/`signIn`
341
+ * (those pass through `'connecting'`/`'disconnecting'`, which count as
342
+ * ready), so a normal connect never makes this block. While transient it
343
+ * returns the **same** promise reference on every call, so successive
344
+ * awaits during one warm-up share a single settlement.
345
+ *
346
+ * Disposing the client mid-warm-up settles the status to `'disconnected'`,
347
+ * so a pending `whenReady()` resolves rather than hanging. Check
348
+ * {@link getState} after awaiting if you need to distinguish a ready
349
+ * connection from a disposed (or never-connected) client.
350
+ *
351
+ * @returns A promise that resolves with no value once the wallet is past its
352
+ * initial `'pending'`/`'reconnecting'` warm-up. Already resolved when the
353
+ * status is not transient.
354
+ *
355
+ * @example
356
+ * ```ts
357
+ * // On a chain switch, hold the old UI until the rebuilt client is ready:
358
+ * const next = createClient().use(walletSigner({ chain }));
359
+ * await next.wallet.whenReady();
360
+ * setClient(next);
361
+ * ```
362
+ */
363
+ whenReady: () => Promise<void>;
364
+ };
365
+ /**
366
+ * Properties added to the client by the wallet plugins.
367
+ *
368
+ * All wallet state and actions are namespaced under `client.wallet`.
369
+ * Depending on which plugin variant is used, `client.payer` and/or
370
+ * `client.identity` may also be set to the connected wallet's signer.
371
+ * This is not part of Kit plugin-interfaces, as it depends on wallet-standard types
372
+ *
373
+ * @see {@link walletSigner}
374
+ * @see {@link walletPayer}
375
+ * @see {@link walletIdentity}
376
+ * @see {@link walletWithoutSigner}
377
+ * @see {@link WalletNamespace}
378
+ *
379
+ */
380
+ export type ClientWithWallet = {
381
+ /** The wallet namespace — state, actions, and framework integration. */
382
+ readonly wallet: WalletNamespace;
383
+ };
384
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,133 @@
1
+ import { type ClientWithIdentity, type ClientWithPayer, type ClientWithSubscribeToIdentity, type ClientWithSubscribeToPayer } from '@solana/kit';
2
+ import type { ClientWithWallet, WalletPluginConfig } from './types';
3
+ /**
4
+ * A framework-agnostic Kit plugin that manages wallet discovery, connection
5
+ * lifecycle, and signer creation using wallet-standard — and syncs the
6
+ * connected wallet's signer to both `client.payer` and `client.identity`.
7
+ *
8
+ * This is the most common entrypoint for dApps. When a signing-capable
9
+ * wallet is connected, `client.payer` and `client.identity` both return the
10
+ * wallet signer. When disconnected or read-only, accessing either throws.
11
+ *
12
+ * Because the signer is dynamic, both `client.subscribeToPayer` and
13
+ * `client.subscribeToIdentity` are installed so reactive consumers can observe
14
+ * changes (the Kit reactive-capability convention).
15
+ *
16
+ * **SSR-safe.** Can be included in a shared client chain that runs on both
17
+ * server and browser.
18
+ *
19
+ * ```ts
20
+ * const client = createClient()
21
+ * .use(walletSigner({ chain: 'solana:mainnet' }))
22
+ * .use(solanaRpc({ rpcUrl: 'https://api.mainnet-beta.solana.com' }))
23
+ * .use(planAndSendTransactions());
24
+ * ```
25
+ *
26
+ * @param config - Plugin configuration.
27
+ *
28
+ * @see {@link walletPayer}
29
+ * @see {@link walletIdentity}
30
+ * @see {@link walletWithoutSigner}
31
+ * @see {@link WalletPluginConfig}
32
+ */
33
+ export declare function walletSigner(config: WalletPluginConfig): <T extends object & {
34
+ wallet?: never;
35
+ }>(client: T) => Disposable & Omit<T, "identity" | "payer" | "subscribeToIdentity" | "subscribeToPayer" | "wallet"> & ClientWithIdentity & ClientWithPayer & ClientWithSubscribeToIdentity & ClientWithSubscribeToPayer & ClientWithWallet;
36
+ /**
37
+ * A framework-agnostic Kit plugin that manages wallet discovery, connection
38
+ * lifecycle, and signer creation using wallet-standard — and syncs the
39
+ * connected wallet's signer to `client.identity`.
40
+ *
41
+ * Use this when `client.payer` is controlled by a separate `payer()` plugin
42
+ * (e.g. a backend relayer pays fees, but the user's wallet is the identity).
43
+ *
44
+ * Because the signer is dynamic, `client.subscribeToIdentity` is installed so
45
+ * reactive consumers can observe changes (the Kit reactive-capability convention).
46
+ *
47
+ * **SSR-safe.** Can be included in a shared client chain that runs on both
48
+ * server and browser.
49
+ *
50
+ * ```ts
51
+ * const client = createClient()
52
+ * .use(payer(relayerKeypair))
53
+ * .use(walletIdentity({ chain: 'solana:mainnet' }))
54
+ * .use(solanaRpc({ rpcUrl: 'https://api.mainnet-beta.solana.com' }))
55
+ * .use(planAndSendTransactions());
56
+ * ```
57
+ *
58
+ * @param config - Plugin configuration.
59
+ *
60
+ * @see {@link walletSigner}
61
+ * @see {@link walletPayer}
62
+ * @see {@link walletWithoutSigner}
63
+ * @see {@link WalletPluginConfig}
64
+ */
65
+ export declare function walletIdentity(config: WalletPluginConfig): <T extends object & {
66
+ wallet?: never;
67
+ }>(client: T) => Disposable & Omit<T, "identity" | "subscribeToIdentity" | "wallet"> & ClientWithIdentity & ClientWithSubscribeToIdentity & ClientWithWallet;
68
+ /**
69
+ * A framework-agnostic Kit plugin that manages wallet discovery, connection
70
+ * lifecycle, and signer creation using wallet-standard — and syncs the
71
+ * connected wallet's signer to `client.payer`.
72
+ *
73
+ * Use this when you need the wallet as the fee payer but don't need
74
+ * `client.identity`. For most dApps, prefer {@link walletSigner} which
75
+ * sets both.
76
+ *
77
+ * Because the signer is dynamic, `client.subscribeToPayer` is installed so
78
+ * reactive consumers can observe changes (the Kit reactive-capability convention).
79
+ *
80
+ * **SSR-safe.** Can be included in a shared client chain that runs on both
81
+ * server and browser.
82
+ *
83
+ * ```ts
84
+ * const client = createClient()
85
+ * .use(walletPayer({ chain: 'solana:mainnet' }))
86
+ * .use(solanaRpc({ rpcUrl: 'https://api.mainnet-beta.solana.com' }))
87
+ * .use(planAndSendTransactions());
88
+ * ```
89
+ *
90
+ * @param config - Plugin configuration.
91
+ *
92
+ * @see {@link walletSigner}
93
+ * @see {@link walletIdentity}
94
+ * @see {@link walletWithoutSigner}
95
+ * @see {@link WalletPluginConfig}
96
+ */
97
+ export declare function walletPayer(config: WalletPluginConfig): <T extends object & {
98
+ wallet?: never;
99
+ }>(client: T) => Disposable & Omit<T, "payer" | "subscribeToPayer" | "wallet"> & ClientWithPayer & ClientWithSubscribeToPayer & ClientWithWallet;
100
+ /**
101
+ * A framework-agnostic Kit plugin that manages wallet discovery, connection
102
+ * lifecycle, and signer creation using wallet-standard.
103
+ *
104
+ * Adds the `wallet` namespace to the client without setting `client.payer`
105
+ * or `client.identity`. Use this alongside separate `payer()` and/or
106
+ * `identity()` plugins, or when the wallet's signer is used explicitly in
107
+ * instructions. For most dApps, prefer {@link walletSigner} instead.
108
+ *
109
+ * **SSR-safe.** Can be included in a shared client chain that runs on both
110
+ * server and browser.
111
+ *
112
+ * ```ts
113
+ * const client = createClient()
114
+ * .use(payer(backendKeypair))
115
+ * .use(walletWithoutSigner({ chain: 'solana:mainnet' }))
116
+ * .use(solanaRpc({ rpcUrl: 'https://api.mainnet-beta.solana.com' }))
117
+ * .use(planAndSendTransactions());
118
+ *
119
+ * // client.payer is always backendKeypair
120
+ * // client.wallet.getState().connected?.signer for manual use
121
+ * ```
122
+ *
123
+ * @param config - Plugin configuration.
124
+ *
125
+ * @see {@link walletSigner}
126
+ * @see {@link walletPayer}
127
+ * @see {@link walletIdentity}
128
+ * @see {@link WalletPluginConfig}
129
+ */
130
+ export declare function walletWithoutSigner(config: WalletPluginConfig): <T extends object & {
131
+ wallet?: never;
132
+ }>(client: T) => Disposable & Omit<T, "wallet"> & ClientWithWallet;
133
+ //# sourceMappingURL=wallet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet.d.ts","sourceRoot":"","sources":["../../src/wallet.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAMlC,MAAM,aAAa,CAAC;AAGrB,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAkEpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,kBAAkB,IAtD3C,CAAC,SAAS,MAAM,GAAG;IAAE,MAAM,CAAC,EAAE,KAAK,CAAA;CAAE,0OA8DhD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,kBAAkB,IA7F7C,CAAC,SAAS,MAAM,GAAG;IAAE,MAAM,CAAC,EAAE,KAAK,CAAA;CAAE,4JA+FhD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,kBAAkB,IA9H1C,CAAC,SAAS,MAAM,GAAG;IAAE,MAAM,CAAC,EAAE,KAAK,CAAA;CAAE,gJAgIhD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,IAhKlD,CAAC,SAAS,MAAM,GAAG;IAAE,MAAM,CAAC,EAAE,KAAK,CAAA;CAAE,kEAkKhD"}
package/package.json CHANGED
@@ -1,12 +1,108 @@
1
1
  {
2
2
  "name": "@solana/kit-plugin-wallet",
3
- "version": "0.0.0",
4
- "description": "",
5
- "license": "ISC",
6
- "author": "",
3
+ "version": "0.13.0",
4
+ "description": "Wallet connection plugin for Kit clients",
5
+ "keywords": [
6
+ "kit",
7
+ "plugin",
8
+ "signer",
9
+ "solana",
10
+ "wallet",
11
+ "wallet-adapter",
12
+ "wallet-standard"
13
+ ],
14
+ "bugs": {
15
+ "url": "http://github.com/anza-xyz/kit-plugins/issues"
16
+ },
17
+ "license": "MIT",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/anza-xyz/kit-plugins"
21
+ },
22
+ "files": [
23
+ "./dist/types",
24
+ "./dist/index.*",
25
+ "./dist/react/index.*",
26
+ "./src/"
27
+ ],
7
28
  "type": "commonjs",
8
- "main": "index.js",
29
+ "sideEffects": false,
30
+ "main": "./dist/index.node.cjs",
31
+ "module": "./dist/index.node.mjs",
32
+ "browser": {
33
+ "./dist/index.node.cjs": "./dist/index.browser.cjs",
34
+ "./dist/index.node.mjs": "./dist/index.browser.mjs"
35
+ },
36
+ "types": "./dist/types/index.d.ts",
37
+ "react-native": "./dist/index.react-native.mjs",
38
+ "exports": {
39
+ ".": {
40
+ "types": "./dist/types/index.d.ts",
41
+ "react-native": "./dist/index.react-native.mjs",
42
+ "browser": {
43
+ "import": "./dist/index.browser.mjs",
44
+ "require": "./dist/index.browser.cjs"
45
+ },
46
+ "node": {
47
+ "import": "./dist/index.node.mjs",
48
+ "require": "./dist/index.node.cjs"
49
+ }
50
+ },
51
+ "./react": {
52
+ "types": "./dist/types/react/index.d.ts",
53
+ "react-native": "./dist/react/index.react-native.mjs",
54
+ "browser": {
55
+ "import": "./dist/react/index.browser.mjs",
56
+ "require": "./dist/react/index.browser.cjs"
57
+ },
58
+ "node": {
59
+ "import": "./dist/react/index.node.mjs",
60
+ "require": "./dist/react/index.node.cjs"
61
+ }
62
+ }
63
+ },
64
+ "dependencies": {
65
+ "@solana/wallet-account-signer": "^7.0.0",
66
+ "@solana/wallet-standard-chains": "^1.1.2",
67
+ "@solana/wallet-standard-features": "^1.4.0",
68
+ "@wallet-standard/app": "^1.1.1",
69
+ "@wallet-standard/base": "^1.1.1",
70
+ "@wallet-standard/features": "^1.1.1",
71
+ "@wallet-standard/ui": "^1.0.3",
72
+ "@wallet-standard/ui-features": "^1.0.3",
73
+ "@wallet-standard/ui-registry": "^1.1.1"
74
+ },
75
+ "devDependencies": {
76
+ "@solana/react": "^7.0.0",
77
+ "@testing-library/react": "^16.0.0",
78
+ "@types/react": "^18.0.0 || ^19.0.0",
79
+ "@wallet-standard/errors": "^0.1.2",
80
+ "react": "^18.0.0 || ^19.0.0",
81
+ "react-dom": "^18.0.0 || ^19.0.0"
82
+ },
83
+ "peerDependencies": {
84
+ "@solana/kit": "^7.0.0",
85
+ "@solana/react": "^7.0.0",
86
+ "react": "^18.0.0 || ^19.0.0"
87
+ },
88
+ "peerDependenciesMeta": {
89
+ "@solana/react": {
90
+ "optional": true
91
+ },
92
+ "react": {
93
+ "optional": true
94
+ }
95
+ },
96
+ "browserslist": [
97
+ "supports bigint and not dead",
98
+ "maintained node versions"
99
+ ],
9
100
  "scripts": {
10
- "test": "echo \"Error: no test specified\" && exit 1"
101
+ "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json",
102
+ "dev": "vitest --project node",
103
+ "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:unit",
104
+ "test:treeshakability": "for file in dist/index.*.mjs dist/react/index.*.mjs; do agadoo $file; done",
105
+ "test:types": "tsc --noEmit",
106
+ "test:unit": "vitest run"
11
107
  }
12
- }
108
+ }