@vue-solana/vue 0.1.3 → 0.2.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 +24 -8
- package/dist/index.cjs +115 -4
- package/dist/index.d.cts +15 -2
- package/dist/index.d.mts +15 -2
- package/dist/index.d.ts +15 -2
- package/dist/index.mjs +117 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -9,8 +9,9 @@ New to Solana? Start with the official docs and the project concepts guide:
|
|
|
9
9
|
- [Solana Documentation](https://solana.com/docs)
|
|
10
10
|
- [Solana RPC Methods](https://solana.com/docs/rpc)
|
|
11
11
|
- [Solana Clusters](https://solana.com/docs/references/clusters)
|
|
12
|
-
- [Vue Solana Concepts Guide](https://
|
|
13
|
-
- [`@vue-solana/vue` docs](https://
|
|
12
|
+
- [Vue Solana Concepts Guide](https://vue-solana-docs.vercel.app/concepts/solana-for-vue-developers)
|
|
13
|
+
- [`@vue-solana/vue` docs](https://vue-solana-docs.vercel.app/packages/vue)
|
|
14
|
+
- [Live demo](https://vue-solana-docs.vercel.app/demo)
|
|
14
15
|
|
|
15
16
|
## Install
|
|
16
17
|
|
|
@@ -104,23 +105,36 @@ const { balance, loading, error, refresh } = useBalance(address);
|
|
|
104
105
|
|
|
105
106
|
```vue
|
|
106
107
|
<script setup lang="ts">
|
|
107
|
-
import { useWallet } from "@vue-solana/vue";
|
|
108
|
+
import { useWallet, useWallets } from "@vue-solana/vue";
|
|
108
109
|
|
|
110
|
+
const { wallets, selectedWallet, selectWallet, refreshWallets } = useWallets();
|
|
109
111
|
const { publicKey, connected, connecting, connect, disconnect } = useWallet();
|
|
110
112
|
</script>
|
|
111
113
|
|
|
112
114
|
<template>
|
|
113
115
|
<section>
|
|
116
|
+
<button type="button" @click="refreshWallets">Refresh Wallets</button>
|
|
117
|
+
<button
|
|
118
|
+
v-for="wallet in wallets"
|
|
119
|
+
:key="wallet.name"
|
|
120
|
+
type="button"
|
|
121
|
+
@click="selectWallet(wallet)"
|
|
122
|
+
>
|
|
123
|
+
{{ wallet.name }}
|
|
124
|
+
</button>
|
|
125
|
+
<p>Selected: {{ selectedWallet?.name ?? "None" }}</p>
|
|
114
126
|
<p>Connected: {{ connected }}</p>
|
|
115
127
|
<p>Public key: {{ publicKey?.toBase58() }}</p>
|
|
116
128
|
<p v-if="connecting">Connecting...</p>
|
|
117
|
-
<button type="button" @click="connect">
|
|
118
|
-
|
|
129
|
+
<button type="button" :disabled="!selectedWallet || connected || connecting" @click="connect">
|
|
130
|
+
Connect
|
|
131
|
+
</button>
|
|
132
|
+
<button type="button" :disabled="!connected" @click="disconnect">Disconnect</button>
|
|
119
133
|
</section>
|
|
120
134
|
</template>
|
|
121
135
|
```
|
|
122
136
|
|
|
123
|
-
Browser
|
|
137
|
+
Browser wallets are discovered through the Solana Wallet Standard. `connect()` works after selecting a discovered wallet or configuring a custom `SolanaWallet`.
|
|
124
138
|
|
|
125
139
|
## Transaction State
|
|
126
140
|
|
|
@@ -144,7 +158,9 @@ This README includes small snippets for quick reference. For a complete runnable
|
|
|
144
158
|
pnpm dev:vue
|
|
145
159
|
```
|
|
146
160
|
|
|
147
|
-
|
|
161
|
+
Docs: <a href="https://vue-solana-docs.vercel.app/examples/vue-vite" target="_blank" rel="noopener noreferrer"><code>examples/vue-vite</code></a>
|
|
162
|
+
|
|
163
|
+
Live demo: [vue-solana-docs.vercel.app/demo](https://vue-solana-docs.vercel.app/demo)
|
|
148
164
|
|
|
149
165
|
## API
|
|
150
166
|
|
|
@@ -183,4 +199,4 @@ Make sure your `tsconfig.json` includes `types/**/*.d.ts` or another pattern tha
|
|
|
183
199
|
|
|
184
200
|
## Status
|
|
185
201
|
|
|
186
|
-
This package is early-stage. RPC and
|
|
202
|
+
This package is early-stage. RPC, balance, wallet, and transaction composables are usable.
|
package/dist/index.cjs
CHANGED
|
@@ -74,14 +74,63 @@ function useBalance(address, commitment) {
|
|
|
74
74
|
function useWallet() {
|
|
75
75
|
const solana = useSolana();
|
|
76
76
|
const wallet = solana.wallet;
|
|
77
|
+
const connecting = vue.ref(false);
|
|
78
|
+
const disconnecting = vue.ref(false);
|
|
79
|
+
async function connect() {
|
|
80
|
+
const activeWallet = wallet.value;
|
|
81
|
+
if (!activeWallet) {
|
|
82
|
+
throw new Error("No Solana wallet is configured");
|
|
83
|
+
}
|
|
84
|
+
connecting.value = true;
|
|
85
|
+
try {
|
|
86
|
+
const connection = activeWallet.connect();
|
|
87
|
+
vue.triggerRef(wallet);
|
|
88
|
+
await connection;
|
|
89
|
+
vue.triggerRef(wallet);
|
|
90
|
+
console.info("[Vue Solana] Wallet connected", {
|
|
91
|
+
publicKey: activeWallet.publicKey?.toBase58() ?? null
|
|
92
|
+
});
|
|
93
|
+
} catch (error) {
|
|
94
|
+
vue.triggerRef(wallet);
|
|
95
|
+
console.error("[Vue Solana] Wallet connection failed", error);
|
|
96
|
+
throw error;
|
|
97
|
+
} finally {
|
|
98
|
+
connecting.value = false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async function disconnect() {
|
|
102
|
+
const activeWallet = wallet.value;
|
|
103
|
+
if (!activeWallet) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const publicKey = activeWallet.publicKey?.toBase58() ?? null;
|
|
107
|
+
disconnecting.value = true;
|
|
108
|
+
try {
|
|
109
|
+
await activeWallet.disconnect();
|
|
110
|
+
vue.triggerRef(wallet);
|
|
111
|
+
console.info("[Vue Solana] Wallet disconnected", { publicKey });
|
|
112
|
+
} catch (error) {
|
|
113
|
+
vue.triggerRef(wallet);
|
|
114
|
+
console.error("[Vue Solana] Wallet disconnection failed", error);
|
|
115
|
+
throw error;
|
|
116
|
+
} finally {
|
|
117
|
+
disconnecting.value = false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const isConnecting = vue.computed(() => Boolean(connecting.value || wallet.value?.connecting));
|
|
121
|
+
const isDisconnecting = vue.computed(
|
|
122
|
+
() => Boolean(disconnecting.value || wallet.value?.disconnecting)
|
|
123
|
+
);
|
|
77
124
|
return {
|
|
78
125
|
wallet,
|
|
79
126
|
publicKey: vue.computed(() => wallet.value?.publicKey ?? null),
|
|
80
127
|
connected: vue.computed(() => Boolean(wallet.value?.connected && wallet.value.publicKey)),
|
|
81
|
-
connecting:
|
|
128
|
+
connecting: isConnecting,
|
|
129
|
+
disconnecting: isDisconnecting,
|
|
130
|
+
loading: vue.computed(() => isConnecting.value || isDisconnecting.value),
|
|
82
131
|
setWallet: solana.setWallet,
|
|
83
|
-
connect
|
|
84
|
-
disconnect
|
|
132
|
+
connect,
|
|
133
|
+
disconnect
|
|
85
134
|
};
|
|
86
135
|
}
|
|
87
136
|
|
|
@@ -121,15 +170,31 @@ function useSignAndSendTransaction() {
|
|
|
121
170
|
});
|
|
122
171
|
}
|
|
123
172
|
|
|
173
|
+
function useWallets() {
|
|
174
|
+
const solana = useSolana();
|
|
175
|
+
return {
|
|
176
|
+
wallets: solana.wallets,
|
|
177
|
+
selectedWallet: solana.selectedWallet,
|
|
178
|
+
refreshWallets: solana.refreshWallets,
|
|
179
|
+
selectWallet: solana.selectWallet
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const RPC_CHECK_TIMEOUT_MS = 1e4;
|
|
124
184
|
function createSolanaPlugin(options = {}) {
|
|
125
185
|
return {
|
|
126
186
|
install(app) {
|
|
127
187
|
const context = core.createSolanaContext(options);
|
|
128
188
|
const wallet = vue.shallowRef(options.wallet ?? null);
|
|
189
|
+
const wallets = vue.shallowRef([]);
|
|
190
|
+
const selectedWallet = vue.shallowRef(null);
|
|
129
191
|
const status = vue.ref("idle");
|
|
130
192
|
const error = vue.ref(null);
|
|
131
193
|
const latestBlockhash = vue.ref(null);
|
|
194
|
+
let unsubscribeWallets = null;
|
|
195
|
+
let rpcCheckId = 0;
|
|
132
196
|
async function checkConnection() {
|
|
197
|
+
const checkId = ++rpcCheckId;
|
|
133
198
|
status.value = "checking";
|
|
134
199
|
error.value = null;
|
|
135
200
|
console.info("[Vue Solana] Checking RPC connection", {
|
|
@@ -138,7 +203,14 @@ function createSolanaPlugin(options = {}) {
|
|
|
138
203
|
wsEndpoint: context.wsEndpoint
|
|
139
204
|
});
|
|
140
205
|
try {
|
|
141
|
-
const blockhash = await
|
|
206
|
+
const blockhash = await withTimeout(
|
|
207
|
+
context.connection.getLatestBlockhash(),
|
|
208
|
+
RPC_CHECK_TIMEOUT_MS,
|
|
209
|
+
`RPC connection check timed out after ${RPC_CHECK_TIMEOUT_MS / 1e3} seconds.`
|
|
210
|
+
);
|
|
211
|
+
if (checkId !== rpcCheckId) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
142
214
|
latestBlockhash.value = blockhash.blockhash;
|
|
143
215
|
status.value = "connected";
|
|
144
216
|
console.info("[Vue Solana] Connected", {
|
|
@@ -148,19 +220,44 @@ function createSolanaPlugin(options = {}) {
|
|
|
148
220
|
blockhash
|
|
149
221
|
});
|
|
150
222
|
} catch (cause) {
|
|
223
|
+
if (checkId !== rpcCheckId) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
151
226
|
status.value = "error";
|
|
152
227
|
error.value = cause instanceof Error ? cause.message : String(cause);
|
|
153
228
|
console.error("[Vue Solana] Connection failed", cause);
|
|
154
229
|
}
|
|
155
230
|
}
|
|
231
|
+
function refreshWallets() {
|
|
232
|
+
unsubscribeWallets ??= core.subscribeSolanaWallets(refreshWallets);
|
|
233
|
+
wallets.value = core.getRegisteredSolanaWallets();
|
|
234
|
+
if (selectedWallet.value) {
|
|
235
|
+
selectedWallet.value = wallets.value.find((nextWallet) => nextWallet.name === selectedWallet.value?.name) ?? null;
|
|
236
|
+
if (!selectedWallet.value) {
|
|
237
|
+
wallet.value = options.wallet ?? null;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function selectWallet(nextWallet) {
|
|
242
|
+
selectedWallet.value = nextWallet;
|
|
243
|
+
wallet.value = nextWallet ? core.adaptSolanaStandardWallet(nextWallet, {
|
|
244
|
+
chain: core.getSolanaChain(context.cluster),
|
|
245
|
+
onChange: () => vue.triggerRef(wallet)
|
|
246
|
+
}) : options.wallet ?? null;
|
|
247
|
+
}
|
|
156
248
|
const vueContext = {
|
|
157
249
|
...context,
|
|
158
250
|
wallet,
|
|
159
251
|
status,
|
|
160
252
|
error,
|
|
161
253
|
latestBlockhash,
|
|
254
|
+
wallets,
|
|
255
|
+
selectedWallet,
|
|
162
256
|
checkConnection,
|
|
257
|
+
refreshWallets,
|
|
258
|
+
selectWallet,
|
|
163
259
|
setWallet(nextWallet) {
|
|
260
|
+
selectedWallet.value = null;
|
|
164
261
|
wallet.value = nextWallet;
|
|
165
262
|
}
|
|
166
263
|
};
|
|
@@ -170,6 +267,19 @@ function createSolanaPlugin(options = {}) {
|
|
|
170
267
|
};
|
|
171
268
|
}
|
|
172
269
|
const VueSolana = createSolanaPlugin;
|
|
270
|
+
function withTimeout(promise, timeoutMs, message) {
|
|
271
|
+
let timeoutId;
|
|
272
|
+
const timeout = new Promise((_, reject) => {
|
|
273
|
+
timeoutId = setTimeout(() => {
|
|
274
|
+
reject(new Error(message));
|
|
275
|
+
}, timeoutMs);
|
|
276
|
+
});
|
|
277
|
+
return Promise.race([promise, timeout]).finally(() => {
|
|
278
|
+
if (timeoutId) {
|
|
279
|
+
clearTimeout(timeoutId);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
}
|
|
173
283
|
|
|
174
284
|
exports.VueSolana = VueSolana;
|
|
175
285
|
exports.createSolanaPlugin = createSolanaPlugin;
|
|
@@ -181,3 +291,4 @@ exports.useSignAndSendTransaction = useSignAndSendTransaction;
|
|
|
181
291
|
exports.useSolana = useSolana;
|
|
182
292
|
exports.useTransaction = useTransaction;
|
|
183
293
|
exports.useWallet = useWallet;
|
|
294
|
+
exports.useWallets = useWallets;
|
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +2,7 @@ import * as vue from 'vue';
|
|
|
2
2
|
import { MaybeRefOrGetter, Ref, InjectionKey, App } from 'vue';
|
|
3
3
|
import { PublicKey, Commitment, TransactionSignature } from '@solana/web3-compat';
|
|
4
4
|
import * as _vue_solana_core from '@vue-solana/core';
|
|
5
|
-
import { SendTransactionOptions, SolanaContext, SolanaWallet, SolanaConfig } from '@vue-solana/core';
|
|
5
|
+
import { SendTransactionOptions, SolanaContext, SolanaWallet, SolanaWalletInfo, SolanaConfig } from '@vue-solana/core';
|
|
6
6
|
|
|
7
7
|
declare function useBalance(address: MaybeRefOrGetter<PublicKey | string | null | undefined>, commitment?: Commitment): {
|
|
8
8
|
balance: vue.Ref<number | null, number | null>;
|
|
@@ -45,19 +45,32 @@ declare function useWallet(): {
|
|
|
45
45
|
publicKey: vue.ComputedRef<any>;
|
|
46
46
|
connected: vue.ComputedRef<boolean>;
|
|
47
47
|
connecting: vue.ComputedRef<boolean>;
|
|
48
|
+
disconnecting: vue.ComputedRef<boolean>;
|
|
49
|
+
loading: vue.ComputedRef<boolean>;
|
|
48
50
|
setWallet: (wallet: _vue_solana_core.SolanaWallet | null) => void;
|
|
49
51
|
connect: () => Promise<void>;
|
|
50
52
|
disconnect: () => Promise<void>;
|
|
51
53
|
};
|
|
52
54
|
|
|
55
|
+
declare function useWallets(): {
|
|
56
|
+
wallets: vue.Ref<_vue_solana_core.SolanaWalletInfo[], _vue_solana_core.SolanaWalletInfo[]>;
|
|
57
|
+
selectedWallet: vue.Ref<_vue_solana_core.SolanaWalletInfo | null, _vue_solana_core.SolanaWalletInfo | null>;
|
|
58
|
+
refreshWallets: () => void;
|
|
59
|
+
selectWallet: (wallet: _vue_solana_core.SolanaWalletInfo | null) => void;
|
|
60
|
+
};
|
|
61
|
+
|
|
53
62
|
type SolanaConnectionStatus = "idle" | "checking" | "connected" | "error";
|
|
54
63
|
interface VueSolanaContext extends SolanaContext {
|
|
55
64
|
wallet: Ref<SolanaWallet | null>;
|
|
56
65
|
status: Ref<SolanaConnectionStatus>;
|
|
57
66
|
error: Ref<string | null>;
|
|
58
67
|
latestBlockhash: Ref<string | null>;
|
|
68
|
+
wallets: Ref<SolanaWalletInfo[]>;
|
|
69
|
+
selectedWallet: Ref<SolanaWalletInfo | null>;
|
|
59
70
|
checkConnection: () => Promise<void>;
|
|
60
71
|
setWallet: (wallet: SolanaWallet | null) => void;
|
|
72
|
+
refreshWallets: () => void;
|
|
73
|
+
selectWallet: (wallet: SolanaWalletInfo | null) => void;
|
|
61
74
|
}
|
|
62
75
|
declare const solanaInjectionKey: InjectionKey<VueSolanaContext>;
|
|
63
76
|
|
|
@@ -69,5 +82,5 @@ declare function createSolanaPlugin(options?: VueSolanaPluginOptions): {
|
|
|
69
82
|
};
|
|
70
83
|
declare const VueSolana: typeof createSolanaPlugin;
|
|
71
84
|
|
|
72
|
-
export { VueSolana, createSolanaPlugin, solanaInjectionKey, useBalance, useConnection, useRpc, useSignAndSendTransaction, useSolana, useTransaction, useWallet };
|
|
85
|
+
export { VueSolana, createSolanaPlugin, solanaInjectionKey, useBalance, useConnection, useRpc, useSignAndSendTransaction, useSolana, useTransaction, useWallet, useWallets };
|
|
73
86
|
export type { SolanaConnectionStatus, VueSolanaContext, VueSolanaPluginOptions };
|
package/dist/index.d.mts
CHANGED
|
@@ -2,7 +2,7 @@ import * as vue from 'vue';
|
|
|
2
2
|
import { MaybeRefOrGetter, Ref, InjectionKey, App } from 'vue';
|
|
3
3
|
import { PublicKey, Commitment, TransactionSignature } from '@solana/web3-compat';
|
|
4
4
|
import * as _vue_solana_core from '@vue-solana/core';
|
|
5
|
-
import { SendTransactionOptions, SolanaContext, SolanaWallet, SolanaConfig } from '@vue-solana/core';
|
|
5
|
+
import { SendTransactionOptions, SolanaContext, SolanaWallet, SolanaWalletInfo, SolanaConfig } from '@vue-solana/core';
|
|
6
6
|
|
|
7
7
|
declare function useBalance(address: MaybeRefOrGetter<PublicKey | string | null | undefined>, commitment?: Commitment): {
|
|
8
8
|
balance: vue.Ref<number | null, number | null>;
|
|
@@ -45,19 +45,32 @@ declare function useWallet(): {
|
|
|
45
45
|
publicKey: vue.ComputedRef<any>;
|
|
46
46
|
connected: vue.ComputedRef<boolean>;
|
|
47
47
|
connecting: vue.ComputedRef<boolean>;
|
|
48
|
+
disconnecting: vue.ComputedRef<boolean>;
|
|
49
|
+
loading: vue.ComputedRef<boolean>;
|
|
48
50
|
setWallet: (wallet: _vue_solana_core.SolanaWallet | null) => void;
|
|
49
51
|
connect: () => Promise<void>;
|
|
50
52
|
disconnect: () => Promise<void>;
|
|
51
53
|
};
|
|
52
54
|
|
|
55
|
+
declare function useWallets(): {
|
|
56
|
+
wallets: vue.Ref<_vue_solana_core.SolanaWalletInfo[], _vue_solana_core.SolanaWalletInfo[]>;
|
|
57
|
+
selectedWallet: vue.Ref<_vue_solana_core.SolanaWalletInfo | null, _vue_solana_core.SolanaWalletInfo | null>;
|
|
58
|
+
refreshWallets: () => void;
|
|
59
|
+
selectWallet: (wallet: _vue_solana_core.SolanaWalletInfo | null) => void;
|
|
60
|
+
};
|
|
61
|
+
|
|
53
62
|
type SolanaConnectionStatus = "idle" | "checking" | "connected" | "error";
|
|
54
63
|
interface VueSolanaContext extends SolanaContext {
|
|
55
64
|
wallet: Ref<SolanaWallet | null>;
|
|
56
65
|
status: Ref<SolanaConnectionStatus>;
|
|
57
66
|
error: Ref<string | null>;
|
|
58
67
|
latestBlockhash: Ref<string | null>;
|
|
68
|
+
wallets: Ref<SolanaWalletInfo[]>;
|
|
69
|
+
selectedWallet: Ref<SolanaWalletInfo | null>;
|
|
59
70
|
checkConnection: () => Promise<void>;
|
|
60
71
|
setWallet: (wallet: SolanaWallet | null) => void;
|
|
72
|
+
refreshWallets: () => void;
|
|
73
|
+
selectWallet: (wallet: SolanaWalletInfo | null) => void;
|
|
61
74
|
}
|
|
62
75
|
declare const solanaInjectionKey: InjectionKey<VueSolanaContext>;
|
|
63
76
|
|
|
@@ -69,5 +82,5 @@ declare function createSolanaPlugin(options?: VueSolanaPluginOptions): {
|
|
|
69
82
|
};
|
|
70
83
|
declare const VueSolana: typeof createSolanaPlugin;
|
|
71
84
|
|
|
72
|
-
export { VueSolana, createSolanaPlugin, solanaInjectionKey, useBalance, useConnection, useRpc, useSignAndSendTransaction, useSolana, useTransaction, useWallet };
|
|
85
|
+
export { VueSolana, createSolanaPlugin, solanaInjectionKey, useBalance, useConnection, useRpc, useSignAndSendTransaction, useSolana, useTransaction, useWallet, useWallets };
|
|
73
86
|
export type { SolanaConnectionStatus, VueSolanaContext, VueSolanaPluginOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as vue from 'vue';
|
|
|
2
2
|
import { MaybeRefOrGetter, Ref, InjectionKey, App } from 'vue';
|
|
3
3
|
import { PublicKey, Commitment, TransactionSignature } from '@solana/web3-compat';
|
|
4
4
|
import * as _vue_solana_core from '@vue-solana/core';
|
|
5
|
-
import { SendTransactionOptions, SolanaContext, SolanaWallet, SolanaConfig } from '@vue-solana/core';
|
|
5
|
+
import { SendTransactionOptions, SolanaContext, SolanaWallet, SolanaWalletInfo, SolanaConfig } from '@vue-solana/core';
|
|
6
6
|
|
|
7
7
|
declare function useBalance(address: MaybeRefOrGetter<PublicKey | string | null | undefined>, commitment?: Commitment): {
|
|
8
8
|
balance: vue.Ref<number | null, number | null>;
|
|
@@ -45,19 +45,32 @@ declare function useWallet(): {
|
|
|
45
45
|
publicKey: vue.ComputedRef<any>;
|
|
46
46
|
connected: vue.ComputedRef<boolean>;
|
|
47
47
|
connecting: vue.ComputedRef<boolean>;
|
|
48
|
+
disconnecting: vue.ComputedRef<boolean>;
|
|
49
|
+
loading: vue.ComputedRef<boolean>;
|
|
48
50
|
setWallet: (wallet: _vue_solana_core.SolanaWallet | null) => void;
|
|
49
51
|
connect: () => Promise<void>;
|
|
50
52
|
disconnect: () => Promise<void>;
|
|
51
53
|
};
|
|
52
54
|
|
|
55
|
+
declare function useWallets(): {
|
|
56
|
+
wallets: vue.Ref<_vue_solana_core.SolanaWalletInfo[], _vue_solana_core.SolanaWalletInfo[]>;
|
|
57
|
+
selectedWallet: vue.Ref<_vue_solana_core.SolanaWalletInfo | null, _vue_solana_core.SolanaWalletInfo | null>;
|
|
58
|
+
refreshWallets: () => void;
|
|
59
|
+
selectWallet: (wallet: _vue_solana_core.SolanaWalletInfo | null) => void;
|
|
60
|
+
};
|
|
61
|
+
|
|
53
62
|
type SolanaConnectionStatus = "idle" | "checking" | "connected" | "error";
|
|
54
63
|
interface VueSolanaContext extends SolanaContext {
|
|
55
64
|
wallet: Ref<SolanaWallet | null>;
|
|
56
65
|
status: Ref<SolanaConnectionStatus>;
|
|
57
66
|
error: Ref<string | null>;
|
|
58
67
|
latestBlockhash: Ref<string | null>;
|
|
68
|
+
wallets: Ref<SolanaWalletInfo[]>;
|
|
69
|
+
selectedWallet: Ref<SolanaWalletInfo | null>;
|
|
59
70
|
checkConnection: () => Promise<void>;
|
|
60
71
|
setWallet: (wallet: SolanaWallet | null) => void;
|
|
72
|
+
refreshWallets: () => void;
|
|
73
|
+
selectWallet: (wallet: SolanaWalletInfo | null) => void;
|
|
61
74
|
}
|
|
62
75
|
declare const solanaInjectionKey: InjectionKey<VueSolanaContext>;
|
|
63
76
|
|
|
@@ -69,5 +82,5 @@ declare function createSolanaPlugin(options?: VueSolanaPluginOptions): {
|
|
|
69
82
|
};
|
|
70
83
|
declare const VueSolana: typeof createSolanaPlugin;
|
|
71
84
|
|
|
72
|
-
export { VueSolana, createSolanaPlugin, solanaInjectionKey, useBalance, useConnection, useRpc, useSignAndSendTransaction, useSolana, useTransaction, useWallet };
|
|
85
|
+
export { VueSolana, createSolanaPlugin, solanaInjectionKey, useBalance, useConnection, useRpc, useSignAndSendTransaction, useSolana, useTransaction, useWallet, useWallets };
|
|
73
86
|
export type { SolanaConnectionStatus, VueSolanaContext, VueSolanaPluginOptions };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PublicKey } from '@solana/web3-compat';
|
|
2
|
-
import { inject, computed, ref, watch, toValue, shallowRef } from 'vue';
|
|
3
|
-
import { signAndSendTransaction, createSolanaContext } from '@vue-solana/core';
|
|
2
|
+
import { inject, computed, ref, watch, toValue, triggerRef, shallowRef } from 'vue';
|
|
3
|
+
import { signAndSendTransaction, createSolanaContext, adaptSolanaStandardWallet, getSolanaChain, subscribeSolanaWallets, getRegisteredSolanaWallets } from '@vue-solana/core';
|
|
4
4
|
|
|
5
5
|
const solanaInjectionKey = Symbol("VueSolana");
|
|
6
6
|
|
|
@@ -72,14 +72,63 @@ function useBalance(address, commitment) {
|
|
|
72
72
|
function useWallet() {
|
|
73
73
|
const solana = useSolana();
|
|
74
74
|
const wallet = solana.wallet;
|
|
75
|
+
const connecting = ref(false);
|
|
76
|
+
const disconnecting = ref(false);
|
|
77
|
+
async function connect() {
|
|
78
|
+
const activeWallet = wallet.value;
|
|
79
|
+
if (!activeWallet) {
|
|
80
|
+
throw new Error("No Solana wallet is configured");
|
|
81
|
+
}
|
|
82
|
+
connecting.value = true;
|
|
83
|
+
try {
|
|
84
|
+
const connection = activeWallet.connect();
|
|
85
|
+
triggerRef(wallet);
|
|
86
|
+
await connection;
|
|
87
|
+
triggerRef(wallet);
|
|
88
|
+
console.info("[Vue Solana] Wallet connected", {
|
|
89
|
+
publicKey: activeWallet.publicKey?.toBase58() ?? null
|
|
90
|
+
});
|
|
91
|
+
} catch (error) {
|
|
92
|
+
triggerRef(wallet);
|
|
93
|
+
console.error("[Vue Solana] Wallet connection failed", error);
|
|
94
|
+
throw error;
|
|
95
|
+
} finally {
|
|
96
|
+
connecting.value = false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function disconnect() {
|
|
100
|
+
const activeWallet = wallet.value;
|
|
101
|
+
if (!activeWallet) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const publicKey = activeWallet.publicKey?.toBase58() ?? null;
|
|
105
|
+
disconnecting.value = true;
|
|
106
|
+
try {
|
|
107
|
+
await activeWallet.disconnect();
|
|
108
|
+
triggerRef(wallet);
|
|
109
|
+
console.info("[Vue Solana] Wallet disconnected", { publicKey });
|
|
110
|
+
} catch (error) {
|
|
111
|
+
triggerRef(wallet);
|
|
112
|
+
console.error("[Vue Solana] Wallet disconnection failed", error);
|
|
113
|
+
throw error;
|
|
114
|
+
} finally {
|
|
115
|
+
disconnecting.value = false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const isConnecting = computed(() => Boolean(connecting.value || wallet.value?.connecting));
|
|
119
|
+
const isDisconnecting = computed(
|
|
120
|
+
() => Boolean(disconnecting.value || wallet.value?.disconnecting)
|
|
121
|
+
);
|
|
75
122
|
return {
|
|
76
123
|
wallet,
|
|
77
124
|
publicKey: computed(() => wallet.value?.publicKey ?? null),
|
|
78
125
|
connected: computed(() => Boolean(wallet.value?.connected && wallet.value.publicKey)),
|
|
79
|
-
connecting:
|
|
126
|
+
connecting: isConnecting,
|
|
127
|
+
disconnecting: isDisconnecting,
|
|
128
|
+
loading: computed(() => isConnecting.value || isDisconnecting.value),
|
|
80
129
|
setWallet: solana.setWallet,
|
|
81
|
-
connect
|
|
82
|
-
disconnect
|
|
130
|
+
connect,
|
|
131
|
+
disconnect
|
|
83
132
|
};
|
|
84
133
|
}
|
|
85
134
|
|
|
@@ -119,15 +168,31 @@ function useSignAndSendTransaction() {
|
|
|
119
168
|
});
|
|
120
169
|
}
|
|
121
170
|
|
|
171
|
+
function useWallets() {
|
|
172
|
+
const solana = useSolana();
|
|
173
|
+
return {
|
|
174
|
+
wallets: solana.wallets,
|
|
175
|
+
selectedWallet: solana.selectedWallet,
|
|
176
|
+
refreshWallets: solana.refreshWallets,
|
|
177
|
+
selectWallet: solana.selectWallet
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const RPC_CHECK_TIMEOUT_MS = 1e4;
|
|
122
182
|
function createSolanaPlugin(options = {}) {
|
|
123
183
|
return {
|
|
124
184
|
install(app) {
|
|
125
185
|
const context = createSolanaContext(options);
|
|
126
186
|
const wallet = shallowRef(options.wallet ?? null);
|
|
187
|
+
const wallets = shallowRef([]);
|
|
188
|
+
const selectedWallet = shallowRef(null);
|
|
127
189
|
const status = ref("idle");
|
|
128
190
|
const error = ref(null);
|
|
129
191
|
const latestBlockhash = ref(null);
|
|
192
|
+
let unsubscribeWallets = null;
|
|
193
|
+
let rpcCheckId = 0;
|
|
130
194
|
async function checkConnection() {
|
|
195
|
+
const checkId = ++rpcCheckId;
|
|
131
196
|
status.value = "checking";
|
|
132
197
|
error.value = null;
|
|
133
198
|
console.info("[Vue Solana] Checking RPC connection", {
|
|
@@ -136,7 +201,14 @@ function createSolanaPlugin(options = {}) {
|
|
|
136
201
|
wsEndpoint: context.wsEndpoint
|
|
137
202
|
});
|
|
138
203
|
try {
|
|
139
|
-
const blockhash = await
|
|
204
|
+
const blockhash = await withTimeout(
|
|
205
|
+
context.connection.getLatestBlockhash(),
|
|
206
|
+
RPC_CHECK_TIMEOUT_MS,
|
|
207
|
+
`RPC connection check timed out after ${RPC_CHECK_TIMEOUT_MS / 1e3} seconds.`
|
|
208
|
+
);
|
|
209
|
+
if (checkId !== rpcCheckId) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
140
212
|
latestBlockhash.value = blockhash.blockhash;
|
|
141
213
|
status.value = "connected";
|
|
142
214
|
console.info("[Vue Solana] Connected", {
|
|
@@ -146,19 +218,44 @@ function createSolanaPlugin(options = {}) {
|
|
|
146
218
|
blockhash
|
|
147
219
|
});
|
|
148
220
|
} catch (cause) {
|
|
221
|
+
if (checkId !== rpcCheckId) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
149
224
|
status.value = "error";
|
|
150
225
|
error.value = cause instanceof Error ? cause.message : String(cause);
|
|
151
226
|
console.error("[Vue Solana] Connection failed", cause);
|
|
152
227
|
}
|
|
153
228
|
}
|
|
229
|
+
function refreshWallets() {
|
|
230
|
+
unsubscribeWallets ??= subscribeSolanaWallets(refreshWallets);
|
|
231
|
+
wallets.value = getRegisteredSolanaWallets();
|
|
232
|
+
if (selectedWallet.value) {
|
|
233
|
+
selectedWallet.value = wallets.value.find((nextWallet) => nextWallet.name === selectedWallet.value?.name) ?? null;
|
|
234
|
+
if (!selectedWallet.value) {
|
|
235
|
+
wallet.value = options.wallet ?? null;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function selectWallet(nextWallet) {
|
|
240
|
+
selectedWallet.value = nextWallet;
|
|
241
|
+
wallet.value = nextWallet ? adaptSolanaStandardWallet(nextWallet, {
|
|
242
|
+
chain: getSolanaChain(context.cluster),
|
|
243
|
+
onChange: () => triggerRef(wallet)
|
|
244
|
+
}) : options.wallet ?? null;
|
|
245
|
+
}
|
|
154
246
|
const vueContext = {
|
|
155
247
|
...context,
|
|
156
248
|
wallet,
|
|
157
249
|
status,
|
|
158
250
|
error,
|
|
159
251
|
latestBlockhash,
|
|
252
|
+
wallets,
|
|
253
|
+
selectedWallet,
|
|
160
254
|
checkConnection,
|
|
255
|
+
refreshWallets,
|
|
256
|
+
selectWallet,
|
|
161
257
|
setWallet(nextWallet) {
|
|
258
|
+
selectedWallet.value = null;
|
|
162
259
|
wallet.value = nextWallet;
|
|
163
260
|
}
|
|
164
261
|
};
|
|
@@ -168,5 +265,18 @@ function createSolanaPlugin(options = {}) {
|
|
|
168
265
|
};
|
|
169
266
|
}
|
|
170
267
|
const VueSolana = createSolanaPlugin;
|
|
268
|
+
function withTimeout(promise, timeoutMs, message) {
|
|
269
|
+
let timeoutId;
|
|
270
|
+
const timeout = new Promise((_, reject) => {
|
|
271
|
+
timeoutId = setTimeout(() => {
|
|
272
|
+
reject(new Error(message));
|
|
273
|
+
}, timeoutMs);
|
|
274
|
+
});
|
|
275
|
+
return Promise.race([promise, timeout]).finally(() => {
|
|
276
|
+
if (timeoutId) {
|
|
277
|
+
clearTimeout(timeoutId);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
}
|
|
171
281
|
|
|
172
|
-
export { VueSolana, createSolanaPlugin, solanaInjectionKey, useBalance, useConnection, useRpc, useSignAndSendTransaction, useSolana, useTransaction, useWallet };
|
|
282
|
+
export { VueSolana, createSolanaPlugin, solanaInjectionKey, useBalance, useConnection, useRpc, useSignAndSendTransaction, useSolana, useTransaction, useWallet, useWallets };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vue-solana/vue",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Vue plugin and composables for Solana applications.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@vue-solana/core": "0.1
|
|
41
|
+
"@vue-solana/core": "0.2.1"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"@solana/web3-compat": "^0.0.21",
|