@vue-solana/vue 3.0.1 → 4.0.0-rc.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 +10 -4
- package/dist/index.d.ts +12 -0
- package/dist/index.mjs +176 -86
- package/dist/shared/{vue.hG_FieA3.mjs → vue.BHBifdbc.mjs} +2 -2
- package/dist/shared/{vue.CjSw0Hh1.mjs → vue.BTD4usyi.mjs} +4 -4
- package/dist/shared/{vue.CsFY1mfz.mjs → vue.BXNjyJ2c.mjs} +1 -1
- package/dist/shared/{vue.D218Ow7t.mjs → vue.Bc_Kbwr5.mjs} +11 -10
- package/dist/shared/{vue.DlihC5GG.mjs → vue.BiKE9Xuv.mjs} +6 -4
- package/dist/shared/{vue.CXB4NEMA.mjs → vue.Bu2cQ690.mjs} +47 -17
- package/dist/shared/{vue.C1JbUTpJ.mjs → vue.C-7v1l8q.mjs} +2 -2
- package/dist/shared/{vue.CpkwC8Th.mjs → vue.C6OkOK2W.mjs} +1 -1
- package/dist/shared/{vue.B9uRpSDJ.mjs → vue.CAltY57B.mjs} +6 -3
- package/dist/shared/{vue.DDQxNX5q.mjs → vue.CELGI7de.mjs} +9 -9
- package/dist/shared/{vue.BxtOHzY_.mjs → vue.CLAqNcLp.mjs} +1 -1
- package/dist/shared/{vue.Mxc8w6Qk.mjs → vue.CZApWQAY.mjs} +1 -1
- package/dist/shared/vue.CbmzveKF.mjs +44 -0
- package/dist/shared/{vue.CQh3AUE8.mjs → vue.CcOZ9858.mjs} +3 -5
- package/dist/shared/{vue.B-xtuLtD.mjs → vue.D2J7_NpQ.mjs} +2 -2
- package/dist/shared/{vue.BsGwt78R.mjs → vue.D8zNWw2t.mjs} +1 -1
- package/dist/shared/{vue.CaAgH2Xt.mjs → vue.DPwdqRO_.mjs} +3 -3
- package/dist/shared/{vue.DNKD6jqM.mjs → vue.DTpvqDyY.mjs} +3 -3
- package/dist/shared/vue.DZVdVfy1.mjs +7 -0
- package/dist/shared/{vue.CvenSbZZ.mjs → vue.DZhPXLZz.mjs} +4 -4
- package/dist/shared/{vue.BFSboXMB.mjs → vue.DbJKnSrl.mjs} +3 -3
- package/dist/shared/{vue.1Qwco2kv.mjs → vue.DcZ_R_RH.mjs} +4 -4
- package/dist/shared/{vue.o98pAmDg.mjs → vue.Ddf_Cdjx.mjs} +2 -2
- package/dist/shared/{vue.C_4qJDiF.mjs → vue.DyLgoSbX.mjs} +1 -1
- package/dist/shared/{vue.XlfH_nkc.mjs → vue.FehFeE3w.mjs} +3 -3
- package/dist/shared/{vue.C9OOmvkD.mjs → vue.SeuJipQ8.mjs} +2 -2
- package/dist/swr.d.ts +7 -1
- package/dist/swr.mjs +16 -1
- package/dist/useAccountInfo.mjs +1 -1
- package/dist/useAirdrop.mjs +1 -1
- package/dist/useBalance.mjs +1 -1
- package/dist/useClientCapability.d.ts +6 -1
- package/dist/useClientCapability.mjs +1 -1
- package/dist/useConnection.d.ts +14 -7
- package/dist/useConnection.mjs +1 -1
- package/dist/useIdentity.mjs +1 -1
- package/dist/usePayer.mjs +1 -1
- package/dist/usePlanTransaction.mjs +1 -1
- package/dist/usePlanTransactions.mjs +1 -1
- package/dist/useProgramAccounts.mjs +1 -1
- package/dist/useRpc.d.ts +12 -6
- package/dist/useRpc.mjs +1 -1
- package/dist/useSelectedWalletAccount.d.ts +3 -0
- package/dist/useSendTransaction.mjs +1 -1
- package/dist/useSendTransactions.mjs +1 -1
- package/dist/useSignAndSendTransaction.mjs +1 -1
- package/dist/useSignAndSendTransactions.mjs +1 -1
- package/dist/useSignIn.mjs +1 -1
- package/dist/useSignMessage.mjs +1 -1
- package/dist/useSignTransactions.mjs +1 -1
- package/dist/useSignatureStatus.d.ts +0 -1
- package/dist/useSignatureStatus.mjs +1 -1
- package/dist/useSolana.mjs +1 -1
- package/dist/useSolanaClient.d.ts +12 -6
- package/dist/useSolanaClient.mjs +1 -1
- package/dist/useTokenAccounts.mjs +1 -1
- package/dist/useTokenBalance.mjs +1 -1
- package/dist/useTransactionConfirmation.mjs +1 -1
- package/dist/useWallet.mjs +1 -1
- package/dist/useWallets.mjs +1 -1
- package/package.json +8 -5
- package/dist/buffer-polyfill.d.mts +0 -2
- package/dist/index.d.mts +0 -64
- package/dist/kit.d.mts +0 -1
- package/dist/shared/vue.BGGixph-.d.mts +0 -5
- package/dist/shared/vue.Bfu1dCKe.mjs +0 -10
- package/dist/shared/vue.CGv0ip3w.mjs +0 -52
- package/dist/shared/vue.DL3z5PxP.d.mts +0 -21
- package/dist/swr.d.mts +0 -41
- package/dist/useAccountInfo.d.mts +0 -24
- package/dist/useAction.d.mts +0 -45
- package/dist/useAirdrop.d.mts +0 -27
- package/dist/useBalance.d.mts +0 -15
- package/dist/useClientCapability.d.mts +0 -39
- package/dist/useConnection.d.mts +0 -46
- package/dist/useIdentity.d.mts +0 -3
- package/dist/usePayer.d.mts +0 -18
- package/dist/usePlanTransaction.d.mts +0 -44
- package/dist/usePlanTransactions.d.mts +0 -5
- package/dist/useProgramAccounts.d.mts +0 -45
- package/dist/useRequest.d.mts +0 -73
- package/dist/useRpc.d.mts +0 -55
- package/dist/useSelectedWalletAccount.d.mts +0 -117
- package/dist/useSendTransaction.d.mts +0 -50
- package/dist/useSendTransactions.d.mts +0 -5
- package/dist/useSignAndSendTransaction.d.mts +0 -40
- package/dist/useSignAndSendTransactions.d.mts +0 -35
- package/dist/useSignIn.d.mts +0 -23
- package/dist/useSignMessage.d.mts +0 -236
- package/dist/useSignTransactions.d.mts +0 -24
- package/dist/useSignatureStatus.d.mts +0 -26
- package/dist/useSolana.d.mts +0 -9
- package/dist/useSolanaClient.d.mts +0 -45
- package/dist/useSubscription.d.mts +0 -70
- package/dist/useTokenAccounts.d.mts +0 -19
- package/dist/useTokenBalance.d.mts +0 -17
- package/dist/useTrackedData.d.mts +0 -98
- package/dist/useTransaction.d.mts +0 -27
- package/dist/useTransactionConfirmation.d.mts +0 -38
- package/dist/useWallet.d.mts +0 -31
- package/dist/useWallets.d.mts +0 -11
package/README.md
CHANGED
|
@@ -98,7 +98,7 @@ createApp(App).use(
|
|
|
98
98
|
|
|
99
99
|
Supported clusters are `mainnet` (legacy alias `mainnet-beta`), `devnet`, `testnet`, and `localnet`. Use `mainnet` for Solana mainnet; this is Solana's official mainnet cluster name.
|
|
100
100
|
|
|
101
|
-
`payer` and `payerSecretKey` are supported by direct Vue/core clients. A client-sent transaction requires a payer. Never put a raw secret or `payerSecretKey` in Nuxt public runtime config, and never ship a funded signing key to an end-user browser. The default `createSolanaPlugin()` client composes
|
|
101
|
+
`payer` and `payerSecretKey` are supported by direct Vue/core clients. A client-sent transaction requires a payer. Never put a raw secret or `payerSecretKey` in Nuxt public runtime config, and never ship a funded signing key to an end-user browser. The default `createSolanaPlugin()` client composes `solanaRpc()` followed by `rpcAirdrop()`; `solanaRpc()` installs `rpcTransactionPlanner()`, `rpcTransactionPlanSigningExecutor()`, and `rpcTransactionPlanSendingExecutor()` itself, so the client exposes RPC reads and subscriptions plus `planTransaction(s)`, `signTransaction(s)`, and `sendTransaction(s)` with no extra plugin. The old custom fallback sender is not used.
|
|
102
102
|
|
|
103
103
|
### Plugin Options
|
|
104
104
|
|
|
@@ -276,6 +276,8 @@ const { publicKey, connected, connecting, canSignMessage, connect, disconnect }
|
|
|
276
276
|
|
|
277
277
|
Browser extension wallets are discovered through the Solana Wallet Standard. Android Mobile Wallet Adapter wallets are registered through `@solana-mobile/wallet-standard-mobile` and exposed through the same `useWallets()` list on supported Android Chrome clients. iOS Phantom, Solflare, and Backpack entries are exposed through wallet-specific universal links on iOS browsers. `connect()` works after selecting a discovered wallet or configuring a custom `SolanaWallet`.
|
|
278
278
|
|
|
279
|
+
Connecting a wallet also disconnects every other discovered wallet through its `standard:disconnect` feature, so only one wallet stays authorized for the app. An extension the user authorized in an earlier page session can otherwise keep answering signing requests, which is the usual cause of the wrong wallet prompting for a `signMessage` confirmation. A wallet that fails or never answers its disconnect is ignored after a 2 second timeout, and `connect()` resolves only after the sweep finishes.
|
|
280
|
+
|
|
279
281
|
Selected discovered wallets are persisted under `localStorage["vue-solana:selected-wallet"]` as non-sensitive identity metadata: `name`, and `platform`/`source` when available. On reload, Vue Solana restores the selected wallet if the same wallet is discovered again. Pass `autoConnect: true` to opt into calling `connect()` for that restored wallet; arbitrary installed wallets are never auto-connected. Calling `selectWallet(null)` or `setWallet(customWallet)` clears the stored selection.
|
|
280
282
|
|
|
281
283
|
Desktop native app wallet adapters are planned but not implemented yet.
|
|
@@ -312,7 +314,7 @@ async function signIn() {
|
|
|
312
314
|
</template>
|
|
313
315
|
```
|
|
314
316
|
|
|
315
|
-
Message signing proves wallet ownership for flows like authentication challenges. It does not sign, submit, or authorize Solana transactions. For authentication, issue a server-generated nonce, include domain and expiration details in the message, and verify the returned signature server-side.
|
|
317
|
+
Message signing proves wallet ownership for flows like authentication challenges. It does not sign, submit, or authorize Solana transactions. For authentication, issue a server-generated nonce, include domain and expiration details in the message, and verify the returned signature server-side. The adapter also checks the signature against the account's public key before resolving, where Ed25519 (WebCrypto) is available — a best-effort client-side guard that rejects with `INVALID_SIGNATURE`, not a replacement for server-side verification.
|
|
316
318
|
|
|
317
319
|
## Transaction State
|
|
318
320
|
|
|
@@ -391,7 +393,7 @@ Configure a direct client with `payer` or `payerSecretKey`. `payerSecretKey` is
|
|
|
391
393
|
|
|
392
394
|
Use the client flow for automated or server-backed signing (airdrop faucet, cron jobs, relayer fees paid by your keypair), and the wallet flow when the end user must own and approve each transaction.
|
|
393
395
|
|
|
394
|
-
**Default client composition.** `createSolanaPlugin()` and `createSolanaClient()`
|
|
396
|
+
**Default client composition.** `createSolanaPlugin()` and `createSolanaClient()` compose `solanaRpc()` followed by `rpcAirdrop()` by default; `solanaRpc()` installs `rpcTransactionPlanner()`, `rpcTransactionPlanSigningExecutor()`, and `rpcTransactionPlanSendingExecutor()` itself. The old custom fallback sender is not used, so `useSendTransaction()` and `useSendTransactions()` do not need a second manual plugin installation. The official executor waits for `confirmed` commitment before `execute()` resolves and the composable reports `sent`. A custom client must still provide the planner and sending executor and a `payer`.
|
|
395
397
|
|
|
396
398
|
```ts
|
|
397
399
|
import { useSendTransaction } from "@vue-solana/vue/useSendTransaction";
|
|
@@ -488,6 +490,8 @@ import { useRequestSwr } from "@vue-solana/vue/swr";
|
|
|
488
490
|
const balance = useRequestSwr(["balance", address], () => client.rpc.getBalance(address).send());
|
|
489
491
|
```
|
|
490
492
|
|
|
493
|
+
The SWR cache is module-level and shared across the whole app, including across SSR requests. Namespace cache keys per request (for example by including a request or session id) or call `clearSwrCache()` at the start of each server request to avoid leaking one request's cached data into another. On the client the cache is intentionally shared for stale-while-revalidate seeding.
|
|
494
|
+
|
|
491
495
|
### Cancellation & Timeouts
|
|
492
496
|
|
|
493
497
|
`useRequest()`, `useSubscription()`, and `useTrackedData()` accept a `getAbortSignal` option — a factory called once per attempt (request) or connection (subscription/tracked data). It is the natural place for a timeout:
|
|
@@ -592,7 +596,9 @@ Docs: [Vue Solana Agent Skill](https://vue-solana-docs.vercel.app/agent-skill)
|
|
|
592
596
|
| ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
593
597
|
| `createSolanaPlugin(options?)` | Installs the Vue Solana context. |
|
|
594
598
|
| `VueSolana` | Alias for `createSolanaPlugin`. |
|
|
595
|
-
| `useSolana()` | Returns the full injected Solana context.
|
|
599
|
+
| `useSolana()` | Returns the full injected Solana context; throws when no plugin context is available. |
|
|
600
|
+
| `tryUseSolana()` | Returns the injected Solana context or `null` when no plugin context is available (SSR-safe). |
|
|
601
|
+
| `MissingClientCapabilityError` | Thrown by `useClientCapability()` (and client-sent composables) when the configured client lacks a required capability. |
|
|
596
602
|
| `useRpc()` | Returns cluster, endpoint, connection status, latest blockhash, the Kit `client`, and `checkConnection()`. |
|
|
597
603
|
| `useSolanaClient()` | Returns the injected Kit client as `{ client, rpc }`. The recommended RPC path. |
|
|
598
604
|
| `useConnection()` | Returns the Kit `client`. Deprecated in favor of `useSolanaClient()`. |
|
package/dist/index.d.ts
CHANGED
|
@@ -56,6 +56,18 @@ interface VueSolanaPlugin {
|
|
|
56
56
|
* context to consumers that run outside a component setup.
|
|
57
57
|
*/
|
|
58
58
|
context: VueSolanaContext | null;
|
|
59
|
+
/**
|
|
60
|
+
* Stops the wallet discovery subscription and the deferred bootstrap started
|
|
61
|
+
* by `install`. Vue has no plugin unmount hook, so call this from an app
|
|
62
|
+
* teardown hook (`app.onUnmount` in Nuxt, after `app.unmount()` in Vue).
|
|
63
|
+
* Safe to call more than once and before `install`. Without it the Wallet
|
|
64
|
+
* Standard subscription outlives the app that created it. After `dispose()`,
|
|
65
|
+
* `refreshWallets()` is a no-op, so a late mobile-wallet import or manual
|
|
66
|
+
* call cannot resurrect the subscription. A connected wallet stays
|
|
67
|
+
* connected; `dispose()` does not disconnect it or abort an in-flight
|
|
68
|
+
* `connect()`.
|
|
69
|
+
*/
|
|
70
|
+
dispose(): void;
|
|
59
71
|
}
|
|
60
72
|
declare function createSolanaPlugin(options?: VueSolanaPluginOptions): VueSolanaPlugin;
|
|
61
73
|
declare const VueSolana: typeof createSolanaPlugin;
|
package/dist/index.mjs
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
export { u as useAccountInfo } from './shared/vue.
|
|
1
|
+
export { u as useAccountInfo } from './shared/vue.DZhPXLZz.mjs';
|
|
2
2
|
export { u as useAction } from './shared/vue.DYk0Xfr3.mjs';
|
|
3
|
-
export { u as useAirdrop } from './shared/vue.
|
|
4
|
-
export { u as useBalance } from './shared/vue.
|
|
5
|
-
export { M as MissingClientCapabilityError, u as useClientCapability } from './shared/vue.
|
|
6
|
-
export { u as useConnection } from './shared/vue.
|
|
7
|
-
export { u as usePlanTransaction, a as usePlanTransactions } from './shared/vue.
|
|
8
|
-
export { u as useProgramAccounts } from './shared/vue.
|
|
9
|
-
export { u as useIdentity, a as usePayer } from './shared/vue.
|
|
3
|
+
export { u as useAirdrop } from './shared/vue.CELGI7de.mjs';
|
|
4
|
+
export { u as useBalance } from './shared/vue.DbJKnSrl.mjs';
|
|
5
|
+
export { M as MissingClientCapabilityError, u as useClientCapability } from './shared/vue.CAltY57B.mjs';
|
|
6
|
+
export { u as useConnection } from './shared/vue.C6OkOK2W.mjs';
|
|
7
|
+
export { u as usePlanTransaction, a as usePlanTransactions } from './shared/vue.BXNjyJ2c.mjs';
|
|
8
|
+
export { u as useProgramAccounts } from './shared/vue.DcZ_R_RH.mjs';
|
|
9
|
+
export { u as useIdentity, a as usePayer } from './shared/vue.D2J7_NpQ.mjs';
|
|
10
10
|
export { u as useRequest } from './shared/vue.B8VvC8d2.mjs';
|
|
11
|
-
export { u as useRpc } from './shared/vue.
|
|
11
|
+
export { u as useRpc } from './shared/vue.D8zNWw2t.mjs';
|
|
12
12
|
export { S as SelectedWalletAccountProvider, c as createSelectedWalletAccountContext, p as provideSelectedWalletAccount, s as selectedWalletAccountInjectionKey, u as useSelectedWalletAccount } from './shared/vue.BngCaeXJ.mjs';
|
|
13
|
-
export { u as useSendTransaction, a as useSendTransactions } from './shared/vue.
|
|
14
|
-
export { u as useSignMessage } from './shared/vue.
|
|
15
|
-
export { u as useSignAndSendTransaction } from './shared/vue.
|
|
16
|
-
export { u as useSignTransactions } from './shared/vue.
|
|
17
|
-
export { P as PartialSignAndSendError, u as useSignAndSendTransactions } from './shared/vue.
|
|
18
|
-
export { u as useSignatureStatus } from './shared/vue.
|
|
19
|
-
export { u as useSignIn } from './shared/vue.
|
|
20
|
-
export { t as tryUseSolana, u as useSolana } from './shared/vue.
|
|
21
|
-
export { u as useSolanaClient } from './shared/vue.
|
|
13
|
+
export { u as useSendTransaction, a as useSendTransactions } from './shared/vue.CLAqNcLp.mjs';
|
|
14
|
+
export { u as useSignMessage } from './shared/vue.Ddf_Cdjx.mjs';
|
|
15
|
+
export { u as useSignAndSendTransaction } from './shared/vue.BTD4usyi.mjs';
|
|
16
|
+
export { u as useSignTransactions } from './shared/vue.BHBifdbc.mjs';
|
|
17
|
+
export { P as PartialSignAndSendError, u as useSignAndSendTransactions } from './shared/vue.C-7v1l8q.mjs';
|
|
18
|
+
export { u as useSignatureStatus } from './shared/vue.Bu2cQ690.mjs';
|
|
19
|
+
export { u as useSignIn } from './shared/vue.SeuJipQ8.mjs';
|
|
20
|
+
export { t as tryUseSolana, u as useSolana } from './shared/vue.CcOZ9858.mjs';
|
|
21
|
+
export { u as useSolanaClient } from './shared/vue.CZApWQAY.mjs';
|
|
22
22
|
export { u as useSubscription } from './shared/vue.D5pqR5Fa.mjs';
|
|
23
|
-
export { u as useTokenAccounts } from './shared/vue.
|
|
24
|
-
export { u as useTokenBalance } from './shared/vue.
|
|
23
|
+
export { u as useTokenAccounts } from './shared/vue.DTpvqDyY.mjs';
|
|
24
|
+
export { u as useTokenBalance } from './shared/vue.FehFeE3w.mjs';
|
|
25
25
|
export { u as useTrackedData } from './shared/vue.BNJTXSnQ.mjs';
|
|
26
26
|
export { u as useTransaction } from './shared/vue.5euWd6-V.mjs';
|
|
27
|
-
export { g as getConfirmedTransactionStatus, u as useTransactionConfirmation } from './shared/vue.
|
|
28
|
-
export { u as useWallet } from './shared/vue.
|
|
29
|
-
export { u as useWallets } from './shared/vue.
|
|
27
|
+
export { g as getConfirmedTransactionStatus, u as useTransactionConfirmation } from './shared/vue.DPwdqRO_.mjs';
|
|
28
|
+
export { u as useWallet } from './shared/vue.Bc_Kbwr5.mjs';
|
|
29
|
+
export { u as useWallets } from './shared/vue.DyLgoSbX.mjs';
|
|
30
30
|
import { s as solanaInjectionKey } from './shared/vue.D_P5SqqD.mjs';
|
|
31
31
|
import { createSolanaError, normalizeSolanaError } from '@vue-solana/core/errors';
|
|
32
32
|
export { SolanaError, isSolanaError } from '@vue-solana/core/errors';
|
|
33
33
|
import { isSolanaMobileWalletSupported } from '@vue-solana/core/mobile-wallet-support';
|
|
34
34
|
import { createSolanaContext } from '@vue-solana/core/rpc';
|
|
35
35
|
import { withTimeout } from '@vue-solana/core/timeout';
|
|
36
|
-
import { getRegisteredSolanaWallets, getSolanaChain, adaptSolanaStandardWallet, subscribeSolanaWallets } from '@vue-solana/core/wallet-standard';
|
|
36
|
+
import { getRegisteredSolanaWallets, getSolanaChain, adaptSolanaStandardWallet, disconnectSolanaStandardWallet, subscribeSolanaWallets } from '@vue-solana/core/wallet-standard';
|
|
37
37
|
import { shallowRef, ref, triggerRef } from 'vue';
|
|
38
38
|
import { handleSolanaIosWalletCallback, getSolanaIosWallets, isSolanaIosWalletInfo, adaptSolanaIosWallet } from '@vue-solana/core/ios-wallet';
|
|
39
39
|
export * from '@vue-solana/core/types';
|
|
@@ -112,50 +112,65 @@ function getLocalStorage() {
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
const DISCONNECT_TIMEOUT_MS = 2e3;
|
|
115
116
|
function createSolanaWalletRegistry(options) {
|
|
116
117
|
const adaptedWallets = /* @__PURE__ */ new WeakMap();
|
|
118
|
+
const adaptedPrimitiveWallets = /* @__PURE__ */ new Map();
|
|
119
|
+
const trackedAdapters = /* @__PURE__ */ new Set();
|
|
120
|
+
function trackAdapter(adapter) {
|
|
121
|
+
trackedAdapters.add(adapter);
|
|
122
|
+
return adapter;
|
|
123
|
+
}
|
|
117
124
|
function getAdaptedWallet(walletInfo) {
|
|
118
125
|
if (isSolanaIosWalletInfo(walletInfo)) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
126
|
+
const cachedIosWallet = adaptedWallets.get(walletInfo.wallet);
|
|
127
|
+
if (cachedIosWallet) {
|
|
128
|
+
return cachedIosWallet;
|
|
129
|
+
}
|
|
130
|
+
const iosAdapter = makeConnectExclusive(
|
|
131
|
+
adaptSolanaIosWallet(walletInfo, {
|
|
132
|
+
chain: getSolanaChain(options.cluster),
|
|
133
|
+
cluster: options.cluster,
|
|
134
|
+
onChange: options.onWalletChange,
|
|
135
|
+
...options.iosWallet || {}
|
|
136
|
+
}),
|
|
137
|
+
walletInfo
|
|
138
|
+
);
|
|
139
|
+
adaptedWallets.set(walletInfo.wallet, iosAdapter);
|
|
140
|
+
return trackAdapter(iosAdapter);
|
|
125
141
|
}
|
|
126
142
|
if (!isObject(walletInfo.wallet)) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
143
|
+
const primitiveKey = getPrimitiveWalletKey(walletInfo);
|
|
144
|
+
const cachedPrimitiveWallet = adaptedPrimitiveWallets.get(primitiveKey);
|
|
145
|
+
if (cachedPrimitiveWallet) {
|
|
146
|
+
return cachedPrimitiveWallet;
|
|
147
|
+
}
|
|
148
|
+
const primitiveAdapter = makeConnectExclusive(
|
|
149
|
+
adaptSolanaStandardWallet(walletInfo, {
|
|
150
|
+
chain: getSolanaChain(options.cluster),
|
|
151
|
+
onChange: options.onWalletChange
|
|
152
|
+
}),
|
|
153
|
+
walletInfo
|
|
154
|
+
);
|
|
155
|
+
adaptedPrimitiveWallets.set(primitiveKey, primitiveAdapter);
|
|
156
|
+
return trackAdapter(primitiveAdapter);
|
|
131
157
|
}
|
|
132
158
|
const cachedWallet = adaptedWallets.get(walletInfo.wallet);
|
|
133
159
|
if (cachedWallet) {
|
|
134
160
|
return cachedWallet;
|
|
135
161
|
}
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return connectAndDisconnectOthers;
|
|
144
|
-
}
|
|
145
|
-
const value = Reflect.get(target, property);
|
|
146
|
-
return typeof value === "function" ? value.bind(target) : value;
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
async function connectAndDisconnectOthers() {
|
|
150
|
-
await adaptedWallet.connect();
|
|
151
|
-
await Promise.all(
|
|
152
|
-
Array.from(getCachedWallets()).map(
|
|
153
|
-
(otherWallet) => otherWallet !== cachedAdapter && otherWallet.connected ? otherWallet.disconnect() : void 0
|
|
154
|
-
)
|
|
155
|
-
);
|
|
156
|
-
}
|
|
162
|
+
const cachedAdapter = makeConnectExclusive(
|
|
163
|
+
adaptSolanaStandardWallet(walletInfo, {
|
|
164
|
+
chain: getSolanaChain(options.cluster),
|
|
165
|
+
onChange: options.onWalletChange
|
|
166
|
+
}),
|
|
167
|
+
walletInfo
|
|
168
|
+
);
|
|
157
169
|
adaptedWallets.set(walletInfo.wallet, cachedAdapter);
|
|
158
|
-
return cachedAdapter;
|
|
170
|
+
return trackAdapter(cachedAdapter);
|
|
171
|
+
}
|
|
172
|
+
function getCachedAdapter(walletInfo) {
|
|
173
|
+
return isObject(walletInfo.wallet) ? adaptedWallets.get(walletInfo.wallet) : adaptedPrimitiveWallets.get(getPrimitiveWalletKey(walletInfo));
|
|
159
174
|
}
|
|
160
175
|
function getDiscoveredWallets() {
|
|
161
176
|
return [
|
|
@@ -171,31 +186,67 @@ function createSolanaWalletRegistry(options) {
|
|
|
171
186
|
try {
|
|
172
187
|
handleSolanaIosWalletCallback({ clearUrl: true });
|
|
173
188
|
} catch (cause) {
|
|
174
|
-
|
|
189
|
+
options.onError?.(cause);
|
|
175
190
|
}
|
|
176
191
|
}
|
|
177
|
-
function
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
192
|
+
function makeConnectExclusive(adapter, walletInfo) {
|
|
193
|
+
const connect = adapter.connect.bind(adapter);
|
|
194
|
+
adapter.connect = async () => {
|
|
195
|
+
await connect();
|
|
196
|
+
await disconnectOtherWallets(walletInfo, adapter);
|
|
197
|
+
};
|
|
198
|
+
return adapter;
|
|
199
|
+
}
|
|
200
|
+
async function disconnectOtherWallets(currentWallet, currentAdapter) {
|
|
201
|
+
await Promise.all(
|
|
202
|
+
options.getWalletInfos().map(async (walletInfo) => {
|
|
203
|
+
const cachedWallet = getCachedAdapter(walletInfo);
|
|
204
|
+
if (cachedWallet === currentAdapter || isSameWalletInfo(walletInfo, currentWallet)) {
|
|
205
|
+
return;
|
|
183
206
|
}
|
|
184
|
-
|
|
207
|
+
try {
|
|
208
|
+
await withTimeout(
|
|
209
|
+
disconnectWallet(walletInfo, cachedWallet),
|
|
210
|
+
DISCONNECT_TIMEOUT_MS,
|
|
211
|
+
() => new Error(`Solana wallet "${walletInfo.name}" did not disconnect within its timeout`)
|
|
212
|
+
);
|
|
213
|
+
} catch {
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
async function disconnectWallet(walletInfo, cachedWallet) {
|
|
219
|
+
if (cachedWallet) {
|
|
220
|
+
await cachedWallet.disconnect();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
await disconnectSolanaStandardWallet(walletInfo);
|
|
224
|
+
}
|
|
225
|
+
function disposeAllAdaptedWallets() {
|
|
226
|
+
for (const adapter of trackedAdapters) {
|
|
227
|
+
adapter.dispose?.();
|
|
185
228
|
}
|
|
186
229
|
}
|
|
187
230
|
return {
|
|
188
231
|
getAdaptedWallet,
|
|
189
232
|
getDiscoveredWallets,
|
|
190
|
-
handleIosWalletCallback
|
|
233
|
+
handleIosWalletCallback,
|
|
234
|
+
disposeAllAdaptedWallets
|
|
191
235
|
};
|
|
192
236
|
}
|
|
193
237
|
function isObject(value) {
|
|
194
238
|
return typeof value === "object" && value !== null || typeof value === "function";
|
|
195
239
|
}
|
|
240
|
+
function getPrimitiveWalletKey(walletInfo) {
|
|
241
|
+
return `${walletInfo.name}::${String(walletInfo.wallet)}`;
|
|
242
|
+
}
|
|
243
|
+
function isSameWalletInfo(a, b) {
|
|
244
|
+
return a.wallet === b.wallet || a.name === b.name && a.source === b.source;
|
|
245
|
+
}
|
|
196
246
|
|
|
197
247
|
const RPC_CHECK_TIMEOUT_MS = 1e4;
|
|
198
248
|
function createSolanaPlugin(options = {}) {
|
|
249
|
+
let teardown = null;
|
|
199
250
|
const plugin = {
|
|
200
251
|
context: null,
|
|
201
252
|
install(app) {
|
|
@@ -210,21 +261,22 @@ function createSolanaPlugin(options = {}) {
|
|
|
210
261
|
cluster: context.cluster,
|
|
211
262
|
iosWallet: options.iosWallet,
|
|
212
263
|
getWalletInfos: () => wallets.value,
|
|
213
|
-
onWalletChange: () => triggerRef(wallet)
|
|
264
|
+
onWalletChange: () => triggerRef(wallet),
|
|
265
|
+
onError: (cause) => {
|
|
266
|
+
error.value = normalizeSolanaError(cause, "WALLET_FAILURE");
|
|
267
|
+
logDevError("Failed to handle Solana iOS wallet callback", cause);
|
|
268
|
+
}
|
|
214
269
|
});
|
|
215
270
|
let unsubscribeWallets = null;
|
|
216
271
|
let mobileWalletRegistrationPromise = null;
|
|
217
272
|
let attemptedAutoConnectWallet = null;
|
|
218
273
|
let rpcCheckId = 0;
|
|
274
|
+
let bootstrapId = 0;
|
|
275
|
+
let disposed = false;
|
|
219
276
|
async function checkConnection() {
|
|
220
277
|
const checkId = ++rpcCheckId;
|
|
221
278
|
status.value = "checking";
|
|
222
279
|
error.value = null;
|
|
223
|
-
console.info("[Vue Solana] Checking RPC connection", {
|
|
224
|
-
cluster: context.cluster,
|
|
225
|
-
endpoint: context.endpoint,
|
|
226
|
-
wsEndpoint: context.wsEndpoint
|
|
227
|
-
});
|
|
228
280
|
try {
|
|
229
281
|
const response = await withTimeout(
|
|
230
282
|
context.client.rpc.getLatestBlockhash().send(),
|
|
@@ -239,22 +291,19 @@ function createSolanaPlugin(options = {}) {
|
|
|
239
291
|
}
|
|
240
292
|
latestBlockhash.value = blockhash.blockhash;
|
|
241
293
|
status.value = "connected";
|
|
242
|
-
console.info("[Vue Solana] Connected", {
|
|
243
|
-
cluster: context.cluster,
|
|
244
|
-
endpoint: context.endpoint,
|
|
245
|
-
wsEndpoint: context.wsEndpoint,
|
|
246
|
-
blockhash
|
|
247
|
-
});
|
|
248
294
|
} catch (cause) {
|
|
249
295
|
if (checkId !== rpcCheckId) {
|
|
250
296
|
return;
|
|
251
297
|
}
|
|
252
298
|
status.value = "error";
|
|
253
299
|
error.value = normalizeSolanaError(cause, "RPC_FAILURE");
|
|
254
|
-
|
|
300
|
+
logDevError("Connection failed", cause);
|
|
255
301
|
}
|
|
256
302
|
}
|
|
257
303
|
function refreshWallets() {
|
|
304
|
+
if (disposed) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
258
307
|
unsubscribeWallets ??= subscribeSolanaWallets(refreshWallets);
|
|
259
308
|
walletRegistry.handleIosWalletCallback();
|
|
260
309
|
wallets.value = walletRegistry.getDiscoveredWallets();
|
|
@@ -268,7 +317,7 @@ function createSolanaPlugin(options = {}) {
|
|
|
268
317
|
const persistedWallet = readSelectedWallet();
|
|
269
318
|
if (persistedWallet.error) {
|
|
270
319
|
error.value = persistedWallet.error;
|
|
271
|
-
|
|
320
|
+
logDevError("Failed to read the persisted Solana wallet", persistedWallet.error);
|
|
272
321
|
}
|
|
273
322
|
restoredWallet = persistedWallet.wallet ? wallets.value.find(
|
|
274
323
|
(nextWallet) => isSameWallet(nextWallet, persistedWallet.wallet)
|
|
@@ -286,14 +335,21 @@ function createSolanaPlugin(options = {}) {
|
|
|
286
335
|
}
|
|
287
336
|
}
|
|
288
337
|
function registerMobileWallets() {
|
|
338
|
+
if (disposed) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
289
341
|
mobileWalletRegistrationPromise ??= import('@vue-solana/core/mobile-wallet').then(({ registerSolanaMobileWallet }) => {
|
|
342
|
+
if (disposed) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
290
345
|
registerSolanaMobileWallet({
|
|
291
346
|
chains: [getSolanaChain(context.cluster)],
|
|
292
347
|
...options.mobileWallet || {}
|
|
293
348
|
});
|
|
294
349
|
refreshWallets();
|
|
295
350
|
}).catch((cause) => {
|
|
296
|
-
|
|
351
|
+
error.value = normalizeSolanaError(cause, "WALLET_FAILURE");
|
|
352
|
+
logDevError("Failed to register Solana mobile wallet", cause);
|
|
297
353
|
}).finally(() => {
|
|
298
354
|
mobileWalletRegistrationPromise = null;
|
|
299
355
|
});
|
|
@@ -304,7 +360,7 @@ function createSolanaPlugin(options = {}) {
|
|
|
304
360
|
const storageError = writeSelectedWallet(nextWallet);
|
|
305
361
|
if (storageError) {
|
|
306
362
|
error.value = storageError;
|
|
307
|
-
|
|
363
|
+
logDevError("Failed to persist the selected Solana wallet", storageError);
|
|
308
364
|
}
|
|
309
365
|
}
|
|
310
366
|
function autoConnectWallet(walletInfo) {
|
|
@@ -318,7 +374,8 @@ function createSolanaPlugin(options = {}) {
|
|
|
318
374
|
}
|
|
319
375
|
attemptedAutoConnectWallet = storageValue;
|
|
320
376
|
void activeWallet.connect().catch((cause) => {
|
|
321
|
-
|
|
377
|
+
error.value = normalizeSolanaError(cause, "WALLET_FAILURE");
|
|
378
|
+
logDevError("Failed to auto-connect Solana wallet", cause);
|
|
322
379
|
}).finally(() => {
|
|
323
380
|
triggerRef(wallet);
|
|
324
381
|
});
|
|
@@ -340,22 +397,37 @@ function createSolanaPlugin(options = {}) {
|
|
|
340
397
|
const storageError = writeSelectedWallet(null);
|
|
341
398
|
if (storageError) {
|
|
342
399
|
error.value = storageError;
|
|
343
|
-
|
|
400
|
+
logDevError("Failed to clear the persisted Solana wallet", storageError);
|
|
344
401
|
}
|
|
345
402
|
}
|
|
346
403
|
};
|
|
347
404
|
app.provide(solanaInjectionKey, vueContext);
|
|
348
405
|
plugin.context = vueContext;
|
|
406
|
+
teardown = () => {
|
|
407
|
+
disposed = true;
|
|
408
|
+
if (typeof window !== "undefined") {
|
|
409
|
+
window.clearTimeout(bootstrapId);
|
|
410
|
+
}
|
|
411
|
+
unsubscribeWallets?.();
|
|
412
|
+
unsubscribeWallets = null;
|
|
413
|
+
walletRegistry.disposeAllAdaptedWallets();
|
|
414
|
+
rpcCheckId += 1;
|
|
415
|
+
teardown = null;
|
|
416
|
+
};
|
|
349
417
|
if (typeof window !== "undefined") {
|
|
350
|
-
window.setTimeout(() => {
|
|
418
|
+
bootstrapId = window.setTimeout(() => {
|
|
419
|
+
void checkConnection();
|
|
351
420
|
try {
|
|
352
421
|
refreshWallets();
|
|
353
422
|
} catch (cause) {
|
|
354
|
-
|
|
423
|
+
error.value = normalizeSolanaError(cause, "WALLET_FAILURE");
|
|
424
|
+
logDevError("Failed to refresh Solana wallets", cause);
|
|
355
425
|
}
|
|
356
|
-
void checkConnection();
|
|
357
426
|
}, 0);
|
|
358
427
|
}
|
|
428
|
+
},
|
|
429
|
+
dispose() {
|
|
430
|
+
teardown?.();
|
|
359
431
|
}
|
|
360
432
|
};
|
|
361
433
|
return plugin;
|
|
@@ -363,6 +435,24 @@ function createSolanaPlugin(options = {}) {
|
|
|
363
435
|
function isSameWallet(wallet, selectedWallet) {
|
|
364
436
|
return wallet.name === selectedWallet?.name && wallet.source === selectedWallet.source && wallet.platform === selectedWallet.platform;
|
|
365
437
|
}
|
|
438
|
+
function isDevEnvironment() {
|
|
439
|
+
try {
|
|
440
|
+
if (import.meta.env?.DEV === true) {
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
} catch {
|
|
444
|
+
}
|
|
445
|
+
if (typeof process === "undefined") {
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
const mode = process.env?.NODE_ENV;
|
|
449
|
+
return mode === "development" || mode === "test";
|
|
450
|
+
}
|
|
451
|
+
function logDevError(message, cause) {
|
|
452
|
+
if (isDevEnvironment()) {
|
|
453
|
+
console.error(`[Vue Solana] ${message}`, cause);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
366
456
|
const VueSolana = createSolanaPlugin;
|
|
367
457
|
|
|
368
458
|
export { VueSolana, createSolanaPlugin, solanaInjectionKey };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createNoWalletSelectedError, assertWalletCanSignTransactions } from '@vue-solana/core/wallet';
|
|
2
2
|
import { shallowRef } from 'vue';
|
|
3
|
-
import { u as useExecution } from './vue.
|
|
4
|
-
import { u as useWallet } from './vue.
|
|
3
|
+
import { u as useExecution } from './vue.BiKE9Xuv.mjs';
|
|
4
|
+
import { u as useWallet } from './vue.Bc_Kbwr5.mjs';
|
|
5
5
|
|
|
6
6
|
function useSignTransactions() {
|
|
7
7
|
const { wallet } = useWallet();
|
|
@@ -3,13 +3,13 @@ import { withSolanaTimeout } from '@vue-solana/core/timeout';
|
|
|
3
3
|
import { signAndSendTransaction, confirmTransactionSignature } from '@vue-solana/core/transaction';
|
|
4
4
|
import { createNoWalletSelectedError } from '@vue-solana/core/wallet';
|
|
5
5
|
import { ref, computed } from 'vue';
|
|
6
|
-
import { u as
|
|
7
|
-
import { u as useWallet } from './vue.
|
|
8
|
-
import { g as getConfirmedTransactionStatus } from './vue.
|
|
6
|
+
import { u as useSolanaClient } from './vue.CZApWQAY.mjs';
|
|
7
|
+
import { u as useWallet } from './vue.Bc_Kbwr5.mjs';
|
|
8
|
+
import { g as getConfirmedTransactionStatus } from './vue.DPwdqRO_.mjs';
|
|
9
9
|
|
|
10
10
|
const SIGN_AND_SEND_TIMEOUT_MS = 12e4;
|
|
11
11
|
function useSignAndSendTransaction() {
|
|
12
|
-
const client =
|
|
12
|
+
const client = useSolanaClient().client;
|
|
13
13
|
const { wallet } = useWallet();
|
|
14
14
|
const signature = ref(null);
|
|
15
15
|
const confirmation = ref(null);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u as useClientAction } from './vue.
|
|
1
|
+
import { u as useClientAction } from './vue.CbmzveKF.mjs';
|
|
2
2
|
|
|
3
3
|
const PLANNING_PROVIDER_HINT = "Install a planner plugin, e.g. `createClient().use(rpcTransactionPlanner())` from `@solana/kit-plugin-rpc`, and plan with a client that has a `payer` signer \u2014 Kit reads `client.payer` to set the fee payer.";
|
|
4
4
|
const PLAN_STATUSES = {
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { normalizeSolanaError } from '@vue-solana/core/errors';
|
|
2
2
|
import { createNoWalletSelectedError, assertWalletConnected } from '@vue-solana/core/wallet';
|
|
3
3
|
import { ref, computed, triggerRef } from 'vue';
|
|
4
|
-
import { u as useSolana } from './vue.
|
|
4
|
+
import { u as useSolana } from './vue.CcOZ9858.mjs';
|
|
5
5
|
|
|
6
6
|
function useWallet() {
|
|
7
7
|
const solana = useSolana();
|
|
8
8
|
const wallet = solana.wallet;
|
|
9
9
|
const connecting = ref(false);
|
|
10
10
|
const disconnecting = ref(false);
|
|
11
|
+
function clearWalletError() {
|
|
12
|
+
const current = solana.error.value;
|
|
13
|
+
if (current?.code === "WALLET_FAILURE" || current?.code === "USER_REJECTED") {
|
|
14
|
+
solana.error.value = null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
11
17
|
async function connect() {
|
|
12
18
|
if (connecting.value || wallet.value?.connecting) {
|
|
13
19
|
return;
|
|
@@ -22,14 +28,11 @@ function useWallet() {
|
|
|
22
28
|
triggerRef(wallet);
|
|
23
29
|
await connection;
|
|
24
30
|
assertWalletConnected(activeWallet);
|
|
31
|
+
clearWalletError();
|
|
25
32
|
triggerRef(wallet);
|
|
26
|
-
console.info("[Vue Solana] Wallet connected", {
|
|
27
|
-
publicKey: activeWallet.publicKey ?? null
|
|
28
|
-
});
|
|
29
33
|
} catch (error) {
|
|
30
|
-
const normalizedError = normalizeSolanaError(error, "
|
|
34
|
+
const normalizedError = normalizeSolanaError(error, "WALLET_FAILURE");
|
|
31
35
|
triggerRef(wallet);
|
|
32
|
-
console.error("[Vue Solana] Wallet connection failed", normalizedError);
|
|
33
36
|
throw normalizedError;
|
|
34
37
|
} finally {
|
|
35
38
|
connecting.value = false;
|
|
@@ -40,16 +43,14 @@ function useWallet() {
|
|
|
40
43
|
if (!activeWallet) {
|
|
41
44
|
return;
|
|
42
45
|
}
|
|
43
|
-
const publicKey = activeWallet.publicKey ?? null;
|
|
44
46
|
disconnecting.value = true;
|
|
45
47
|
try {
|
|
46
48
|
await activeWallet.disconnect();
|
|
49
|
+
clearWalletError();
|
|
47
50
|
triggerRef(wallet);
|
|
48
|
-
console.info("[Vue Solana] Wallet disconnected", { publicKey });
|
|
49
51
|
} catch (error) {
|
|
50
|
-
const normalizedError = normalizeSolanaError(error, "
|
|
52
|
+
const normalizedError = normalizeSolanaError(error, "WALLET_FAILURE");
|
|
51
53
|
triggerRef(wallet);
|
|
52
|
-
console.error("[Vue Solana] Wallet disconnection failed", normalizedError);
|
|
53
54
|
throw normalizedError;
|
|
54
55
|
} finally {
|
|
55
56
|
disconnecting.value = false;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { normalizeSolanaError } from '@vue-solana/core/errors';
|
|
2
2
|
import { shallowRef, onScopeDispose, computed } from 'vue';
|
|
3
3
|
|
|
4
|
-
function useExecution(busy) {
|
|
5
|
-
const
|
|
4
|
+
function useExecution(busy, statuses = {}) {
|
|
5
|
+
const errorStatus = statuses.error ?? "error";
|
|
6
|
+
const idleStatus = statuses.idle ?? "idle";
|
|
7
|
+
const status = shallowRef(idleStatus);
|
|
6
8
|
const error = shallowRef(null);
|
|
7
9
|
let id = 0;
|
|
8
10
|
async function execute(run, settled) {
|
|
@@ -19,14 +21,14 @@ function useExecution(busy) {
|
|
|
19
21
|
const normalizedError = normalizeSolanaError(cause, "RPC_FAILURE");
|
|
20
22
|
if (currentId === id) {
|
|
21
23
|
error.value = normalizedError;
|
|
22
|
-
status.value =
|
|
24
|
+
status.value = errorStatus;
|
|
23
25
|
}
|
|
24
26
|
throw normalizedError;
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
function reset() {
|
|
28
30
|
id += 1;
|
|
29
|
-
status.value =
|
|
31
|
+
status.value = idleStatus;
|
|
30
32
|
error.value = null;
|
|
31
33
|
}
|
|
32
34
|
onScopeDispose(() => {
|