@vue-solana/vue 3.0.0 → 4.0.0-rc.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 (110) hide show
  1. package/README.md +8 -4
  2. package/dist/index.d.ts +12 -0
  3. package/dist/index.mjs +81 -58
  4. package/dist/shared/{vue.CjSw0Hh1.mjs → vue.4ne5EBD9.mjs} +4 -4
  5. package/dist/shared/{vue.C9OOmvkD.mjs → vue.BBN9aU6D.mjs} +2 -2
  6. package/dist/shared/{vue.CsFY1mfz.mjs → vue.BXNjyJ2c.mjs} +1 -1
  7. package/dist/shared/{vue.DlihC5GG.mjs → vue.BiKE9Xuv.mjs} +6 -4
  8. package/dist/shared/{vue.CXB4NEMA.mjs → vue.Bu2cQ690.mjs} +47 -17
  9. package/dist/shared/{vue.CpkwC8Th.mjs → vue.C6OkOK2W.mjs} +1 -1
  10. package/dist/shared/{vue.B9uRpSDJ.mjs → vue.CAltY57B.mjs} +6 -3
  11. package/dist/shared/{vue.DDQxNX5q.mjs → vue.CELGI7de.mjs} +9 -9
  12. package/dist/shared/{vue.BxtOHzY_.mjs → vue.CLAqNcLp.mjs} +1 -1
  13. package/dist/shared/{vue.hG_FieA3.mjs → vue.CW-1AuSO.mjs} +2 -2
  14. package/dist/shared/{vue.Mxc8w6Qk.mjs → vue.CZApWQAY.mjs} +1 -1
  15. package/dist/shared/vue.CbmzveKF.mjs +44 -0
  16. package/dist/shared/{vue.CQh3AUE8.mjs → vue.CcOZ9858.mjs} +3 -5
  17. package/dist/shared/{vue.B-xtuLtD.mjs → vue.D2J7_NpQ.mjs} +2 -2
  18. package/dist/shared/{vue.BsGwt78R.mjs → vue.D8zNWw2t.mjs} +1 -1
  19. package/dist/shared/{vue.CaAgH2Xt.mjs → vue.DPwdqRO_.mjs} +3 -3
  20. package/dist/shared/{vue.DNKD6jqM.mjs → vue.DTpvqDyY.mjs} +3 -3
  21. package/dist/shared/{vue.D218Ow7t.mjs → vue.DY9VadLH.mjs} +1 -8
  22. package/dist/shared/vue.DZVdVfy1.mjs +7 -0
  23. package/dist/shared/{vue.CvenSbZZ.mjs → vue.DZhPXLZz.mjs} +4 -4
  24. package/dist/shared/{vue.o98pAmDg.mjs → vue.DbJG4-ku.mjs} +2 -2
  25. package/dist/shared/{vue.BFSboXMB.mjs → vue.DbJKnSrl.mjs} +3 -3
  26. package/dist/shared/{vue.1Qwco2kv.mjs → vue.DcZ_R_RH.mjs} +4 -4
  27. package/dist/shared/{vue.C_4qJDiF.mjs → vue.DyLgoSbX.mjs} +1 -1
  28. package/dist/shared/{vue.XlfH_nkc.mjs → vue.FehFeE3w.mjs} +3 -3
  29. package/dist/shared/{vue.C1JbUTpJ.mjs → vue.UrCjmf0T.mjs} +2 -2
  30. package/dist/swr.d.ts +7 -1
  31. package/dist/swr.mjs +16 -4
  32. package/dist/useAccountInfo.mjs +1 -10
  33. package/dist/useAction.mjs +0 -2
  34. package/dist/useAirdrop.mjs +1 -8
  35. package/dist/useBalance.mjs +1 -9
  36. package/dist/useClientCapability.d.ts +6 -1
  37. package/dist/useClientCapability.mjs +1 -5
  38. package/dist/useConnection.d.ts +8 -1
  39. package/dist/useConnection.mjs +1 -5
  40. package/dist/useIdentity.mjs +1 -6
  41. package/dist/usePayer.mjs +1 -6
  42. package/dist/usePlanTransaction.mjs +1 -8
  43. package/dist/usePlanTransactions.mjs +1 -8
  44. package/dist/useProgramAccounts.mjs +1 -10
  45. package/dist/useRequest.mjs +0 -4
  46. package/dist/useRpc.d.ts +6 -0
  47. package/dist/useRpc.mjs +1 -4
  48. package/dist/useSelectedWalletAccount.d.ts +3 -0
  49. package/dist/useSelectedWalletAccount.mjs +0 -2
  50. package/dist/useSendTransaction.mjs +1 -8
  51. package/dist/useSendTransactions.mjs +1 -8
  52. package/dist/useSignAndSendTransaction.mjs +1 -13
  53. package/dist/useSignAndSendTransactions.mjs +1 -9
  54. package/dist/useSignIn.mjs +1 -8
  55. package/dist/useSignMessage.mjs +1 -8
  56. package/dist/useSignTransactions.mjs +1 -8
  57. package/dist/useSignatureStatus.d.ts +0 -1
  58. package/dist/useSignatureStatus.mjs +1 -8
  59. package/dist/useSolana.mjs +1 -3
  60. package/dist/useSolanaClient.d.ts +6 -0
  61. package/dist/useSolanaClient.mjs +1 -4
  62. package/dist/useSubscription.mjs +0 -2
  63. package/dist/useTokenAccounts.mjs +1 -10
  64. package/dist/useTokenBalance.mjs +1 -10
  65. package/dist/useTrackedData.mjs +0 -3
  66. package/dist/useTransaction.mjs +0 -4
  67. package/dist/useTransactionConfirmation.mjs +1 -9
  68. package/dist/useWallet.mjs +1 -6
  69. package/dist/useWallets.mjs +1 -4
  70. package/package.json +8 -5
  71. package/dist/buffer-polyfill.d.mts +0 -2
  72. package/dist/index.d.mts +0 -64
  73. package/dist/kit.d.mts +0 -1
  74. package/dist/shared/vue.BGGixph-.d.mts +0 -5
  75. package/dist/shared/vue.Bfu1dCKe.mjs +0 -10
  76. package/dist/shared/vue.CGv0ip3w.mjs +0 -52
  77. package/dist/shared/vue.DL3z5PxP.d.mts +0 -21
  78. package/dist/swr.d.mts +0 -41
  79. package/dist/useAccountInfo.d.mts +0 -24
  80. package/dist/useAction.d.mts +0 -45
  81. package/dist/useAirdrop.d.mts +0 -27
  82. package/dist/useBalance.d.mts +0 -15
  83. package/dist/useClientCapability.d.mts +0 -39
  84. package/dist/useConnection.d.mts +0 -46
  85. package/dist/useIdentity.d.mts +0 -3
  86. package/dist/usePayer.d.mts +0 -18
  87. package/dist/usePlanTransaction.d.mts +0 -44
  88. package/dist/usePlanTransactions.d.mts +0 -5
  89. package/dist/useProgramAccounts.d.mts +0 -45
  90. package/dist/useRequest.d.mts +0 -73
  91. package/dist/useRpc.d.mts +0 -55
  92. package/dist/useSelectedWalletAccount.d.mts +0 -117
  93. package/dist/useSendTransaction.d.mts +0 -50
  94. package/dist/useSendTransactions.d.mts +0 -5
  95. package/dist/useSignAndSendTransaction.d.mts +0 -40
  96. package/dist/useSignAndSendTransactions.d.mts +0 -35
  97. package/dist/useSignIn.d.mts +0 -23
  98. package/dist/useSignMessage.d.mts +0 -236
  99. package/dist/useSignTransactions.d.mts +0 -24
  100. package/dist/useSignatureStatus.d.mts +0 -26
  101. package/dist/useSolana.d.mts +0 -9
  102. package/dist/useSolanaClient.d.mts +0 -45
  103. package/dist/useSubscription.d.mts +0 -70
  104. package/dist/useTokenAccounts.d.mts +0 -19
  105. package/dist/useTokenBalance.d.mts +0 -17
  106. package/dist/useTrackedData.d.mts +0 -98
  107. package/dist/useTransaction.d.mts +0 -27
  108. package/dist/useTransactionConfirmation.d.mts +0 -38
  109. package/dist/useWallet.d.mts +0 -31
  110. 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 the official `solanaRpc()`, `rpcTransactionPlanner()`, and `rpcTransactionPlanSendingExecutor()` stack; the old custom fallback sender is not used.
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
 
