@solana/kit-plugin-wallet 0.12.0 → 0.13.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 +102 -4
- package/dist/index.browser.cjs +120 -36
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.mjs +120 -37
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.cjs +9 -2
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.mjs +9 -3
- package/dist/index.node.mjs.map +1 -1
- package/dist/index.react-native.mjs +9 -3
- package/dist/index.react-native.mjs.map +1 -1
- package/dist/react/index.browser.cjs +77 -0
- package/dist/react/index.browser.cjs.map +1 -0
- package/dist/react/index.browser.mjs +66 -0
- package/dist/react/index.browser.mjs.map +1 -0
- package/dist/react/index.node.cjs +77 -0
- package/dist/react/index.node.cjs.map +1 -0
- package/dist/react/index.node.mjs +66 -0
- package/dist/react/index.node.mjs.map +1 -0
- package/dist/react/index.react-native.mjs +66 -0
- package/dist/react/index.react-native.mjs.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/react/index.d.ts +235 -0
- package/dist/types/react/index.d.ts.map +1 -0
- package/dist/types/status.d.ts +31 -0
- package/dist/types/status.d.ts.map +1 -0
- package/dist/types/store.d.ts.map +1 -1
- package/dist/types/types.d.ts +57 -9
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/wallet.d.ts +3 -3
- package/dist/types/wallet.d.ts.map +1 -1
- package/package.json +45 -14
- package/src/__typetests__/wallet-typetest.ts +15 -0
- package/src/index.ts +1 -0
- package/src/react/__typetests__/index.ts +108 -0
- package/src/react/index.ts +301 -0
- package/src/status.ts +33 -0
- package/src/store.ts +208 -81
- package/src/types.ts +58 -9
- package/src/wallet.ts +3 -1
package/README.md
CHANGED
|
@@ -149,9 +149,9 @@ All wallet state is accessed via `client.wallet.getState()`, which returns a ref
|
|
|
149
149
|
}
|
|
150
150
|
```
|
|
151
151
|
|
|
152
|
-
- **`disconnect()`** —
|
|
152
|
+
- **`disconnect(wallet?)`** — Disconnects an authorized wallet. If `wallet` is not provided, disconnects the active wallet.
|
|
153
153
|
|
|
154
|
-
- **`selectAccount(account)`** — Switch to a different account within
|
|
154
|
+
- **`selectAccount(account)`** — Switch to a different account within any already-authorized wallet without reconnecting.
|
|
155
155
|
|
|
156
156
|
```ts
|
|
157
157
|
client.wallet.selectAccount(accounts[0]);
|
|
@@ -169,11 +169,109 @@ All wallet state is accessed via `client.wallet.getState()`, which returns a ref
|
|
|
169
169
|
const output = await client.wallet.signIn(selectedWallet, { domain: window.location.host });
|
|
170
170
|
```
|
|
171
171
|
|
|
172
|
+
## React hooks
|
|
173
|
+
|
|
174
|
+
The `@solana/kit-plugin-wallet/react` subpath exposes hooks for reading wallet state and driving wallet actions from React components. Install the optional peer dependencies (`react` and [`@solana/react`](https://www.npmjs.com/package/@solana/react)) and render your tree inside a `ClientProvider` whose client has a wallet plugin installed.
|
|
175
|
+
|
|
176
|
+
The **state** hooks subscribe via `useSyncExternalStore`, each to a single slice of `WalletState`, so a component only re-renders when the slice it reads changes:
|
|
177
|
+
|
|
178
|
+
| Hook | Returns |
|
|
179
|
+
| -------------------- | -------------------------------------------------------------------------------- |
|
|
180
|
+
| `useWalletStatus` | The current `WalletStatus`. |
|
|
181
|
+
| `useConnectedWallet` | The active connection (`{ account, signer, wallet }`) or null. |
|
|
182
|
+
| `useWallets` | The discovered wallets for the client's chain. |
|
|
183
|
+
| `useIsWalletReady` | `false` while the initial warm-up is in progress (`'pending'`/`'reconnecting'`). |
|
|
184
|
+
|
|
185
|
+
The **action** hooks wrap the async wallet actions with `useAction` from `@solana/react`, returning its result (`dispatch`, `dispatchAsync`, `data`, `error`, `status`, `isRunning`, `reset`, …). The hook manages the `AbortSignal` internally, so an in-flight call is aborted when a newer one is dispatched:
|
|
186
|
+
|
|
187
|
+
| Hook | Wraps |
|
|
188
|
+
| ------------------ | ------------------------------------------------------------------------- |
|
|
189
|
+
| `useConnect` | `client.wallet.connect` — `dispatch(wallet)` |
|
|
190
|
+
| `useDisconnect` | `client.wallet.disconnect` — `dispatch()` |
|
|
191
|
+
| `useSignIn` | `client.wallet.signIn` — `dispatch(wallet, input)` |
|
|
192
|
+
| `useSignMessage` | `client.wallet.signMessage` — `dispatch(message)` |
|
|
193
|
+
| `useSelectAccount` | `client.wallet.selectAccount` — returns the synchronous callback directly |
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
import { useConnect, useConnectedWallet, useWallets, useWalletStatus } from '@solana/kit-plugin-wallet/react';
|
|
197
|
+
|
|
198
|
+
function WalletButton() {
|
|
199
|
+
const status = useWalletStatus();
|
|
200
|
+
const wallets = useWallets();
|
|
201
|
+
const connected = useConnectedWallet();
|
|
202
|
+
const { dispatch: connect, isRunning } = useConnect();
|
|
203
|
+
|
|
204
|
+
if (status === 'pending') return null; // avoid flashing UI before auto-reconnect resolves
|
|
205
|
+
|
|
206
|
+
if (connected) return <p>Connected: {connected.account.address}</p>;
|
|
207
|
+
|
|
208
|
+
return wallets.map(wallet => (
|
|
209
|
+
<button key={wallet.name} disabled={isRunning} onClick={() => connect(wallet)}>
|
|
210
|
+
Connect {wallet.name}
|
|
211
|
+
</button>
|
|
212
|
+
));
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Gating UI on the initial warm-up
|
|
217
|
+
|
|
218
|
+
A freshly built client runs a silent auto-reconnect on mount, briefly passing through `'pending'` and `'reconnecting'` before it settles. If you render wallet-dependent UI immediately, a persisted wallet flashes "disconnected" for a frame before it reconnects. `useIsWalletReady` reports `false` for the duration of that warm-up and `true` once it settles, so you can hold back the wallet-dependent parts while painting the rest of the app:
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
import { useIsWalletReady, WalletReadyGate } from '@solana/kit-plugin-wallet/react';
|
|
222
|
+
|
|
223
|
+
// Hide a whole subtree until the connection settles:
|
|
224
|
+
function App() {
|
|
225
|
+
return (
|
|
226
|
+
<WalletReadyGate fallback={<Spinner />}>
|
|
227
|
+
<WalletDependentUI />
|
|
228
|
+
</WalletReadyGate>
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Or read the boolean directly for finer control (e.g. disabling a button):
|
|
233
|
+
function ConnectButton() {
|
|
234
|
+
const isReady = useIsWalletReady();
|
|
235
|
+
return <button disabled={!isReady}>Connect</button>;
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
`WalletReadyGate` is a thin wrapper over `useIsWalletReady`. Its props are shaped like React's `<Suspense fallback>`, but it is synchronous — it renders `fallback` directly off the reactive status rather than suspending, so it needs no `<Suspense>` ancestor. Both gate on the same warm-up set as `whenReady()` below, so they stay in sync — and like `whenReady()`, they ignore user-initiated `'connecting'` / `'disconnecting'`. To genuinely suspend a subtree, throw the Suspense-safe `whenReady()` promise from your own component instead.
|
|
240
|
+
|
|
241
|
+
### Advanced: seamless client swaps with `whenReady()`
|
|
242
|
+
|
|
243
|
+
> Most apps don't need this. It only matters if you **rebuild the client at runtime** — for example, to change chain — since each wallet plugin is bound to a single chain.
|
|
244
|
+
|
|
245
|
+
Every freshly built client runs a silent auto-reconnect that briefly passes through the `'pending'` and `'reconnecting'` statuses. If you publish the new client as soon as you build it, the UI may flash that reconnecting state on every switch. `client.wallet.whenReady()` returns a promise that resolves once the status has left `'pending'` / `'reconnecting'`, so you can build the new client, wait for it to settle, and only then swap it in — keeping the previous client live until the new one is ready:
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
import { createClient } from '@solana/kit';
|
|
249
|
+
import { walletSigner } from '@solana/kit-plugin-wallet';
|
|
250
|
+
|
|
251
|
+
// On a chain switch, hold the previous client until the rebuilt one is ready:
|
|
252
|
+
const next = createClient().use(walletSigner({ chain }));
|
|
253
|
+
await next.wallet.whenReady();
|
|
254
|
+
swapInClient(next); // publish `next`, then dispose the client it replaced
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
`whenReady()` deliberately does **not** wait for user-initiated `connect` / `disconnect` / `signIn` (those pass through `'connecting'` / `'disconnecting'`), so it only ever blocks on the initial warm-up — a normal connect stays interactive.
|
|
258
|
+
|
|
259
|
+
Disposing a client mid-warm-up settles its status to `'disconnected'` and resolves any pending `whenReady()` promise — a superseded client never leaves an `await` hanging. Check `getState()` after awaiting if you need to tell a ready connection from a disposed (or never-connected) client.
|
|
260
|
+
|
|
172
261
|
## Framework integration
|
|
173
262
|
|
|
174
|
-
The plugin exposes `subscribe` and `getState` for binding wallet state to any UI framework.
|
|
263
|
+
The plugin exposes `subscribe` and `getState` for binding wallet state to any UI framework. To gate UI on the initial auto-reconnect warm-up without React, pass `getState().status` through `isWalletWarmingUp` — the same predicate that backs `whenReady()` and the [React readiness helpers](#gating-ui-on-the-initial-warm-up), so all three stay in sync:
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
import { isWalletWarmingUp } from '@solana/kit-plugin-wallet';
|
|
267
|
+
|
|
268
|
+
client.wallet.subscribe(() => {
|
|
269
|
+
const { status } = client.wallet.getState();
|
|
270
|
+
setLoading(isWalletWarmingUp(status)); // true while 'pending' / 'reconnecting'
|
|
271
|
+
});
|
|
272
|
+
```
|
|
175
273
|
|
|
176
|
-
**React** — use `useSyncExternalStore` for concurrent-mode-safe rendering:
|
|
274
|
+
**React** — prefer the ready-made [React hooks](#react-hooks) above; they wrap the pattern below. To bind state manually (e.g. to read the whole snapshot at once), use `useSyncExternalStore` for concurrent-mode-safe rendering:
|
|
177
275
|
|
|
178
276
|
```tsx
|
|
179
277
|
import { useSyncExternalStore } from 'react';
|
package/dist/index.browser.cjs
CHANGED
|
@@ -8,7 +8,10 @@ var features = require('@wallet-standard/features');
|
|
|
8
8
|
var uiFeatures = require('@wallet-standard/ui-features');
|
|
9
9
|
var uiRegistry = require('@wallet-standard/ui-registry');
|
|
10
10
|
|
|
11
|
-
// src/
|
|
11
|
+
// src/status.ts
|
|
12
|
+
function isWalletWarmingUp(status) {
|
|
13
|
+
return status === "pending" || status === "reconnecting";
|
|
14
|
+
}
|
|
12
15
|
function createWalletStore(config) {
|
|
13
16
|
let state = {
|
|
14
17
|
account: null,
|
|
@@ -19,12 +22,13 @@ function createWalletStore(config) {
|
|
|
19
22
|
};
|
|
20
23
|
const listeners = /* @__PURE__ */ new Set();
|
|
21
24
|
const signerListeners = /* @__PURE__ */ new Set();
|
|
22
|
-
|
|
25
|
+
const walletEventSubscriptions = /* @__PURE__ */ new Map();
|
|
23
26
|
let reconnectCleanup = null;
|
|
24
27
|
let userHasSelected = false;
|
|
25
28
|
let connectGeneration = 0;
|
|
26
29
|
let disposed = false;
|
|
27
30
|
let disconnectingWalletName = null;
|
|
31
|
+
let readyDeferred = null;
|
|
28
32
|
function resolveDefaultStorage() {
|
|
29
33
|
try {
|
|
30
34
|
return localStorage;
|
|
@@ -52,6 +56,13 @@ function createWalletStore(config) {
|
|
|
52
56
|
function updateState(updates) {
|
|
53
57
|
const prev = state;
|
|
54
58
|
state = { ...state, ...updates };
|
|
59
|
+
if (isWalletWarmingUp(prev.status) && !isWalletWarmingUp(state.status)) {
|
|
60
|
+
readyDeferred?.resolve();
|
|
61
|
+
readyDeferred = null;
|
|
62
|
+
}
|
|
63
|
+
if (state.wallets !== prev.wallets) {
|
|
64
|
+
syncWalletEventSubscriptions(state.wallets);
|
|
65
|
+
}
|
|
55
66
|
const signerChanged = observableSigner(state) !== observableSigner(prev);
|
|
56
67
|
if (state.connectedWallet !== prev.connectedWallet || state.account !== prev.account || state.status !== prev.status || state.signer !== prev.signer || state.wallets !== prev.wallets) {
|
|
57
68
|
snapshot = deriveSnapshot(state);
|
|
@@ -61,6 +72,13 @@ function createWalletStore(config) {
|
|
|
61
72
|
signerListeners.forEach((l) => l());
|
|
62
73
|
}
|
|
63
74
|
}
|
|
75
|
+
function whenReady() {
|
|
76
|
+
if (!isWalletWarmingUp(state.status)) {
|
|
77
|
+
return Promise.resolve();
|
|
78
|
+
}
|
|
79
|
+
readyDeferred ??= Promise.withResolvers();
|
|
80
|
+
return readyDeferred.promise;
|
|
81
|
+
}
|
|
64
82
|
function tryCreateSigner(account) {
|
|
65
83
|
try {
|
|
66
84
|
return walletAccountSigner.createSignerFromWalletAccount(account, config.chain);
|
|
@@ -86,6 +104,20 @@ function createWalletStore(config) {
|
|
|
86
104
|
}
|
|
87
105
|
return next;
|
|
88
106
|
}
|
|
107
|
+
function syncWalletEventSubscriptions(wallets) {
|
|
108
|
+
const names = new Set(wallets.map((w) => w.name));
|
|
109
|
+
for (const [name, cleanup] of walletEventSubscriptions) {
|
|
110
|
+
if (!names.has(name)) {
|
|
111
|
+
cleanup();
|
|
112
|
+
walletEventSubscriptions.delete(name);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
for (const w of wallets) {
|
|
116
|
+
if (!walletEventSubscriptions.has(w.name)) {
|
|
117
|
+
walletEventSubscriptions.set(w.name, subscribeToWalletEvents(w));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
89
121
|
function isWalletStillAvailable(uiWallet) {
|
|
90
122
|
return buildWalletList().some((w) => w.name === uiWallet.name);
|
|
91
123
|
}
|
|
@@ -97,8 +129,6 @@ function createWalletStore(config) {
|
|
|
97
129
|
const newWallets = reconcileWalletList();
|
|
98
130
|
const updates = { wallets: newWallets };
|
|
99
131
|
if (state.connectedWallet && !newWallets.some((w) => w.name === state.connectedWallet.name)) {
|
|
100
|
-
walletEventsCleanup?.();
|
|
101
|
-
walletEventsCleanup = null;
|
|
102
132
|
updates.connectedWallet = null;
|
|
103
133
|
updates.account = null;
|
|
104
134
|
updates.signer = null;
|
|
@@ -111,16 +141,17 @@ function createWalletStore(config) {
|
|
|
111
141
|
reconnectCleanup?.();
|
|
112
142
|
reconnectCleanup = null;
|
|
113
143
|
}
|
|
114
|
-
function resubscribeToWalletEvents(uiWallet) {
|
|
115
|
-
walletEventsCleanup?.();
|
|
116
|
-
walletEventsCleanup = subscribeToWalletEvents(uiWallet);
|
|
117
|
-
}
|
|
118
144
|
function setConnected(account, wallet, options) {
|
|
119
145
|
if (disposed) return;
|
|
120
146
|
const signer = tryCreateSigner(account);
|
|
121
|
-
resubscribeToWalletEvents(wallet);
|
|
122
147
|
disconnectingWalletName = null;
|
|
123
|
-
updateState({
|
|
148
|
+
updateState({
|
|
149
|
+
account,
|
|
150
|
+
connectedWallet: wallet,
|
|
151
|
+
signer,
|
|
152
|
+
status: "connected",
|
|
153
|
+
wallets: reconcileWalletList()
|
|
154
|
+
});
|
|
124
155
|
if (options?.persist !== false) {
|
|
125
156
|
persistAccount(account, wallet);
|
|
126
157
|
}
|
|
@@ -138,8 +169,14 @@ function createWalletStore(config) {
|
|
|
138
169
|
uiWallet,
|
|
139
170
|
features.StandardEvents
|
|
140
171
|
);
|
|
172
|
+
const walletName = uiWallet.name;
|
|
141
173
|
return eventsFeature.on("change", () => {
|
|
142
|
-
const
|
|
174
|
+
const newWallets = reconcileWalletList();
|
|
175
|
+
if (!state.connectedWallet || state.connectedWallet.name !== walletName) {
|
|
176
|
+
updateState({ wallets: newWallets });
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const refreshed = refreshUiWallet(state.connectedWallet);
|
|
143
180
|
if (!filterWallet(refreshed)) {
|
|
144
181
|
disconnectLocally();
|
|
145
182
|
return;
|
|
@@ -149,7 +186,7 @@ function createWalletStore(config) {
|
|
|
149
186
|
disconnectLocally();
|
|
150
187
|
return;
|
|
151
188
|
}
|
|
152
|
-
updateState({ connectedWallet: refreshed, wallets:
|
|
189
|
+
updateState({ connectedWallet: refreshed, wallets: newWallets, ...result });
|
|
153
190
|
if (result.account) {
|
|
154
191
|
persistAccount(result.account, refreshed);
|
|
155
192
|
}
|
|
@@ -199,9 +236,10 @@ function createWalletStore(config) {
|
|
|
199
236
|
throw error;
|
|
200
237
|
}
|
|
201
238
|
}
|
|
202
|
-
async function disconnect(options) {
|
|
239
|
+
async function disconnect(wallet, options) {
|
|
203
240
|
options?.abortSignal?.throwIfAborted();
|
|
204
|
-
|
|
241
|
+
const target = wallet ?? state.connectedWallet;
|
|
242
|
+
if (!target) {
|
|
205
243
|
userHasSelected = true;
|
|
206
244
|
cancelReconnect();
|
|
207
245
|
connectGeneration++;
|
|
@@ -209,27 +247,52 @@ function createWalletStore(config) {
|
|
|
209
247
|
clearPersistedAccount();
|
|
210
248
|
return;
|
|
211
249
|
}
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
250
|
+
const isActive = state.connectedWallet != null && state.connectedWallet.name === target.name;
|
|
251
|
+
if (isActive) {
|
|
252
|
+
const currentWallet = state.connectedWallet;
|
|
253
|
+
const generation = ++connectGeneration;
|
|
254
|
+
disconnectingWalletName = currentWallet.name;
|
|
255
|
+
updateState({ status: "disconnecting" });
|
|
256
|
+
try {
|
|
257
|
+
if (currentWallet.features.includes(features.StandardDisconnect)) {
|
|
258
|
+
const disconnectFeature = uiFeatures.getWalletFeature(
|
|
259
|
+
currentWallet,
|
|
260
|
+
features.StandardDisconnect
|
|
261
|
+
);
|
|
262
|
+
await disconnectFeature.disconnect();
|
|
263
|
+
}
|
|
264
|
+
} finally {
|
|
265
|
+
if (generation === connectGeneration) {
|
|
266
|
+
disconnectLocally();
|
|
267
|
+
}
|
|
223
268
|
}
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (!isWalletStillAvailable(target)) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const refreshedTarget = refreshUiWallet(target);
|
|
275
|
+
if (!refreshedTarget.features.includes(features.StandardDisconnect)) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const prevDisconnecting = disconnectingWalletName;
|
|
279
|
+
disconnectingWalletName = refreshedTarget.name;
|
|
280
|
+
try {
|
|
281
|
+
const disconnectFeature = uiFeatures.getWalletFeature(
|
|
282
|
+
refreshedTarget,
|
|
283
|
+
features.StandardDisconnect
|
|
284
|
+
);
|
|
285
|
+
await disconnectFeature.disconnect();
|
|
224
286
|
} finally {
|
|
225
|
-
if (
|
|
226
|
-
|
|
287
|
+
if (disconnectingWalletName === refreshedTarget.name) {
|
|
288
|
+
disconnectingWalletName = prevDisconnecting;
|
|
289
|
+
}
|
|
290
|
+
if (!disposed) {
|
|
291
|
+
updateState({ wallets: reconcileWalletList() });
|
|
227
292
|
}
|
|
228
293
|
}
|
|
229
294
|
}
|
|
230
295
|
function disconnectLocally() {
|
|
231
|
-
walletEventsCleanup?.();
|
|
232
|
-
walletEventsCleanup = null;
|
|
233
296
|
disconnectingWalletName = null;
|
|
234
297
|
updateState({
|
|
235
298
|
account: null,
|
|
@@ -255,13 +318,25 @@ function createWalletStore(config) {
|
|
|
255
318
|
}
|
|
256
319
|
}
|
|
257
320
|
function selectAccount(account) {
|
|
258
|
-
|
|
259
|
-
|
|
321
|
+
let owner;
|
|
322
|
+
try {
|
|
323
|
+
owner = uiRegistry.getOrCreateUiWalletForStandardWallet(uiRegistry.getWalletForHandle(account));
|
|
324
|
+
} catch {
|
|
325
|
+
throw new kit.SolanaError(kit.SOLANA_ERROR__WALLET__ACCOUNT_NOT_AVAILABLE, {
|
|
326
|
+
account: account.address,
|
|
327
|
+
operation: "selectAccount"
|
|
328
|
+
});
|
|
260
329
|
}
|
|
261
|
-
if (
|
|
330
|
+
if (!isWalletStillAvailable(owner)) {
|
|
331
|
+
throw new kit.SolanaError(kit.SOLANA_ERROR__WALLET__ACCOUNT_NOT_AVAILABLE, {
|
|
332
|
+
account: account.address,
|
|
333
|
+
operation: "selectAccount"
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
if (owner.name === disconnectingWalletName) {
|
|
262
337
|
throw new kit.SolanaError(kit.SOLANA_ERROR__WALLET__NOT_CONNECTED, { operation: "selectAccount" });
|
|
263
338
|
}
|
|
264
|
-
const refreshed = refreshUiWallet(
|
|
339
|
+
const refreshed = refreshUiWallet(owner);
|
|
265
340
|
const selectedAccount = refreshed.accounts.find((a) => a.address === account.address);
|
|
266
341
|
if (!selectedAccount) {
|
|
267
342
|
throw new kit.SolanaError(kit.SOLANA_ERROR__WALLET__ACCOUNT_NOT_AVAILABLE, {
|
|
@@ -466,16 +541,22 @@ function createWalletStore(config) {
|
|
|
466
541
|
signerListeners.delete(listener);
|
|
467
542
|
};
|
|
468
543
|
},
|
|
544
|
+
whenReady,
|
|
469
545
|
[Symbol.dispose]: () => {
|
|
470
546
|
disposed = true;
|
|
471
547
|
connectGeneration++;
|
|
472
548
|
unsubRegister();
|
|
473
549
|
unsubUnregister();
|
|
474
|
-
|
|
475
|
-
|
|
550
|
+
for (const cleanup of walletEventSubscriptions.values()) {
|
|
551
|
+
cleanup();
|
|
552
|
+
}
|
|
553
|
+
walletEventSubscriptions.clear();
|
|
476
554
|
cancelReconnect();
|
|
477
555
|
listeners.clear();
|
|
478
556
|
signerListeners.clear();
|
|
557
|
+
if (isWalletWarmingUp(state.status)) {
|
|
558
|
+
updateState({ status: "disconnected" });
|
|
559
|
+
}
|
|
479
560
|
}
|
|
480
561
|
};
|
|
481
562
|
}
|
|
@@ -484,7 +565,9 @@ function createWalletStore(config) {
|
|
|
484
565
|
function defineSignerGetter(additions, property, store) {
|
|
485
566
|
Object.defineProperty(additions, property, {
|
|
486
567
|
configurable: true,
|
|
487
|
-
enumerable:
|
|
568
|
+
// Non-enumerable on purpose: this getter throws when no signer is connected, so we
|
|
569
|
+
// don't want things like Object.entries to read it.
|
|
570
|
+
enumerable: false,
|
|
488
571
|
get() {
|
|
489
572
|
const state = store.getState();
|
|
490
573
|
if (!state.connected) {
|
|
@@ -530,6 +613,7 @@ function walletWithoutSigner(config) {
|
|
|
530
613
|
return createPlugin(config, []);
|
|
531
614
|
}
|
|
532
615
|
|
|
616
|
+
exports.isWalletWarmingUp = isWalletWarmingUp;
|
|
533
617
|
exports.walletIdentity = walletIdentity;
|
|
534
618
|
exports.walletPayer = walletPayer;
|
|
535
619
|
exports.walletSigner = walletSigner;
|