@solana/kit-plugin-wallet 0.0.0 → 0.12.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.
- package/LICENSE +22 -0
- package/README.md +303 -0
- package/dist/index.browser.cjs +538 -0
- package/dist/index.browser.cjs.map +1 -0
- package/dist/index.browser.mjs +533 -0
- package/dist/index.browser.mjs.map +1 -0
- package/dist/index.node.cjs +93 -0
- package/dist/index.node.cjs.map +1 -0
- package/dist/index.node.mjs +88 -0
- package/dist/index.node.mjs.map +1 -0
- package/dist/index.react-native.mjs +88 -0
- package/dist/index.react-native.mjs.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/store.d.ts +16 -0
- package/dist/types/store.d.ts.map +1 -0
- package/dist/types/types.d.ts +336 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/wallet.d.ts +133 -0
- package/dist/types/wallet.d.ts.map +1 -0
- package/package.json +73 -7
- package/src/__typetests__/wallet-typetest.ts +114 -0
- package/src/index.ts +2 -0
- package/src/store.ts +863 -0
- package/src/types/global.d.ts +6 -0
- package/src/types.ts +358 -0
- package/src/wallet.ts +216 -0
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var kit = require('@solana/kit');
|
|
4
|
+
var walletAccountSigner = require('@solana/wallet-account-signer');
|
|
5
|
+
var walletStandardFeatures = require('@solana/wallet-standard-features');
|
|
6
|
+
var app = require('@wallet-standard/app');
|
|
7
|
+
var features = require('@wallet-standard/features');
|
|
8
|
+
var uiFeatures = require('@wallet-standard/ui-features');
|
|
9
|
+
var uiRegistry = require('@wallet-standard/ui-registry');
|
|
10
|
+
|
|
11
|
+
// src/wallet.ts
|
|
12
|
+
function createWalletStore(config) {
|
|
13
|
+
let state = {
|
|
14
|
+
account: null,
|
|
15
|
+
connectedWallet: null,
|
|
16
|
+
signer: null,
|
|
17
|
+
status: "pending",
|
|
18
|
+
wallets: []
|
|
19
|
+
};
|
|
20
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
21
|
+
const signerListeners = /* @__PURE__ */ new Set();
|
|
22
|
+
let walletEventsCleanup = null;
|
|
23
|
+
let reconnectCleanup = null;
|
|
24
|
+
let userHasSelected = false;
|
|
25
|
+
let connectGeneration = 0;
|
|
26
|
+
let disposed = false;
|
|
27
|
+
let disconnectingWalletName = null;
|
|
28
|
+
function resolveDefaultStorage() {
|
|
29
|
+
try {
|
|
30
|
+
return localStorage;
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const storage = config.storage === null ? null : config.storage ?? resolveDefaultStorage();
|
|
36
|
+
const storageKey = config.storageKey ?? "kit-wallet";
|
|
37
|
+
function deriveSnapshot(s) {
|
|
38
|
+
return Object.freeze({
|
|
39
|
+
connected: s.connectedWallet && s.account ? Object.freeze({
|
|
40
|
+
account: s.account,
|
|
41
|
+
signer: s.signer,
|
|
42
|
+
wallet: s.connectedWallet
|
|
43
|
+
}) : null,
|
|
44
|
+
status: s.status,
|
|
45
|
+
wallets: s.wallets
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
let snapshot = deriveSnapshot(state);
|
|
49
|
+
function observableSigner(s) {
|
|
50
|
+
return s.connectedWallet && s.account ? s.signer : void 0;
|
|
51
|
+
}
|
|
52
|
+
function updateState(updates) {
|
|
53
|
+
const prev = state;
|
|
54
|
+
state = { ...state, ...updates };
|
|
55
|
+
const signerChanged = observableSigner(state) !== observableSigner(prev);
|
|
56
|
+
if (state.connectedWallet !== prev.connectedWallet || state.account !== prev.account || state.status !== prev.status || state.signer !== prev.signer || state.wallets !== prev.wallets) {
|
|
57
|
+
snapshot = deriveSnapshot(state);
|
|
58
|
+
listeners.forEach((l) => l());
|
|
59
|
+
}
|
|
60
|
+
if (signerChanged) {
|
|
61
|
+
signerListeners.forEach((l) => l());
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function tryCreateSigner(account) {
|
|
65
|
+
try {
|
|
66
|
+
return walletAccountSigner.createSignerFromWalletAccount(account, config.chain);
|
|
67
|
+
} catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const registry = app.getWallets();
|
|
72
|
+
function filterWallet(uiWallet) {
|
|
73
|
+
const supportsChain = uiWallet.chains.includes(config.chain);
|
|
74
|
+
const supportsConnect = uiWallet.features.includes(features.StandardConnect);
|
|
75
|
+
if (!supportsChain || !supportsConnect) return false;
|
|
76
|
+
return config.filter ? config.filter(uiWallet) : true;
|
|
77
|
+
}
|
|
78
|
+
function buildWalletList() {
|
|
79
|
+
return Object.freeze(registry.get().map(uiRegistry.getOrCreateUiWalletForStandardWallet).filter(filterWallet));
|
|
80
|
+
}
|
|
81
|
+
function reconcileWalletList() {
|
|
82
|
+
const next = buildWalletList();
|
|
83
|
+
const prev = state.wallets;
|
|
84
|
+
if (next.length === prev.length && next.every((w, i) => w === prev[i])) {
|
|
85
|
+
return prev;
|
|
86
|
+
}
|
|
87
|
+
return next;
|
|
88
|
+
}
|
|
89
|
+
function isWalletStillAvailable(uiWallet) {
|
|
90
|
+
return buildWalletList().some((w) => w.name === uiWallet.name);
|
|
91
|
+
}
|
|
92
|
+
updateState({ wallets: buildWalletList() });
|
|
93
|
+
const unsubRegister = registry.on("register", () => {
|
|
94
|
+
updateState({ wallets: reconcileWalletList() });
|
|
95
|
+
});
|
|
96
|
+
const unsubUnregister = registry.on("unregister", () => {
|
|
97
|
+
const newWallets = reconcileWalletList();
|
|
98
|
+
const updates = { wallets: newWallets };
|
|
99
|
+
if (state.connectedWallet && !newWallets.some((w) => w.name === state.connectedWallet.name)) {
|
|
100
|
+
walletEventsCleanup?.();
|
|
101
|
+
walletEventsCleanup = null;
|
|
102
|
+
updates.connectedWallet = null;
|
|
103
|
+
updates.account = null;
|
|
104
|
+
updates.signer = null;
|
|
105
|
+
updates.status = "disconnected";
|
|
106
|
+
clearPersistedAccount();
|
|
107
|
+
}
|
|
108
|
+
updateState(updates);
|
|
109
|
+
});
|
|
110
|
+
function cancelReconnect() {
|
|
111
|
+
reconnectCleanup?.();
|
|
112
|
+
reconnectCleanup = null;
|
|
113
|
+
}
|
|
114
|
+
function resubscribeToWalletEvents(uiWallet) {
|
|
115
|
+
walletEventsCleanup?.();
|
|
116
|
+
walletEventsCleanup = subscribeToWalletEvents(uiWallet);
|
|
117
|
+
}
|
|
118
|
+
function setConnected(account, wallet, options) {
|
|
119
|
+
if (disposed) return;
|
|
120
|
+
const signer = tryCreateSigner(account);
|
|
121
|
+
resubscribeToWalletEvents(wallet);
|
|
122
|
+
disconnectingWalletName = null;
|
|
123
|
+
updateState({ account, connectedWallet: wallet, signer, status: "connected" });
|
|
124
|
+
if (options?.persist !== false) {
|
|
125
|
+
persistAccount(account, wallet);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function refreshUiWallet(staleUiWallet) {
|
|
129
|
+
const rawWallet = uiRegistry.getWalletForHandle(staleUiWallet);
|
|
130
|
+
return uiRegistry.getOrCreateUiWalletForStandardWallet(rawWallet);
|
|
131
|
+
}
|
|
132
|
+
function subscribeToWalletEvents(uiWallet) {
|
|
133
|
+
if (!uiWallet.features.includes(features.StandardEvents)) {
|
|
134
|
+
return () => {
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const eventsFeature = uiFeatures.getWalletFeature(
|
|
138
|
+
uiWallet,
|
|
139
|
+
features.StandardEvents
|
|
140
|
+
);
|
|
141
|
+
return eventsFeature.on("change", () => {
|
|
142
|
+
const refreshed = refreshUiWallet(uiWallet);
|
|
143
|
+
if (!filterWallet(refreshed)) {
|
|
144
|
+
disconnectLocally();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const result = reconcileActiveAccount(refreshed);
|
|
148
|
+
if (result === null) {
|
|
149
|
+
disconnectLocally();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
updateState({ connectedWallet: refreshed, wallets: reconcileWalletList(), ...result });
|
|
153
|
+
if (result.account) {
|
|
154
|
+
persistAccount(result.account, refreshed);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function reconcileActiveAccount(wallet) {
|
|
159
|
+
const newAccounts = wallet.accounts;
|
|
160
|
+
if (newAccounts.length === 0) return null;
|
|
161
|
+
const currentAddress = state.account?.address;
|
|
162
|
+
const stillPresent = currentAddress ? newAccounts.find((a) => a.address === currentAddress) : null;
|
|
163
|
+
const activeAccount = stillPresent ?? newAccounts[0];
|
|
164
|
+
if (activeAccount === state.account) return {};
|
|
165
|
+
return { account: activeAccount, signer: tryCreateSigner(activeAccount) };
|
|
166
|
+
}
|
|
167
|
+
async function connect(uiWallet, options) {
|
|
168
|
+
options?.abortSignal?.throwIfAborted();
|
|
169
|
+
const connectFeature = uiFeatures.getWalletFeature(
|
|
170
|
+
uiWallet,
|
|
171
|
+
features.StandardConnect
|
|
172
|
+
);
|
|
173
|
+
userHasSelected = true;
|
|
174
|
+
cancelReconnect();
|
|
175
|
+
const generation = ++connectGeneration;
|
|
176
|
+
updateState({ status: "connecting" });
|
|
177
|
+
try {
|
|
178
|
+
const existingAccounts = [...uiWallet.accounts];
|
|
179
|
+
await connectFeature.connect();
|
|
180
|
+
if (generation !== connectGeneration) {
|
|
181
|
+
throw new DOMException("Wallet connect was superseded by a newer connect or sign-in", "AbortError");
|
|
182
|
+
}
|
|
183
|
+
if (!isWalletStillAvailable(uiWallet)) {
|
|
184
|
+
throw new kit.SolanaError(kit.SOLANA_ERROR__WALLET__NOT_CONNECTED, { operation: "connect" });
|
|
185
|
+
}
|
|
186
|
+
const refreshedWallet = refreshUiWallet(uiWallet);
|
|
187
|
+
const allAccounts = refreshedWallet.accounts;
|
|
188
|
+
if (allAccounts.length === 0) {
|
|
189
|
+
throw new kit.SolanaError(kit.SOLANA_ERROR__WALLET__NOT_CONNECTED, { operation: "connect" });
|
|
190
|
+
}
|
|
191
|
+
const newAccount = allAccounts.find((a) => !existingAccounts.some((e) => e.address === a.address));
|
|
192
|
+
const activeAccount = newAccount ?? allAccounts[0];
|
|
193
|
+
setConnected(activeAccount, refreshedWallet);
|
|
194
|
+
return allAccounts;
|
|
195
|
+
} catch (error) {
|
|
196
|
+
if (generation === connectGeneration) {
|
|
197
|
+
revertToPreviousConnectionOrDisconnect();
|
|
198
|
+
}
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
async function disconnect(options) {
|
|
203
|
+
options?.abortSignal?.throwIfAborted();
|
|
204
|
+
if (!state.connectedWallet) {
|
|
205
|
+
userHasSelected = true;
|
|
206
|
+
cancelReconnect();
|
|
207
|
+
connectGeneration++;
|
|
208
|
+
updateState({ status: "disconnected" });
|
|
209
|
+
clearPersistedAccount();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const currentWallet = state.connectedWallet;
|
|
213
|
+
const generation = ++connectGeneration;
|
|
214
|
+
disconnectingWalletName = currentWallet.name;
|
|
215
|
+
updateState({ status: "disconnecting" });
|
|
216
|
+
try {
|
|
217
|
+
if (currentWallet.features.includes(features.StandardDisconnect)) {
|
|
218
|
+
const disconnectFeature = uiFeatures.getWalletFeature(
|
|
219
|
+
currentWallet,
|
|
220
|
+
features.StandardDisconnect
|
|
221
|
+
);
|
|
222
|
+
await disconnectFeature.disconnect();
|
|
223
|
+
}
|
|
224
|
+
} finally {
|
|
225
|
+
if (generation === connectGeneration) {
|
|
226
|
+
disconnectLocally();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function disconnectLocally() {
|
|
231
|
+
walletEventsCleanup?.();
|
|
232
|
+
walletEventsCleanup = null;
|
|
233
|
+
disconnectingWalletName = null;
|
|
234
|
+
updateState({
|
|
235
|
+
account: null,
|
|
236
|
+
connectedWallet: null,
|
|
237
|
+
signer: null,
|
|
238
|
+
status: "disconnected",
|
|
239
|
+
// Reconcile the list too: when this runs from the change handler
|
|
240
|
+
// because the connected wallet dropped the configured chain or
|
|
241
|
+
// failed the filter, that wallet must leave `wallets` immediately
|
|
242
|
+
// rather than linger until an unrelated register/unregister event.
|
|
243
|
+
// `reconcileWalletList` returns the existing reference when the
|
|
244
|
+
// visible set is unchanged (the common case for a plain disconnect),
|
|
245
|
+
// so this stays churn-free.
|
|
246
|
+
wallets: reconcileWalletList()
|
|
247
|
+
});
|
|
248
|
+
clearPersistedAccount();
|
|
249
|
+
}
|
|
250
|
+
function revertToPreviousConnectionOrDisconnect() {
|
|
251
|
+
if (state.connectedWallet && state.account && state.connectedWallet.name !== disconnectingWalletName) {
|
|
252
|
+
updateState({ status: "connected" });
|
|
253
|
+
} else {
|
|
254
|
+
disconnectLocally();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function selectAccount(account) {
|
|
258
|
+
if (!state.connectedWallet) {
|
|
259
|
+
throw new kit.SolanaError(kit.SOLANA_ERROR__WALLET__NOT_CONNECTED, { operation: "selectAccount" });
|
|
260
|
+
}
|
|
261
|
+
if (state.connectedWallet.name === disconnectingWalletName) {
|
|
262
|
+
throw new kit.SolanaError(kit.SOLANA_ERROR__WALLET__NOT_CONNECTED, { operation: "selectAccount" });
|
|
263
|
+
}
|
|
264
|
+
const refreshed = refreshUiWallet(state.connectedWallet);
|
|
265
|
+
const selectedAccount = refreshed.accounts.find((a) => a.address === account.address);
|
|
266
|
+
if (!selectedAccount) {
|
|
267
|
+
throw new kit.SolanaError(kit.SOLANA_ERROR__WALLET__ACCOUNT_NOT_AVAILABLE, {
|
|
268
|
+
account: account.address,
|
|
269
|
+
operation: "selectAccount"
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
userHasSelected = true;
|
|
273
|
+
++connectGeneration;
|
|
274
|
+
if (selectedAccount === state.account && refreshed === state.connectedWallet) {
|
|
275
|
+
updateState({ status: "connected" });
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const signer = tryCreateSigner(selectedAccount);
|
|
279
|
+
updateState({ account: selectedAccount, connectedWallet: refreshed, signer, status: "connected" });
|
|
280
|
+
persistAccount(selectedAccount, refreshed);
|
|
281
|
+
}
|
|
282
|
+
async function signMessage(message, options) {
|
|
283
|
+
options?.abortSignal?.throwIfAborted();
|
|
284
|
+
const { connectedWallet, account } = state;
|
|
285
|
+
if (!connectedWallet || !account) {
|
|
286
|
+
throw new kit.SolanaError(kit.SOLANA_ERROR__WALLET__NOT_CONNECTED, { operation: "signMessage" });
|
|
287
|
+
}
|
|
288
|
+
const signMessageFeature = uiFeatures.getWalletAccountFeature(
|
|
289
|
+
account,
|
|
290
|
+
walletStandardFeatures.SolanaSignMessage
|
|
291
|
+
);
|
|
292
|
+
const [output] = await signMessageFeature.signMessage({ account, message });
|
|
293
|
+
return output.signature;
|
|
294
|
+
}
|
|
295
|
+
async function signIn(uiWallet, input, options) {
|
|
296
|
+
options?.abortSignal?.throwIfAborted();
|
|
297
|
+
const signInFeature = uiFeatures.getWalletFeature(uiWallet, walletStandardFeatures.SolanaSignIn);
|
|
298
|
+
userHasSelected = true;
|
|
299
|
+
cancelReconnect();
|
|
300
|
+
const generation = ++connectGeneration;
|
|
301
|
+
updateState({ status: "connecting" });
|
|
302
|
+
try {
|
|
303
|
+
const [result] = await signInFeature.signIn(input);
|
|
304
|
+
if (generation !== connectGeneration) {
|
|
305
|
+
throw new DOMException("Wallet sign-in was superseded by a newer connect or sign-in", "AbortError");
|
|
306
|
+
}
|
|
307
|
+
if (!isWalletStillAvailable(uiWallet)) {
|
|
308
|
+
throw new kit.SolanaError(kit.SOLANA_ERROR__WALLET__NOT_CONNECTED, { operation: "signIn" });
|
|
309
|
+
}
|
|
310
|
+
const refreshedWallet = refreshUiWallet(uiWallet);
|
|
311
|
+
const activeAccount = refreshedWallet.accounts.find((a) => a.address === result.account.address);
|
|
312
|
+
if (!activeAccount) {
|
|
313
|
+
throw new kit.SolanaError(kit.SOLANA_ERROR__WALLET__NOT_CONNECTED, { operation: "signIn" });
|
|
314
|
+
}
|
|
315
|
+
setConnected(activeAccount, refreshedWallet);
|
|
316
|
+
return result;
|
|
317
|
+
} catch (error) {
|
|
318
|
+
if (generation === connectGeneration) {
|
|
319
|
+
revertToPreviousConnectionOrDisconnect();
|
|
320
|
+
}
|
|
321
|
+
throw error;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
function ignoreStorageFailure(operation) {
|
|
325
|
+
void (async () => {
|
|
326
|
+
try {
|
|
327
|
+
await operation();
|
|
328
|
+
} catch {
|
|
329
|
+
}
|
|
330
|
+
})();
|
|
331
|
+
}
|
|
332
|
+
function persistAccount(account, wallet) {
|
|
333
|
+
if (!storage) return;
|
|
334
|
+
ignoreStorageFailure(() => storage.setItem(storageKey, `${wallet.name}:${account.address}`));
|
|
335
|
+
}
|
|
336
|
+
function clearPersistedAccount() {
|
|
337
|
+
if (!storage) return;
|
|
338
|
+
ignoreStorageFailure(() => storage.removeItem(storageKey));
|
|
339
|
+
}
|
|
340
|
+
if (config.autoConnect !== false && storage) {
|
|
341
|
+
const generation = connectGeneration;
|
|
342
|
+
(async () => {
|
|
343
|
+
const savedKey = await storage.getItem(storageKey);
|
|
344
|
+
if (userHasSelected || disposed) return;
|
|
345
|
+
if (!savedKey) {
|
|
346
|
+
updateState({ status: "disconnected" });
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const separatorIndex = savedKey.lastIndexOf(":");
|
|
350
|
+
if (separatorIndex === -1) {
|
|
351
|
+
updateState({ status: "disconnected" });
|
|
352
|
+
clearPersistedAccount();
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const walletName = savedKey.slice(0, separatorIndex);
|
|
356
|
+
const savedAddress = savedKey.slice(separatorIndex + 1);
|
|
357
|
+
const existing = state.wallets.find((w) => w.name === walletName);
|
|
358
|
+
if (existing) {
|
|
359
|
+
await attemptSilentReconnect(savedAddress, existing);
|
|
360
|
+
} else if (registry.get().some((w) => {
|
|
361
|
+
const ui = uiRegistry.getOrCreateUiWalletForStandardWallet(w);
|
|
362
|
+
return ui.name === walletName;
|
|
363
|
+
})) {
|
|
364
|
+
updateState({ status: "disconnected" });
|
|
365
|
+
clearPersistedAccount();
|
|
366
|
+
} else {
|
|
367
|
+
updateState({ status: "reconnecting" });
|
|
368
|
+
const statusTimeout = setTimeout(() => {
|
|
369
|
+
if (!userHasSelected && state.status === "reconnecting") {
|
|
370
|
+
updateState({ status: "disconnected" });
|
|
371
|
+
}
|
|
372
|
+
}, 3e3);
|
|
373
|
+
const unsubRegisterForReconnect = registry.on("register", () => {
|
|
374
|
+
const generation2 = connectGeneration;
|
|
375
|
+
void (async () => {
|
|
376
|
+
if (userHasSelected) {
|
|
377
|
+
clearTimeout(statusTimeout);
|
|
378
|
+
unsubRegisterForReconnect();
|
|
379
|
+
reconnectCleanup = null;
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
const found = buildWalletList().find((w) => w.name === walletName);
|
|
383
|
+
if (found) {
|
|
384
|
+
clearTimeout(statusTimeout);
|
|
385
|
+
unsubRegisterForReconnect();
|
|
386
|
+
reconnectCleanup = null;
|
|
387
|
+
await attemptSilentReconnect(savedAddress, found);
|
|
388
|
+
} else if (registry.get().some((w) => {
|
|
389
|
+
const ui = uiRegistry.getOrCreateUiWalletForStandardWallet(w);
|
|
390
|
+
return ui.name === walletName;
|
|
391
|
+
})) {
|
|
392
|
+
clearTimeout(statusTimeout);
|
|
393
|
+
unsubRegisterForReconnect();
|
|
394
|
+
reconnectCleanup = null;
|
|
395
|
+
updateState({ status: "disconnected" });
|
|
396
|
+
clearPersistedAccount();
|
|
397
|
+
}
|
|
398
|
+
})().catch(() => {
|
|
399
|
+
if (generation2 === connectGeneration && !userHasSelected) {
|
|
400
|
+
updateState({ status: "disconnected" });
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
reconnectCleanup = () => {
|
|
405
|
+
clearTimeout(statusTimeout);
|
|
406
|
+
unsubRegisterForReconnect();
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
})().catch(() => {
|
|
410
|
+
if (generation === connectGeneration && !userHasSelected) {
|
|
411
|
+
updateState({ status: "disconnected" });
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
} else {
|
|
415
|
+
updateState({ status: "disconnected" });
|
|
416
|
+
}
|
|
417
|
+
async function attemptSilentReconnect(savedAddress, uiWallet) {
|
|
418
|
+
const generation = ++connectGeneration;
|
|
419
|
+
updateState({ status: "reconnecting" });
|
|
420
|
+
try {
|
|
421
|
+
const connectFeature = uiFeatures.getWalletFeature(
|
|
422
|
+
uiWallet,
|
|
423
|
+
features.StandardConnect
|
|
424
|
+
);
|
|
425
|
+
await connectFeature.connect({ silent: true });
|
|
426
|
+
if (generation !== connectGeneration) return;
|
|
427
|
+
if (!isWalletStillAvailable(uiWallet)) {
|
|
428
|
+
updateState({ status: "disconnected" });
|
|
429
|
+
clearPersistedAccount();
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
const refreshedWallet = refreshUiWallet(uiWallet);
|
|
433
|
+
const allAccounts = refreshedWallet.accounts;
|
|
434
|
+
if (allAccounts.length === 0) {
|
|
435
|
+
updateState({ status: "disconnected" });
|
|
436
|
+
clearPersistedAccount();
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
const activeAccount = allAccounts.find((a) => a.address === savedAddress) ?? allAccounts[0];
|
|
440
|
+
setConnected(activeAccount, refreshedWallet, {
|
|
441
|
+
persist: activeAccount.address !== savedAddress
|
|
442
|
+
});
|
|
443
|
+
} catch {
|
|
444
|
+
if (generation === connectGeneration) {
|
|
445
|
+
updateState({ status: "disconnected" });
|
|
446
|
+
clearPersistedAccount();
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return {
|
|
451
|
+
connect,
|
|
452
|
+
disconnect,
|
|
453
|
+
getState: () => snapshot,
|
|
454
|
+
selectAccount,
|
|
455
|
+
signIn,
|
|
456
|
+
signMessage,
|
|
457
|
+
subscribe: (listener) => {
|
|
458
|
+
listeners.add(listener);
|
|
459
|
+
return () => {
|
|
460
|
+
listeners.delete(listener);
|
|
461
|
+
};
|
|
462
|
+
},
|
|
463
|
+
subscribeSigner: (listener) => {
|
|
464
|
+
signerListeners.add(listener);
|
|
465
|
+
return () => {
|
|
466
|
+
signerListeners.delete(listener);
|
|
467
|
+
};
|
|
468
|
+
},
|
|
469
|
+
[Symbol.dispose]: () => {
|
|
470
|
+
disposed = true;
|
|
471
|
+
connectGeneration++;
|
|
472
|
+
unsubRegister();
|
|
473
|
+
unsubUnregister();
|
|
474
|
+
walletEventsCleanup?.();
|
|
475
|
+
walletEventsCleanup = null;
|
|
476
|
+
cancelReconnect();
|
|
477
|
+
listeners.clear();
|
|
478
|
+
signerListeners.clear();
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/wallet.ts
|
|
484
|
+
function defineSignerGetter(additions, property, store) {
|
|
485
|
+
Object.defineProperty(additions, property, {
|
|
486
|
+
configurable: true,
|
|
487
|
+
enumerable: true,
|
|
488
|
+
get() {
|
|
489
|
+
const state = store.getState();
|
|
490
|
+
if (!state.connected) {
|
|
491
|
+
throw new kit.SolanaError(kit.SOLANA_ERROR__WALLET__NO_SIGNER_CONNECTED, { status: state.status });
|
|
492
|
+
}
|
|
493
|
+
if (!state.connected.signer) {
|
|
494
|
+
throw new kit.SolanaError(kit.SOLANA_ERROR__WALLET__SIGNER_NOT_AVAILABLE);
|
|
495
|
+
}
|
|
496
|
+
return state.connected.signer;
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
var SUBSCRIBE_PROPERTY = {
|
|
501
|
+
identity: "subscribeToIdentity",
|
|
502
|
+
payer: "subscribeToPayer"
|
|
503
|
+
};
|
|
504
|
+
function createPlugin(config, signerProperties) {
|
|
505
|
+
return (client) => {
|
|
506
|
+
if ("wallet" in client) {
|
|
507
|
+
throw new Error(
|
|
508
|
+
"Only one wallet plugin can be used per client. Use walletSigner, walletPayer, walletIdentity, or walletWithoutSigner \u2014 not multiple."
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
const store = createWalletStore(config);
|
|
512
|
+
const additions = { wallet: store };
|
|
513
|
+
for (const prop of signerProperties) {
|
|
514
|
+
defineSignerGetter(additions, prop, store);
|
|
515
|
+
additions[SUBSCRIBE_PROPERTY[prop]] = store.subscribeSigner;
|
|
516
|
+
}
|
|
517
|
+
return kit.withCleanup(kit.extendClient(client, additions), () => store[Symbol.dispose]());
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
function walletSigner(config) {
|
|
521
|
+
return createPlugin(config, ["payer", "identity"]);
|
|
522
|
+
}
|
|
523
|
+
function walletIdentity(config) {
|
|
524
|
+
return createPlugin(config, ["identity"]);
|
|
525
|
+
}
|
|
526
|
+
function walletPayer(config) {
|
|
527
|
+
return createPlugin(config, ["payer"]);
|
|
528
|
+
}
|
|
529
|
+
function walletWithoutSigner(config) {
|
|
530
|
+
return createPlugin(config, []);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
exports.walletIdentity = walletIdentity;
|
|
534
|
+
exports.walletPayer = walletPayer;
|
|
535
|
+
exports.walletSigner = walletSigner;
|
|
536
|
+
exports.walletWithoutSigner = walletWithoutSigner;
|
|
537
|
+
//# sourceMappingURL=index.browser.cjs.map
|
|
538
|
+
//# sourceMappingURL=index.browser.cjs.map
|