@@ -312,7 +312,7 @@ async function signIn() {
312
312
  </template>
313
313
  ```
314
314
 
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.
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. 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
316
 
317
317
  ## Transaction State
318
318
 
@@ -391,7 +391,7 @@ Configure a direct client with `payer` or `payerSecretKey`. `payerSecretKey` is
391
391
 
392
392
  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
393
 
394
- **Default client composition.** `createSolanaPlugin()` and `createSolanaClient()` install the official `solanaRpc()`, `rpcTransactionPlanner()`, and `rpcTransactionPlanSendingExecutor()` plugins by default. 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`.
394
+ **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
395
 
396
396
  ```ts
397
397
  import { useSendTransaction } from "@vue-solana/vue/useSendTransaction";
@@ -488,6 +488,8 @@ import { useRequestSwr } from "@vue-solana/vue/swr";
488
488
  const balance = useRequestSwr(["balance", address], () => client.rpc.getBalance(address).send());
489
489
  ```
490
490
 
491
+ 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.
492
+
491
493
  ### Cancellation & Timeouts
492
494
 
493
495
  `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 +594,9 @@ Docs: [Vue Solana Agent Skill](https://vue-solana-docs.vercel.app/agent-skill)
592
594
  | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
593
595
  | `createSolanaPlugin(options?)` | Installs the Vue Solana context. |
594
596
  | `VueSolana` | Alias for `createSolanaPlugin`. |
595
- | `useSolana()` | Returns the full injected Solana context. |
597
+ | `useSolana()` | Returns the full injected Solana context; throws when no plugin context is available. |
598
+ | `tryUseSolana()` | Returns the injected Solana context or `null` when no plugin context is available (SSR-safe). |
599
+ | `MissingClientCapabilityError` | Thrown by `useClientCapability()` (and client-sent composables) when the configured client lacks a required capability. |
596
600
  | `useRpc()` | Returns cluster, endpoint, connection status, latest blockhash, the Kit `client`, and `checkConnection()`. |
597
601
  | `useSolanaClient()` | Returns the injected Kit client as `{ client, rpc }`. The recommended RPC path. |
598
602
  | `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,35 +1,36 @@
1
- export { u as useAccountInfo } from './shared/vue.CvenSbZZ.mjs';
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.DDQxNX5q.mjs';
4
- export { u as useBalance } from './shared/vue.BFSboXMB.mjs';
5
- export { M as MissingClientCapabilityError, u as useClientCapability } from './shared/vue.B9uRpSDJ.mjs';
6
- export { u as useConnection } from './shared/vue.CpkwC8Th.mjs';
7
- export { u as usePlanTransaction, a as usePlanTransactions } from './shared/vue.CsFY1mfz.mjs';
8
- export { u as useProgramAccounts } from './shared/vue.1Qwco2kv.mjs';
9
- export { u as useIdentity, a as usePayer } from './shared/vue.B-xtuLtD.mjs';
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.BsGwt78R.mjs';
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.BxtOHzY_.mjs';
14
- export { u as useSignMessage } from './shared/vue.o98pAmDg.mjs';
15
- export { u as useSignAndSendTransaction } from './shared/vue.CjSw0Hh1.mjs';
16
- export { u as useSignTransactions } from './shared/vue.hG_FieA3.mjs';
17
- export { P as PartialSignAndSendError, u as useSignAndSendTransactions } from './shared/vue.C1JbUTpJ.mjs';
18
- export { u as useSignatureStatus } from './shared/vue.CXB4NEMA.mjs';
19
- export { u as useSignIn } from './shared/vue.C9OOmvkD.mjs';
20
- export { t as tryUseSolana, u as useSolana } from './shared/vue.CQh3AUE8.mjs';
21
- export { u as useSolanaClient } from './shared/vue.Mxc8w6Qk.mjs';
13
+ export { u as useSendTransaction, a as useSendTransactions } from './shared/vue.CLAqNcLp.mjs';
14
+ export { u as useSignMessage } from './shared/vue.DbJG4-ku.mjs';
15
+ export { u as useSignAndSendTransaction } from './shared/vue.4ne5EBD9.mjs';
16
+ export { u as useSignTransactions } from './shared/vue.CW-1AuSO.mjs';
17
+ export { P as PartialSignAndSendError, u as useSignAndSendTransactions } from './shared/vue.UrCjmf0T.mjs';
18
+ export { u as useSignatureStatus } from './shared/vue.Bu2cQ690.mjs';
19
+ export { u as useSignIn } from './shared/vue.BBN9aU6D.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.DNKD6jqM.mjs';
24
- export { u as useTokenBalance } from './shared/vue.XlfH_nkc.mjs';
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.CaAgH2Xt.mjs';
28
- export { u as useWallet } from './shared/vue.D218Ow7t.mjs';
29
- export { u as useWallets } from './shared/vue.C_4qJDiF.mjs';
27
+ export { g as getConfirmedTransactionStatus, u as useTransactionConfirmation } from './shared/vue.DPwdqRO_.mjs';
28
+ export { u as useWallet } from './shared/vue.DY9VadLH.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
+ import { isSolanaMobileWalletSupported } from '@vue-solana/core/mobile-wallet-support';
33
34
  import { createSolanaContext } from '@vue-solana/core/rpc';
34
35
  import { withTimeout } from '@vue-solana/core/timeout';
35
36
  import { getRegisteredSolanaWallets, getSolanaChain, adaptSolanaStandardWallet, subscribeSolanaWallets } from '@vue-solana/core/wallet-standard';
@@ -37,16 +38,6 @@ import { shallowRef, ref, triggerRef } from 'vue';
37
38
  import { handleSolanaIosWalletCallback, getSolanaIosWallets, isSolanaIosWalletInfo, adaptSolanaIosWallet } from '@vue-solana/core/ios-wallet';
38
39
  export * from '@vue-solana/core/types';
39
40
  export * from '@vue-solana/core/kit';
40
- import './shared/vue.BwBqla_n.mjs';
41
- import '@vue-solana/core/address';
42
- import './shared/vue.Bfu1dCKe.mjs';
43
- import '@vue-solana/core/action';
44
- import './shared/vue.CGv0ip3w.mjs';
45
- import '@vue-solana/core/wallet';
46
- import './shared/vue.DlihC5GG.mjs';
47
- import '@vue-solana/core/transaction';
48
- import 'bs58';
49
- import '@vue-solana/core/token-accounts';
50
41
 
51
42
  const SELECTED_WALLET_STORAGE_KEY = "vue-solana:selected-wallet";
52
43
  function readSelectedWallet() {
@@ -123,20 +114,39 @@ function getLocalStorage() {
123
114
 
124
115
  function createSolanaWalletRegistry(options) {
125
116
  const adaptedWallets = /* @__PURE__ */ new WeakMap();
117
+ const adaptedPrimitiveWallets = /* @__PURE__ */ new Map();
118
+ const trackedAdapters = /* @__PURE__ */ new Set();
119
+ function trackAdapter(adapter) {
120
+ trackedAdapters.add(adapter);
121
+ return adapter;
122
+ }
126
123
  function getAdaptedWallet(walletInfo) {
127
124
  if (isSolanaIosWalletInfo(walletInfo)) {
128
- return adaptSolanaIosWallet(walletInfo, {
125
+ const cachedIosWallet = adaptedWallets.get(walletInfo.wallet);
126
+ if (cachedIosWallet) {
127
+ return cachedIosWallet;
128
+ }
129
+ const iosAdapter = adaptSolanaIosWallet(walletInfo, {
129
130
  chain: getSolanaChain(options.cluster),
130
131
  cluster: options.cluster,
131
132
  onChange: options.onWalletChange,
132
133
  ...options.iosWallet || {}
133
134
  });
135
+ adaptedWallets.set(walletInfo.wallet, iosAdapter);
136
+ return trackAdapter(iosAdapter);
134
137
  }
135
138
  if (!isObject(walletInfo.wallet)) {
136
- return adaptSolanaStandardWallet(walletInfo, {
139
+ const primitiveKey = `${walletInfo.name}::${String(walletInfo.wallet)}`;
140
+ const cachedPrimitiveWallet = adaptedPrimitiveWallets.get(primitiveKey);
141
+ if (cachedPrimitiveWallet) {
142
+ return cachedPrimitiveWallet;
143
+ }
144
+ const primitiveAdapter = adaptSolanaStandardWallet(walletInfo, {
137
145
  chain: getSolanaChain(options.cluster),
138
146
  onChange: options.onWalletChange
139
147
  });
148
+ adaptedPrimitiveWallets.set(primitiveKey, primitiveAdapter);
149
+ return trackAdapter(primitiveAdapter);
140
150
  }
141
151
  const cachedWallet = adaptedWallets.get(walletInfo.wallet);
142
152
  if (cachedWallet) {
@@ -164,7 +174,7 @@ function createSolanaWalletRegistry(options) {
164
174
  );
165
175
  }
166
176
  adaptedWallets.set(walletInfo.wallet, cachedAdapter);
167
- return cachedAdapter;
177
+ return trackAdapter(cachedAdapter);
168
178
  }
169
179
  function getDiscoveredWallets() {
170
180
  return [
@@ -180,7 +190,6 @@ function createSolanaWalletRegistry(options) {
180
190
  try {
181
191
  handleSolanaIosWalletCallback({ clearUrl: true });
182
192
  } catch (cause) {
183
- console.error("[Vue Solana] iOS wallet callback failed", cause);
184
193
  }
185
194
  }
186
195
  function* getCachedWallets() {
@@ -193,10 +202,16 @@ function createSolanaWalletRegistry(options) {
193
202
  }
194
203
  }
195
204
  }
205
+ function disposeAllAdaptedWallets() {
206
+ for (const adapter of trackedAdapters) {
207
+ adapter.dispose?.();
208
+ }
209
+ }
196
210
  return {
197
211
  getAdaptedWallet,
198
212
  getDiscoveredWallets,
199
- handleIosWalletCallback
213
+ handleIosWalletCallback,
214
+ disposeAllAdaptedWallets
200
215
  };
201
216
  }
202
217
  function isObject(value) {
@@ -205,6 +220,7 @@ function isObject(value) {
205
220
 
206
221
  const RPC_CHECK_TIMEOUT_MS = 1e4;
207
222
  function createSolanaPlugin(options = {}) {
223
+ let teardown = null;
208
224
  const plugin = {
209
225
  context: null,
210
226
  install(app) {
@@ -225,15 +241,12 @@ function createSolanaPlugin(options = {}) {
225
241
  let mobileWalletRegistrationPromise = null;
226
242
  let attemptedAutoConnectWallet = null;
227
243
  let rpcCheckId = 0;
244
+ let bootstrapId = 0;
245
+ let disposed = false;
228
246
  async function checkConnection() {
229
247
  const checkId = ++rpcCheckId;
230
248
  status.value = "checking";
231
249
  error.value = null;
232
- console.info("[Vue Solana] Checking RPC connection", {
233
- cluster: context.cluster,
234
- endpoint: context.endpoint,
235
- wsEndpoint: context.wsEndpoint
236
- });
237
250
  try {
238
251
  const response = await withTimeout(
239
252
  context.client.rpc.getLatestBlockhash().send(),
@@ -248,22 +261,18 @@ function createSolanaPlugin(options = {}) {
248
261
  }
249
262
  latestBlockhash.value = blockhash.blockhash;
250
263
  status.value = "connected";
251
- console.info("[Vue Solana] Connected", {
252
- cluster: context.cluster,
253
- endpoint: context.endpoint,
254
- wsEndpoint: context.wsEndpoint,
255
- blockhash
256
- });
257
264
  } catch (cause) {
258
265
  if (checkId !== rpcCheckId) {
259
266
  return;
260
267
  }
261
268
  status.value = "error";
262
269
  error.value = normalizeSolanaError(cause, "RPC_FAILURE");
263
- console.error("[Vue Solana] Connection failed", cause);
264
270
  }
265
271
  }
266
272
  function refreshWallets() {
273
+ if (disposed) {
274
+ return;
275
+ }
267
276
  unsubscribeWallets ??= subscribeSolanaWallets(refreshWallets);
268
277
  walletRegistry.handleIosWalletCallback();
269
278
  wallets.value = walletRegistry.getDiscoveredWallets();
@@ -277,7 +286,6 @@ function createSolanaPlugin(options = {}) {
277
286
  const persistedWallet = readSelectedWallet();
278
287
  if (persistedWallet.error) {
279
288
  error.value = persistedWallet.error;
280
- console.error("[Vue Solana] Selected wallet restoration failed", persistedWallet.error);
281
289
  }
282
290
  restoredWallet = persistedWallet.wallet ? wallets.value.find(
283
291
  (nextWallet) => isSameWallet(nextWallet, persistedWallet.wallet)
@@ -287,7 +295,7 @@ function createSolanaPlugin(options = {}) {
287
295
  wallet.value = walletRegistry.getAdaptedWallet(restoredWallet);
288
296
  }
289
297
  }
290
- if (options.mobileWallet !== false) {
298
+ if (options.mobileWallet !== false && isSolanaMobileWalletSupported()) {
291
299
  registerMobileWallets();
292
300
  }
293
301
  if (restoredWallet) {
@@ -295,14 +303,19 @@ function createSolanaPlugin(options = {}) {
295
303
  }
296
304
  }
297
305
  function registerMobileWallets() {
306
+ if (disposed) {
307
+ return;
308
+ }
298
309
  mobileWalletRegistrationPromise ??= import('@vue-solana/core/mobile-wallet').then(({ registerSolanaMobileWallet }) => {
310
+ if (disposed) {
311
+ return;
312
+ }
299
313
  registerSolanaMobileWallet({
300
314
  chains: [getSolanaChain(context.cluster)],
301
315
  ...options.mobileWallet || {}
302
316
  });
303
317
  refreshWallets();
304
318
  }).catch((cause) => {
305
- console.error("[Vue Solana] Mobile wallet registration failed", cause);
306
319
  }).finally(() => {
307
320
  mobileWalletRegistrationPromise = null;
308
321
  });
@@ -313,7 +326,6 @@ function createSolanaPlugin(options = {}) {
313
326
  const storageError = writeSelectedWallet(nextWallet);
314
327
  if (storageError) {
315
328
  error.value = storageError;
316
- console.error("[Vue Solana] Selected wallet persistence failed", storageError);
317
329
  }
318
330
  }
319
331
  function autoConnectWallet(walletInfo) {
@@ -327,7 +339,6 @@ function createSolanaPlugin(options = {}) {
327
339
  }
328
340
  attemptedAutoConnectWallet = storageValue;
329
341
  void activeWallet.connect().catch((cause) => {
330
- console.error("[Vue Solana] Wallet auto-connect failed", cause);
331
342
  }).finally(() => {
332
343
  triggerRef(wallet);
333
344
  });
@@ -349,22 +360,34 @@ function createSolanaPlugin(options = {}) {
349
360
  const storageError = writeSelectedWallet(null);
350
361
  if (storageError) {
351
362
  error.value = storageError;
352
- console.error("[Vue Solana] Selected wallet persistence failed", storageError);
353
363
  }
354
364
  }
355
365
  };
356
366
  app.provide(solanaInjectionKey, vueContext);
357
367
  plugin.context = vueContext;
368
+ teardown = () => {
369
+ disposed = true;
370
+ if (typeof window !== "undefined") {
371
+ window.clearTimeout(bootstrapId);
372
+ }
373
+ unsubscribeWallets?.();
374
+ unsubscribeWallets = null;
375
+ walletRegistry.disposeAllAdaptedWallets();
376
+ rpcCheckId += 1;
377
+ teardown = null;
378
+ };
358
379
  if (typeof window !== "undefined") {
359
- window.setTimeout(() => {
380
+ bootstrapId = window.setTimeout(() => {
360
381
  try {
361
382
  refreshWallets();
362
383
  } catch (cause) {
363
- console.error("[Vue Solana] Wallet refresh failed", cause);
364
384
  }
365
385
  void checkConnection();
366
386
  }, 0);
367
387
  }
388
+ },
389
+ dispose() {
390
+ teardown?.();
368
391
  }
369
392
  };
370
393
  return plugin;
@@ -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 useConnection } from './vue.CpkwC8Th.mjs';
7
- import { u as useWallet } from './vue.D218Ow7t.mjs';
8
- import { g as getConfirmedTransactionStatus } from './vue.CaAgH2Xt.mjs';
6
+ import { u as useSolanaClient } from './vue.CZApWQAY.mjs';
7
+ import { u as useWallet } from './vue.DY9VadLH.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 = useConnection();
12
+ const client = useSolanaClient().client;
13
13
  const { wallet } = useWallet();
14
14
  const signature = ref(null);
15
15
  const confirmation = ref(null);
@@ -1,7 +1,7 @@
1
1
  import { createNoWalletSelectedError, assertWalletCanSignIn } from '@vue-solana/core/wallet';
2
2
  import { shallowRef } from 'vue';
3
- import { u as useExecution } from './vue.DlihC5GG.mjs';
4
- import { u as useWallet } from './vue.D218Ow7t.mjs';
3
+ import { u as useExecution } from './vue.BiKE9Xuv.mjs';
4
+ import { u as useWallet } from './vue.DY9VadLH.mjs';
5
5
 
6
6
  function useSignIn() {
7
7
  const { wallet } = useWallet();
@@ -1,4 +1,4 @@
1
- import { u as useClientAction } from './vue.CGv0ip3w.mjs';
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,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 status = shallowRef("idle");
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 = "error";
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 = "idle";
31
+ status.value = idleStatus;
30
32
  error.value = null;
31
33
  }
32
34
  onScopeDispose(() => {
@@ -1,19 +1,36 @@
1
- import { normalizeSolanaError, createSolanaError } from '@vue-solana/core/errors';
2
- import bs58 from 'bs58';
3
- import { shallowRef, onMounted, onUnmounted, watch, toValue } from 'vue';
4
- import { u as useConnection } from './vue.CpkwC8Th.mjs';
5
- import { t as tryUseSolana } from './vue.CQh3AUE8.mjs';
1
+ import { getBase58Encoder } from '@vue-solana/core/kit';
2
+ import { createSolanaError, normalizeSolanaError } from '@vue-solana/core/errors';
3
+ import { shallowRef, onMounted, onScopeDispose, watch, toValue } from 'vue';
4
+ import { u as useSolanaClient } from './vue.CZApWQAY.mjs';
5
+ import { t as tryUseSolana } from './vue.CcOZ9858.mjs';
6
6
 
7
7
  function useSignatureStatus(signature, options = {}) {
8
8
  const solana = tryUseSolana();
9
- const client = solana?.client ?? useConnection();
9
+ const client = solana?.client ?? useSolanaClient().client;
10
10
  const status = shallowRef(null);
11
11
  const loading = shallowRef(false);
12
12
  const error = shallowRef(null);
13
13
  let refreshId = 0;
14
- let pollId = null;
14
+ let pollTimer = null;
15
15
  let manuallyStoppedPolling = false;
16
+ let refreshInFlight = null;
16
17
  async function refresh() {
18
+ const value = toValue(signature);
19
+ const inFlight = refreshInFlight;
20
+ if (inFlight && inFlight.value === value) {
21
+ return inFlight.promise;
22
+ }
23
+ const promise = runRefresh();
24
+ refreshInFlight = { value, promise };
25
+ try {
26
+ return await promise;
27
+ } finally {
28
+ if (refreshInFlight?.promise === promise) {
29
+ refreshInFlight = null;
30
+ }
31
+ }
32
+ }
33
+ async function runRefresh() {
17
34
  const requestId = ++refreshId;
18
35
  const value = toValue(signature);
19
36
  if (!value || !solana) {
@@ -53,16 +70,22 @@ function useSignatureStatus(signature, options = {}) {
53
70
  stopCurrentPolling();
54
71
  }
55
72
  function stopCurrentPolling() {
56
- if (pollId === null) {
73
+ if (pollTimer === null) {
57
74
  return;
58
75
  }
59
- clearInterval(pollId);
60
- pollId = null;
76
+ clearTimeout(pollTimer);
77
+ pollTimer = null;
61
78
  }
62
- function startPolling() {
79
+ function schedulePoll() {
63
80
  stopCurrentPolling();
81
+ if (!options.pollIntervalMs || !solana) {
82
+ return;
83
+ }
84
+ if (manuallyStoppedPolling) {
85
+ return;
86
+ }
64
87
  const value = toValue(signature);
65
- if (manuallyStoppedPolling || !options.pollIntervalMs || !value || !solana) {
88
+ if (!value) {
66
89
  return;
67
90
  }
68
91
  if (options.pollIntervalMs <= 0) {
@@ -75,15 +98,22 @@ function useSignatureStatus(signature, options = {}) {
75
98
  error.value = normalizeSolanaError(cause, "RPC_FAILURE");
76
99
  return;
77
100
  }
78
- pollId = setInterval(() => {
79
- void refresh().catch(() => void 0);
101
+ pollTimer = setTimeout(() => {
102
+ pollTimer = null;
103
+ void refresh().catch(() => void 0).finally(() => {
104
+ schedulePoll();
105
+ });
80
106
  }, options.pollIntervalMs);
81
107
  }
108
+ function startPolling() {
109
+ manuallyStoppedPolling = false;
110
+ schedulePoll();
111
+ }
82
112
  onMounted(() => {
83
113
  void refresh().catch(() => void 0);
84
- startPolling();
114
+ schedulePoll();
85
115
  });
86
- onUnmounted(() => {
116
+ onScopeDispose(() => {
87
117
  refreshId += 1;
88
118
  stopPolling();
89
119
  });
@@ -105,7 +135,7 @@ function useSignatureStatus(signature, options = {}) {
105
135
  function parseTransactionSignature(signature) {
106
136
  let decodedSignature;
107
137
  try {
108
- decodedSignature = bs58.decode(signature);
138
+ decodedSignature = getBase58Encoder().encode(signature);
109
139
  } catch (cause) {
110
140
  throw new TypeError("Invalid Solana transaction signature", { cause });
111
141
  }
@@ -1,4 +1,4 @@
1
- import { u as useSolanaClient } from './vue.Mxc8w6Qk.mjs';
1
+ import { u as useSolanaClient } from './vue.CZApWQAY.mjs';
2
2
 
3
3
  function useConnection() {
4
4
  return useSolanaClient().client;
@@ -1,6 +1,7 @@
1
- import { u as useSolanaClient } from './vue.Mxc8w6Qk.mjs';
1
+ import { SolanaError } from '@vue-solana/core/errors';
2
+ import { u as useSolanaClient } from './vue.CZApWQAY.mjs';
2
3
 
3
- class MissingClientCapabilityError extends Error {
4
+ class MissingClientCapabilityError extends SolanaError {
4
5
  /** Name of the hook that requested the capability, e.g. `usePayer`. */
5
6
  hookName;
6
7
  /** Human guidance for installing the capability on the client. */
@@ -9,7 +10,9 @@ class MissingClientCapabilityError extends Error {
9
10
  capabilities;
10
11
  constructor(hookName, capabilities, providerHint) {
11
12
  super(
12
- `${hookName} requires the ${capabilities.map((capability) => `\`${capability}\``).join(" and ")} capabilit${capabilities.length === 1 ? "y" : "ies"} on the Solana client, but none ${capabilities.length === 1 ? "was" : "were"} found. ` + providerHint
13
+ "MISSING_CLIENT_CAPABILITY",
14
+ `${hookName} requires the ${capabilities.map((capability) => `\`${capability}\``).join(" and ")} capabilit${capabilities.length === 1 ? "y" : "ies"} on the Solana client, but none ${capabilities.length === 1 ? "was" : "were"} found. ` + providerHint,
15
+ {}
13
16
  );
14
17
  this.name = "MissingClientCapabilityError";
15
18
  this.hookName = hookName;
@@ -1,6 +1,7 @@
1
+ import { createSolanaError } from '@vue-solana/core/errors';
1
2
  import { u as useAction } from './vue.DYk0Xfr3.mjs';
2
- import { u as useClientCapability } from './vue.B9uRpSDJ.mjs';
3
- import { u as useSolanaClient } from './vue.Mxc8w6Qk.mjs';
3
+ import { u as useClientCapability, M as MissingClientCapabilityError } from './vue.CAltY57B.mjs';
4
+ import { u as useSolanaClient } from './vue.CZApWQAY.mjs';
4
5
 
5
6
  function toReadableAirdropError(error) {
6
7
  if (error instanceof Error) {
@@ -9,23 +10,22 @@ function toReadableAirdropError(error) {
9
10
  if (!isThrottled) {
10
11
  throw error;
11
12
  }
12
- throw new Error(
13
+ throw createSolanaError(
14
+ "RPC_FAILURE",
13
15
  `${error.message} This likely means the network's airdrop faucet is rate-limited or out of test SOL. Retry later, use https://faucet.solana.com, or point the client at a local validator.`,
14
16
  { cause: error }
15
17
  );
16
18
  }
17
- throw new Error(`Airdrop failed: ${String(error)}`);
19
+ throw createSolanaError("RPC_FAILURE", `Airdrop failed: ${String(error)}`, { cause: error });
18
20
  }
19
21
  function useAirdrop() {
20
- useClientCapability("airdrop", {
21
- hookName: "useAirdrop",
22
- providerHint: "Install it by adding the airdrop capability with `createClient().use(solanaRpc({ ... })).use(rpcAirdrop())` from `@solana/kit-plugin-rpc`, on a client that has a `payer` signer to sign the request."
23
- });
22
+ const providerHint = "Install it by adding the airdrop capability with `createClient().use(solanaRpc({ ... })).use(rpcAirdrop())` from `@solana/kit-plugin-rpc`, on a client that has a `payer` signer to sign the request.";
23
+ useClientCapability("airdrop", { hookName: "useAirdrop", providerHint });
24
24
  const { client } = useSolanaClient();
25
25
  return useAction((abortSignal, address, amount) => {
26
26
  const airdrop = client.airdrop;
27
27
  if (!airdrop) {
28
- throw new Error("useAirdrop requires the `airdrop` capability on the Solana client.");
28
+ throw new MissingClientCapabilityError("useAirdrop", ["airdrop"], providerHint);
29
29
  }
30
30
  return airdrop(address, amount, abortSignal).catch(toReadableAirdropError);
31
31
  });
@@ -1,4 +1,4 @@
1
- import { u as useClientAction } from './vue.CGv0ip3w.mjs';
1
+ import { u as useClientAction } from './vue.CbmzveKF.mjs';
2
2
 
3
3
  const SENDING_PROVIDER_HINT = "Use a client created by `createSolanaClient({ payer })` \u2014 or any client with a `payer` signer. Kit reads `client.payer` when it plans a transaction from an instruction plan.";
4
4
  const SEND_STATUSES = {
@@ -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.DlihC5GG.mjs';
4
- import { u as useWallet } from './vue.D218Ow7t.mjs';
3
+ import { u as useExecution } from './vue.BiKE9Xuv.mjs';
4
+ import { u as useWallet } from './vue.DY9VadLH.mjs';
5
5
 
6
6
  function useSignTransactions() {
7
7
  const { wallet } = useWallet();
@@ -1,4 +1,4 @@
1
- import { u as useSolana } from './vue.CQh3AUE8.mjs';
1
+ import { u as useSolana } from './vue.CcOZ9858.mjs';
2
2
 
3
3
  function useSolanaClient() {
4
4
  const { client } = useSolana();