@vue-solana/core 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 vue-solana
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # @vue-solana/core
2
+
3
+ Framework-agnostic Solana primitives used by the Vue Solana packages.
4
+
5
+ Use this package directly when you want connection helpers, shared wallet types, and transaction helpers without installing the Vue plugin.
6
+
7
+ `@vue-solana/core` does not replace `@solana/web3-compat`. Use `@solana/web3-compat` for raw Solana primitives like `Connection`, `PublicKey`, and transactions. Use `@vue-solana/core` for Vue Solana shared configuration, cluster endpoint defaults, wallet interfaces, and transaction helpers.
8
+
9
+ Official Solana docs:
10
+
11
+ - [Solana Documentation](https://solana.com/docs)
12
+ - [Solana RPC Methods](https://solana.com/docs/rpc)
13
+ - [Solana Clusters](https://solana.com/docs/references/clusters)
14
+
15
+ Full Vue Solana docs:
16
+
17
+ - [`@vue-solana/core`](https://vue-solana-docs.vercel.app/packages/core)
18
+ - [Getting Started](https://vue-solana-docs.vercel.app/getting-started)
19
+ - [Troubleshooting](https://vue-solana-docs.vercel.app/troubleshooting)
20
+
21
+ ## Install
22
+
23
+ ```sh
24
+ pnpm add @vue-solana/core @solana/web3-compat
25
+ ```
26
+
27
+ ```sh
28
+ npm install @vue-solana/core @solana/web3-compat
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ```ts
34
+ import { createSolanaContext } from "@vue-solana/core";
35
+
36
+ const solana = createSolanaContext({
37
+ cluster: "devnet",
38
+ });
39
+
40
+ const { blockhash } = await solana.connection.getLatestBlockhash();
41
+
42
+ console.log(solana.endpoint, blockhash);
43
+ ```
44
+
45
+ ## Configuration
46
+
47
+ ```ts
48
+ import type { SolanaConfig } from "@vue-solana/core";
49
+
50
+ const config: SolanaConfig = {
51
+ cluster: "devnet",
52
+ endpoint: "https://api.devnet.solana.com",
53
+ wsEndpoint: "wss://api.devnet.solana.com",
54
+ commitment: "confirmed",
55
+ autoConnect: false,
56
+ };
57
+ ```
58
+
59
+ Supported clusters are `mainnet-beta`, `testnet`, `devnet`, and `localnet`. If `endpoint` is omitted, the package uses the public Solana RPC endpoint for the selected cluster. If `wsEndpoint` is omitted, it is derived from the RPC endpoint.
60
+
61
+ Use `mainnet-beta` for Solana mainnet. This is Solana's official cluster name; the package intentionally does not use `mainnet` as an alias.
62
+
63
+ For development, use `devnet` and request free test SOL from the official faucet:
64
+
65
+ ```txt
66
+ https://faucet.solana.com
67
+ ```
68
+
69
+ ## API
70
+
71
+ - `DEFAULT_CLUSTER`: default cluster, currently `devnet`.
72
+ - `createSolanaConnection(config?)`: creates a `Connection`.
73
+ - `createSolanaContext(config?)`: creates `{ cluster, endpoint, wsEndpoint, connection }`.
74
+ - `getClusterEndpoint(cluster?)`: returns the HTTP RPC endpoint for a cluster.
75
+ - `getClusterWebSocketEndpoint(cluster?)`: returns the WebSocket endpoint for a cluster.
76
+ - `getWebSocketEndpoint(endpoint)`: converts `http`/`https` RPC URLs to `ws`/`wss` URLs.
77
+ - `isWalletConnected(wallet)`: checks whether a wallet is connected and has a public key.
78
+ - `assertWalletConnected(wallet)`: throws if the wallet is not connected.
79
+ - `assertWalletCanSign(wallet)`: throws if the wallet cannot sign transactions.
80
+ - `signAndSendTransaction(connection, wallet, transaction, options?)`: signs and sends a transaction using a configured wallet.
81
+
82
+ ## Wallet Interface
83
+
84
+ ```ts
85
+ import type { SolanaWallet } from "@vue-solana/core";
86
+
87
+ const wallet: SolanaWallet = {
88
+ publicKey: null,
89
+ connected: false,
90
+ connect: async () => {},
91
+ disconnect: async () => {},
92
+ signTransaction: async (transaction) => transaction,
93
+ };
94
+ ```
95
+
96
+ Browser wallets discovered through the Solana Wallet Standard are adapted into `SolanaWallet`. You can also provide a custom object that implements `SolanaWallet` for tests or custom adapters.
97
+
98
+ ## Examples
99
+
100
+ For complete runnable Vue and Nuxt examples that use this package through the framework integrations, see:
101
+
102
+ - [`examples/vue-vite`](https://vue-solana-docs.vercel.app/examples/vue-vite)
103
+ - [`examples/nuxt`](https://vue-solana-docs.vercel.app/examples/nuxt)
104
+
105
+ ## Known TypeScript Issue
106
+
107
+ `@solana/web3-compat@0.0.21` currently has broken TypeScript metadata. Runtime imports still use the real package, but TypeScript consumers may need a local declaration shim.
108
+
109
+ If TypeScript cannot resolve `@solana/web3-compat`, add `types/web3-compat.d.ts` to your app:
110
+
111
+ ```ts
112
+ declare module "@solana/web3-compat" {
113
+ export type { Commitment, SendOptions, TransactionSignature } from "@solana/web3.js";
114
+ export {
115
+ Connection,
116
+ Keypair,
117
+ PublicKey,
118
+ SystemProgram,
119
+ Transaction,
120
+ TransactionInstruction,
121
+ VersionedTransaction,
122
+ } from "@solana/web3.js";
123
+ }
124
+ ```
125
+
126
+ Make sure your `tsconfig.json` includes `types/**/*.d.ts` or another pattern that includes the shim.
127
+
128
+ ## Status
129
+
130
+ This package is early-stage. RPC helpers, wallet primitives, and transaction helpers are usable.
package/dist/index.cjs CHANGED
@@ -1,6 +1,14 @@
1
1
  'use strict';
2
2
 
3
3
  const web3Compat = require('@solana/web3-compat');
4
+ const app = require('@wallet-standard/app');
5
+ const features = require('@wallet-standard/features');
6
+ const walletStandardFeatures = require('@solana/wallet-standard-features');
7
+ const bs58 = require('bs58');
8
+
9
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
10
+
11
+ const bs58__default = /*#__PURE__*/_interopDefaultCompat(bs58);
4
12
 
5
13
  const DEFAULT_CLUSTER = "devnet";
6
14
  const CLUSTER_ENDPOINTS = {
@@ -82,13 +90,214 @@ async function signAndSendTransaction(connection, wallet, transaction, options)
82
90
  return connection.sendRawTransaction(rawTransaction, options);
83
91
  }
84
92
 
93
+ const SOLANA_CHAINS = [
94
+ "solana:mainnet",
95
+ "solana:testnet",
96
+ "solana:devnet",
97
+ "solana:localnet"
98
+ ];
99
+ function getSolanaChain(cluster) {
100
+ if (cluster === "mainnet-beta") {
101
+ return "solana:mainnet";
102
+ }
103
+ return `solana:${cluster}`;
104
+ }
105
+ function isSolanaStandardWallet(wallet) {
106
+ return features.StandardConnect in wallet.features && features.StandardDisconnect in wallet.features && wallet.chains.some((chain) => SOLANA_CHAINS.includes(chain));
107
+ }
108
+ function getRegisteredSolanaWallets() {
109
+ if (typeof window === "undefined") {
110
+ return [];
111
+ }
112
+ return app.getWallets().get().filter(isSolanaStandardWallet).map(createSolanaWalletInfo);
113
+ }
114
+ function subscribeSolanaWallets(listener) {
115
+ if (typeof window === "undefined") {
116
+ return () => {
117
+ };
118
+ }
119
+ const wallets = app.getWallets();
120
+ const offRegister = wallets.on("register", listener);
121
+ const offUnregister = wallets.on("unregister", listener);
122
+ return () => {
123
+ offRegister();
124
+ offUnregister();
125
+ };
126
+ }
127
+ function adaptSolanaStandardWallet(walletInfo, options = {}) {
128
+ const wallet = walletInfo.wallet;
129
+ let accounts = wallet.accounts;
130
+ let account = options.account;
131
+ let allowAccountUpdates = Boolean(options.account);
132
+ let connecting = false;
133
+ let disconnecting = false;
134
+ let manuallyDisconnected = false;
135
+ const eventsFeature = wallet.features[features.StandardEvents];
136
+ eventsFeature?.on("change", (properties) => {
137
+ if (properties.accounts) {
138
+ accounts = properties.accounts;
139
+ account = allowAccountUpdates && !manuallyDisconnected ? getSolanaAccount(accounts, options.chain) : void 0;
140
+ options.onChange?.();
141
+ }
142
+ });
143
+ return {
144
+ get publicKey() {
145
+ return account ? new web3Compat.PublicKey(account.publicKey) : null;
146
+ },
147
+ get connected() {
148
+ return Boolean(account);
149
+ },
150
+ get connecting() {
151
+ return connecting;
152
+ },
153
+ get disconnecting() {
154
+ return disconnecting;
155
+ },
156
+ async connect() {
157
+ connecting = true;
158
+ manuallyDisconnected = false;
159
+ options.onChange?.();
160
+ try {
161
+ const feature = wallet.features[features.StandardConnect];
162
+ const result = await feature.connect();
163
+ accounts = result.accounts;
164
+ allowAccountUpdates = true;
165
+ account = getSolanaAccount(accounts, options.chain);
166
+ if (!account) {
167
+ throw new Error("Solana wallet did not authorize a Solana account");
168
+ }
169
+ } finally {
170
+ connecting = false;
171
+ options.onChange?.();
172
+ }
173
+ },
174
+ async disconnect() {
175
+ const feature = wallet.features[features.StandardDisconnect];
176
+ disconnecting = true;
177
+ manuallyDisconnected = true;
178
+ allowAccountUpdates = false;
179
+ account = void 0;
180
+ options.onChange?.();
181
+ try {
182
+ await feature.disconnect();
183
+ accounts = [];
184
+ account = void 0;
185
+ } catch (error) {
186
+ manuallyDisconnected = false;
187
+ allowAccountUpdates = true;
188
+ account = getSolanaAccount(accounts, options.chain);
189
+ throw error;
190
+ } finally {
191
+ disconnecting = false;
192
+ options.onChange?.();
193
+ }
194
+ },
195
+ signTransaction: hasSignTransaction(wallet) ? async (transaction) => {
196
+ const activeAccount = getActiveAccount(account);
197
+ const [result] = await wallet.features[walletStandardFeatures.SolanaSignTransaction].signTransaction({
198
+ account: activeAccount,
199
+ transaction: serializeTransaction(transaction),
200
+ chain: options.chain
201
+ });
202
+ if (!result) {
203
+ throw new Error("Solana wallet did not return a signed transaction");
204
+ }
205
+ return deserializeTransaction(transaction, result.signedTransaction);
206
+ } : void 0,
207
+ signAllTransactions: hasSignTransaction(wallet) ? async (transactions) => {
208
+ const activeAccount = getActiveAccount(account);
209
+ const results = await wallet.features[walletStandardFeatures.SolanaSignTransaction].signTransaction(
210
+ ...transactions.map((transaction) => ({
211
+ account: activeAccount,
212
+ transaction: serializeTransaction(transaction),
213
+ chain: options.chain
214
+ }))
215
+ );
216
+ return results.map(
217
+ (result, index) => deserializeTransaction(transactions[index], result.signedTransaction)
218
+ );
219
+ } : void 0,
220
+ signAndSendTransaction: hasSignAndSendTransaction(wallet) ? async (transaction, sendOptions) => {
221
+ const activeAccount = getActiveAccount(account);
222
+ const [result] = await wallet.features[walletStandardFeatures.SolanaSignAndSendTransaction].signAndSendTransaction({
223
+ account: activeAccount,
224
+ transaction: serializeTransaction(transaction),
225
+ chain: options.chain ?? getSolanaAccountChain(activeAccount),
226
+ options: sendOptions
227
+ });
228
+ if (!result) {
229
+ throw new Error("Solana wallet did not return a transaction signature");
230
+ }
231
+ return { signature: bs58__default.encode(result.signature) };
232
+ } : void 0
233
+ };
234
+ }
235
+ function createSolanaWalletInfo(wallet) {
236
+ return {
237
+ name: wallet.name,
238
+ icon: wallet.icon,
239
+ chains: wallet.chains,
240
+ accounts: wallet.accounts.map((account) => ({
241
+ address: account.address,
242
+ publicKey: Uint8Array.from(account.publicKey),
243
+ chains: account.chains,
244
+ label: account.label,
245
+ icon: account.icon
246
+ })),
247
+ wallet
248
+ };
249
+ }
250
+ function getSolanaAccount(accounts, chain) {
251
+ return accounts.find((account) => account.chains.some((accountChain) => accountChain === chain)) ?? accounts.find(
252
+ (account) => account.chains.some((accountChain) => SOLANA_CHAINS.includes(accountChain))
253
+ );
254
+ }
255
+ function getActiveAccount(account) {
256
+ if (!account) {
257
+ throw new Error("Solana wallet is not connected");
258
+ }
259
+ return account;
260
+ }
261
+ function getSolanaAccountChain(account) {
262
+ const chain = account.chains.find(
263
+ (accountChain) => SOLANA_CHAINS.includes(accountChain)
264
+ );
265
+ if (!chain) {
266
+ throw new Error("Solana wallet account does not support a Solana chain");
267
+ }
268
+ return chain;
269
+ }
270
+ function hasSignTransaction(wallet) {
271
+ return walletStandardFeatures.SolanaSignTransaction in wallet.features;
272
+ }
273
+ function hasSignAndSendTransaction(wallet) {
274
+ return walletStandardFeatures.SolanaSignAndSendTransaction in wallet.features;
275
+ }
276
+ function serializeTransaction(transaction) {
277
+ if (transaction instanceof web3Compat.Transaction) {
278
+ return transaction.serialize({ requireAllSignatures: false, verifySignatures: false });
279
+ }
280
+ return transaction.serialize();
281
+ }
282
+ function deserializeTransaction(source, bytes) {
283
+ if (source instanceof web3Compat.Transaction) {
284
+ return web3Compat.Transaction.from(bytes);
285
+ }
286
+ return web3Compat.VersionedTransaction.deserialize(bytes);
287
+ }
288
+
85
289
  exports.DEFAULT_CLUSTER = DEFAULT_CLUSTER;
290
+ exports.adaptSolanaStandardWallet = adaptSolanaStandardWallet;
86
291
  exports.assertWalletCanSign = assertWalletCanSign;
87
292
  exports.assertWalletConnected = assertWalletConnected;
88
293
  exports.createSolanaConnection = createSolanaConnection;
89
294
  exports.createSolanaContext = createSolanaContext;
90
295
  exports.getClusterEndpoint = getClusterEndpoint;
91
296
  exports.getClusterWebSocketEndpoint = getClusterWebSocketEndpoint;
297
+ exports.getRegisteredSolanaWallets = getRegisteredSolanaWallets;
298
+ exports.getSolanaChain = getSolanaChain;
92
299
  exports.getWebSocketEndpoint = getWebSocketEndpoint;
300
+ exports.isSolanaStandardWallet = isSolanaStandardWallet;
93
301
  exports.isWalletConnected = isWalletConnected;
94
302
  exports.signAndSendTransaction = signAndSendTransaction;
303
+ exports.subscribeSolanaWallets = subscribeSolanaWallets;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { SendOptions, Commitment, Connection, Transaction, VersionedTransaction, PublicKey, TransactionSignature } from '@solana/web3-compat';
2
+ import { WalletAccount, Wallet } from '@wallet-standard/base';
2
3
 
3
- type SolanaCluster = 'mainnet-beta' | 'testnet' | 'devnet' | 'localnet';
4
+ type SolanaCluster = "mainnet-beta" | "testnet" | "devnet" | "localnet";
5
+ type SolanaChain = "solana:mainnet" | "solana:testnet" | "solana:devnet" | "solana:localnet";
4
6
  interface SolanaConfig {
5
7
  cluster?: SolanaCluster;
6
8
  endpoint?: string;
@@ -19,6 +21,7 @@ interface SolanaWallet {
19
21
  publicKey: PublicKey | null;
20
22
  connected: boolean;
21
23
  connecting?: boolean;
24
+ disconnecting?: boolean;
22
25
  connect: () => Promise<void>;
23
26
  disconnect: () => Promise<void>;
24
27
  signTransaction?: <T extends SolanaTransaction>(transaction: T) => Promise<T>;
@@ -27,6 +30,19 @@ interface SolanaWallet {
27
30
  signature: TransactionSignature;
28
31
  }>;
29
32
  }
33
+ interface SolanaWalletInfo {
34
+ name: string;
35
+ icon: string;
36
+ chains: readonly string[];
37
+ accounts: readonly {
38
+ address: string;
39
+ publicKey: Uint8Array;
40
+ chains: readonly string[];
41
+ label?: string;
42
+ icon?: string;
43
+ }[];
44
+ wallet: unknown;
45
+ }
30
46
  interface SendTransactionOptions extends SendOptions {
31
47
  skipPreflight?: boolean;
32
48
  }
@@ -41,11 +57,22 @@ declare function createSolanaContext(config?: SolanaConfig): SolanaContext;
41
57
 
42
58
  declare function signAndSendTransaction(connection: Connection, wallet: SolanaWallet, transaction: SolanaTransaction, options?: SendTransactionOptions): Promise<TransactionSignature>;
43
59
 
44
- declare function isWalletConnected(wallet: Pick<SolanaWallet, 'connected' | 'publicKey'> | null | undefined): boolean;
60
+ declare function isWalletConnected(wallet: Pick<SolanaWallet, "connected" | "publicKey"> | null | undefined): boolean;
45
61
  declare function assertWalletConnected(wallet: SolanaWallet | null | undefined): asserts wallet is SolanaWallet & {
46
- publicKey: NonNullable<SolanaWallet['publicKey']>;
62
+ publicKey: NonNullable<SolanaWallet["publicKey"]>;
47
63
  };
48
- declare function assertWalletCanSign(wallet: SolanaWallet | null | undefined): asserts wallet is SolanaWallet & Required<Pick<SolanaWallet, 'signTransaction'>>;
64
+ declare function assertWalletCanSign(wallet: SolanaWallet | null | undefined): asserts wallet is SolanaWallet & Required<Pick<SolanaWallet, "signTransaction">>;
65
+
66
+ interface AdaptSolanaWalletOptions {
67
+ chain?: SolanaChain;
68
+ account?: WalletAccount;
69
+ onChange?: () => void;
70
+ }
71
+ declare function getSolanaChain(cluster: SolanaCluster): SolanaChain;
72
+ declare function isSolanaStandardWallet(wallet: Wallet): boolean;
73
+ declare function getRegisteredSolanaWallets(): SolanaWalletInfo[];
74
+ declare function subscribeSolanaWallets(listener: () => void): () => void;
75
+ declare function adaptSolanaStandardWallet(walletInfo: SolanaWalletInfo, options?: AdaptSolanaWalletOptions): SolanaWallet;
49
76
 
50
- export { DEFAULT_CLUSTER, assertWalletCanSign, assertWalletConnected, createSolanaConnection, createSolanaContext, getClusterEndpoint, getClusterWebSocketEndpoint, getWebSocketEndpoint, isWalletConnected, signAndSendTransaction };
51
- export type { SendTransactionOptions, SolanaCluster, SolanaConfig, SolanaContext, SolanaTransaction, SolanaWallet };
77
+ export { DEFAULT_CLUSTER, adaptSolanaStandardWallet, assertWalletCanSign, assertWalletConnected, createSolanaConnection, createSolanaContext, getClusterEndpoint, getClusterWebSocketEndpoint, getRegisteredSolanaWallets, getSolanaChain, getWebSocketEndpoint, isSolanaStandardWallet, isWalletConnected, signAndSendTransaction, subscribeSolanaWallets };
78
+ export type { AdaptSolanaWalletOptions, SendTransactionOptions, SolanaChain, SolanaCluster, SolanaConfig, SolanaContext, SolanaTransaction, SolanaWallet, SolanaWalletInfo };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { SendOptions, Commitment, Connection, Transaction, VersionedTransaction, PublicKey, TransactionSignature } from '@solana/web3-compat';
2
+ import { WalletAccount, Wallet } from '@wallet-standard/base';
2
3
 
3
- type SolanaCluster = 'mainnet-beta' | 'testnet' | 'devnet' | 'localnet';
4
+ type SolanaCluster = "mainnet-beta" | "testnet" | "devnet" | "localnet";
5
+ type SolanaChain = "solana:mainnet" | "solana:testnet" | "solana:devnet" | "solana:localnet";
4
6
  interface SolanaConfig {
5
7
  cluster?: SolanaCluster;
6
8
  endpoint?: string;
@@ -19,6 +21,7 @@ interface SolanaWallet {
19
21
  publicKey: PublicKey | null;
20
22
  connected: boolean;
21
23
  connecting?: boolean;
24
+ disconnecting?: boolean;
22
25
  connect: () => Promise<void>;
23
26
  disconnect: () => Promise<void>;
24
27
  signTransaction?: <T extends SolanaTransaction>(transaction: T) => Promise<T>;
@@ -27,6 +30,19 @@ interface SolanaWallet {
27
30
  signature: TransactionSignature;
28
31
  }>;
29
32
  }
33
+ interface SolanaWalletInfo {
34
+ name: string;
35
+ icon: string;
36
+ chains: readonly string[];
37
+ accounts: readonly {
38
+ address: string;
39
+ publicKey: Uint8Array;
40
+ chains: readonly string[];
41
+ label?: string;
42
+ icon?: string;
43
+ }[];
44
+ wallet: unknown;
45
+ }
30
46
  interface SendTransactionOptions extends SendOptions {
31
47
  skipPreflight?: boolean;
32
48
  }
@@ -41,11 +57,22 @@ declare function createSolanaContext(config?: SolanaConfig): SolanaContext;
41
57
 
42
58
  declare function signAndSendTransaction(connection: Connection, wallet: SolanaWallet, transaction: SolanaTransaction, options?: SendTransactionOptions): Promise<TransactionSignature>;
43
59
 
44
- declare function isWalletConnected(wallet: Pick<SolanaWallet, 'connected' | 'publicKey'> | null | undefined): boolean;
60
+ declare function isWalletConnected(wallet: Pick<SolanaWallet, "connected" | "publicKey"> | null | undefined): boolean;
45
61
  declare function assertWalletConnected(wallet: SolanaWallet | null | undefined): asserts wallet is SolanaWallet & {
46
- publicKey: NonNullable<SolanaWallet['publicKey']>;
62
+ publicKey: NonNullable<SolanaWallet["publicKey"]>;
47
63
  };
48
- declare function assertWalletCanSign(wallet: SolanaWallet | null | undefined): asserts wallet is SolanaWallet & Required<Pick<SolanaWallet, 'signTransaction'>>;
64
+ declare function assertWalletCanSign(wallet: SolanaWallet | null | undefined): asserts wallet is SolanaWallet & Required<Pick<SolanaWallet, "signTransaction">>;
65
+
66
+ interface AdaptSolanaWalletOptions {
67
+ chain?: SolanaChain;
68
+ account?: WalletAccount;
69
+ onChange?: () => void;
70
+ }
71
+ declare function getSolanaChain(cluster: SolanaCluster): SolanaChain;
72
+ declare function isSolanaStandardWallet(wallet: Wallet): boolean;
73
+ declare function getRegisteredSolanaWallets(): SolanaWalletInfo[];
74
+ declare function subscribeSolanaWallets(listener: () => void): () => void;
75
+ declare function adaptSolanaStandardWallet(walletInfo: SolanaWalletInfo, options?: AdaptSolanaWalletOptions): SolanaWallet;
49
76
 
50
- export { DEFAULT_CLUSTER, assertWalletCanSign, assertWalletConnected, createSolanaConnection, createSolanaContext, getClusterEndpoint, getClusterWebSocketEndpoint, getWebSocketEndpoint, isWalletConnected, signAndSendTransaction };
51
- export type { SendTransactionOptions, SolanaCluster, SolanaConfig, SolanaContext, SolanaTransaction, SolanaWallet };
77
+ export { DEFAULT_CLUSTER, adaptSolanaStandardWallet, assertWalletCanSign, assertWalletConnected, createSolanaConnection, createSolanaContext, getClusterEndpoint, getClusterWebSocketEndpoint, getRegisteredSolanaWallets, getSolanaChain, getWebSocketEndpoint, isSolanaStandardWallet, isWalletConnected, signAndSendTransaction, subscribeSolanaWallets };
78
+ export type { AdaptSolanaWalletOptions, SendTransactionOptions, SolanaChain, SolanaCluster, SolanaConfig, SolanaContext, SolanaTransaction, SolanaWallet, SolanaWalletInfo };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { SendOptions, Commitment, Connection, Transaction, VersionedTransaction, PublicKey, TransactionSignature } from '@solana/web3-compat';
2
+ import { WalletAccount, Wallet } from '@wallet-standard/base';
2
3
 
3
- type SolanaCluster = 'mainnet-beta' | 'testnet' | 'devnet' | 'localnet';
4
+ type SolanaCluster = "mainnet-beta" | "testnet" | "devnet" | "localnet";
5
+ type SolanaChain = "solana:mainnet" | "solana:testnet" | "solana:devnet" | "solana:localnet";
4
6
  interface SolanaConfig {
5
7
  cluster?: SolanaCluster;
6
8
  endpoint?: string;
@@ -19,6 +21,7 @@ interface SolanaWallet {
19
21
  publicKey: PublicKey | null;
20
22
  connected: boolean;
21
23
  connecting?: boolean;
24
+ disconnecting?: boolean;
22
25
  connect: () => Promise<void>;
23
26
  disconnect: () => Promise<void>;
24
27
  signTransaction?: <T extends SolanaTransaction>(transaction: T) => Promise<T>;
@@ -27,6 +30,19 @@ interface SolanaWallet {
27
30
  signature: TransactionSignature;
28
31
  }>;
29
32
  }
33
+ interface SolanaWalletInfo {
34
+ name: string;
35
+ icon: string;
36
+ chains: readonly string[];
37
+ accounts: readonly {
38
+ address: string;
39
+ publicKey: Uint8Array;
40
+ chains: readonly string[];
41
+ label?: string;
42
+ icon?: string;
43
+ }[];
44
+ wallet: unknown;
45
+ }
30
46
  interface SendTransactionOptions extends SendOptions {
31
47
  skipPreflight?: boolean;
32
48
  }
@@ -41,11 +57,22 @@ declare function createSolanaContext(config?: SolanaConfig): SolanaContext;
41
57
 
42
58
  declare function signAndSendTransaction(connection: Connection, wallet: SolanaWallet, transaction: SolanaTransaction, options?: SendTransactionOptions): Promise<TransactionSignature>;
43
59
 
44
- declare function isWalletConnected(wallet: Pick<SolanaWallet, 'connected' | 'publicKey'> | null | undefined): boolean;
60
+ declare function isWalletConnected(wallet: Pick<SolanaWallet, "connected" | "publicKey"> | null | undefined): boolean;
45
61
  declare function assertWalletConnected(wallet: SolanaWallet | null | undefined): asserts wallet is SolanaWallet & {
46
- publicKey: NonNullable<SolanaWallet['publicKey']>;
62
+ publicKey: NonNullable<SolanaWallet["publicKey"]>;
47
63
  };
48
- declare function assertWalletCanSign(wallet: SolanaWallet | null | undefined): asserts wallet is SolanaWallet & Required<Pick<SolanaWallet, 'signTransaction'>>;
64
+ declare function assertWalletCanSign(wallet: SolanaWallet | null | undefined): asserts wallet is SolanaWallet & Required<Pick<SolanaWallet, "signTransaction">>;
65
+
66
+ interface AdaptSolanaWalletOptions {
67
+ chain?: SolanaChain;
68
+ account?: WalletAccount;
69
+ onChange?: () => void;
70
+ }
71
+ declare function getSolanaChain(cluster: SolanaCluster): SolanaChain;
72
+ declare function isSolanaStandardWallet(wallet: Wallet): boolean;
73
+ declare function getRegisteredSolanaWallets(): SolanaWalletInfo[];
74
+ declare function subscribeSolanaWallets(listener: () => void): () => void;
75
+ declare function adaptSolanaStandardWallet(walletInfo: SolanaWalletInfo, options?: AdaptSolanaWalletOptions): SolanaWallet;
49
76
 
50
- export { DEFAULT_CLUSTER, assertWalletCanSign, assertWalletConnected, createSolanaConnection, createSolanaContext, getClusterEndpoint, getClusterWebSocketEndpoint, getWebSocketEndpoint, isWalletConnected, signAndSendTransaction };
51
- export type { SendTransactionOptions, SolanaCluster, SolanaConfig, SolanaContext, SolanaTransaction, SolanaWallet };
77
+ export { DEFAULT_CLUSTER, adaptSolanaStandardWallet, assertWalletCanSign, assertWalletConnected, createSolanaConnection, createSolanaContext, getClusterEndpoint, getClusterWebSocketEndpoint, getRegisteredSolanaWallets, getSolanaChain, getWebSocketEndpoint, isSolanaStandardWallet, isWalletConnected, signAndSendTransaction, subscribeSolanaWallets };
78
+ export type { AdaptSolanaWalletOptions, SendTransactionOptions, SolanaChain, SolanaCluster, SolanaConfig, SolanaContext, SolanaTransaction, SolanaWallet, SolanaWalletInfo };
package/dist/index.mjs CHANGED
@@ -1,4 +1,8 @@
1
- import { Connection } from '@solana/web3-compat';
1
+ import { Connection, PublicKey, Transaction, VersionedTransaction } from '@solana/web3-compat';
2
+ import { getWallets } from '@wallet-standard/app';
3
+ import { StandardEvents, StandardDisconnect, StandardConnect } from '@wallet-standard/features';
4
+ import { SolanaSignAndSendTransaction, SolanaSignTransaction } from '@solana/wallet-standard-features';
5
+ import bs58 from 'bs58';
2
6
 
3
7
  const DEFAULT_CLUSTER = "devnet";
4
8
  const CLUSTER_ENDPOINTS = {
@@ -80,4 +84,200 @@ async function signAndSendTransaction(connection, wallet, transaction, options)
80
84
  return connection.sendRawTransaction(rawTransaction, options);
81
85
  }
82
86
 
83
- export { DEFAULT_CLUSTER, assertWalletCanSign, assertWalletConnected, createSolanaConnection, createSolanaContext, getClusterEndpoint, getClusterWebSocketEndpoint, getWebSocketEndpoint, isWalletConnected, signAndSendTransaction };
87
+ const SOLANA_CHAINS = [
88
+ "solana:mainnet",
89
+ "solana:testnet",
90
+ "solana:devnet",
91
+ "solana:localnet"
92
+ ];
93
+ function getSolanaChain(cluster) {
94
+ if (cluster === "mainnet-beta") {
95
+ return "solana:mainnet";
96
+ }
97
+ return `solana:${cluster}`;
98
+ }
99
+ function isSolanaStandardWallet(wallet) {
100
+ return StandardConnect in wallet.features && StandardDisconnect in wallet.features && wallet.chains.some((chain) => SOLANA_CHAINS.includes(chain));
101
+ }
102
+ function getRegisteredSolanaWallets() {
103
+ if (typeof window === "undefined") {
104
+ return [];
105
+ }
106
+ return getWallets().get().filter(isSolanaStandardWallet).map(createSolanaWalletInfo);
107
+ }
108
+ function subscribeSolanaWallets(listener) {
109
+ if (typeof window === "undefined") {
110
+ return () => {
111
+ };
112
+ }
113
+ const wallets = getWallets();
114
+ const offRegister = wallets.on("register", listener);
115
+ const offUnregister = wallets.on("unregister", listener);
116
+ return () => {
117
+ offRegister();
118
+ offUnregister();
119
+ };
120
+ }
121
+ function adaptSolanaStandardWallet(walletInfo, options = {}) {
122
+ const wallet = walletInfo.wallet;
123
+ let accounts = wallet.accounts;
124
+ let account = options.account;
125
+ let allowAccountUpdates = Boolean(options.account);
126
+ let connecting = false;
127
+ let disconnecting = false;
128
+ let manuallyDisconnected = false;
129
+ const eventsFeature = wallet.features[StandardEvents];
130
+ eventsFeature?.on("change", (properties) => {
131
+ if (properties.accounts) {
132
+ accounts = properties.accounts;
133
+ account = allowAccountUpdates && !manuallyDisconnected ? getSolanaAccount(accounts, options.chain) : void 0;
134
+ options.onChange?.();
135
+ }
136
+ });
137
+ return {
138
+ get publicKey() {
139
+ return account ? new PublicKey(account.publicKey) : null;
140
+ },
141
+ get connected() {
142
+ return Boolean(account);
143
+ },
144
+ get connecting() {
145
+ return connecting;
146
+ },
147
+ get disconnecting() {
148
+ return disconnecting;
149
+ },
150
+ async connect() {
151
+ connecting = true;
152
+ manuallyDisconnected = false;
153
+ options.onChange?.();
154
+ try {
155
+ const feature = wallet.features[StandardConnect];
156
+ const result = await feature.connect();
157
+ accounts = result.accounts;
158
+ allowAccountUpdates = true;
159
+ account = getSolanaAccount(accounts, options.chain);
160
+ if (!account) {
161
+ throw new Error("Solana wallet did not authorize a Solana account");
162
+ }
163
+ } finally {
164
+ connecting = false;
165
+ options.onChange?.();
166
+ }
167
+ },
168
+ async disconnect() {
169
+ const feature = wallet.features[StandardDisconnect];
170
+ disconnecting = true;
171
+ manuallyDisconnected = true;
172
+ allowAccountUpdates = false;
173
+ account = void 0;
174
+ options.onChange?.();
175
+ try {
176
+ await feature.disconnect();
177
+ accounts = [];
178
+ account = void 0;
179
+ } catch (error) {
180
+ manuallyDisconnected = false;
181
+ allowAccountUpdates = true;
182
+ account = getSolanaAccount(accounts, options.chain);
183
+ throw error;
184
+ } finally {
185
+ disconnecting = false;
186
+ options.onChange?.();
187
+ }
188
+ },
189
+ signTransaction: hasSignTransaction(wallet) ? async (transaction) => {
190
+ const activeAccount = getActiveAccount(account);
191
+ const [result] = await wallet.features[SolanaSignTransaction].signTransaction({
192
+ account: activeAccount,
193
+ transaction: serializeTransaction(transaction),
194
+ chain: options.chain
195
+ });
196
+ if (!result) {
197
+ throw new Error("Solana wallet did not return a signed transaction");
198
+ }
199
+ return deserializeTransaction(transaction, result.signedTransaction);
200
+ } : void 0,
201
+ signAllTransactions: hasSignTransaction(wallet) ? async (transactions) => {
202
+ const activeAccount = getActiveAccount(account);
203
+ const results = await wallet.features[SolanaSignTransaction].signTransaction(
204
+ ...transactions.map((transaction) => ({
205
+ account: activeAccount,
206
+ transaction: serializeTransaction(transaction),
207
+ chain: options.chain
208
+ }))
209
+ );
210
+ return results.map(
211
+ (result, index) => deserializeTransaction(transactions[index], result.signedTransaction)
212
+ );
213
+ } : void 0,
214
+ signAndSendTransaction: hasSignAndSendTransaction(wallet) ? async (transaction, sendOptions) => {
215
+ const activeAccount = getActiveAccount(account);
216
+ const [result] = await wallet.features[SolanaSignAndSendTransaction].signAndSendTransaction({
217
+ account: activeAccount,
218
+ transaction: serializeTransaction(transaction),
219
+ chain: options.chain ?? getSolanaAccountChain(activeAccount),
220
+ options: sendOptions
221
+ });
222
+ if (!result) {
223
+ throw new Error("Solana wallet did not return a transaction signature");
224
+ }
225
+ return { signature: bs58.encode(result.signature) };
226
+ } : void 0
227
+ };
228
+ }
229
+ function createSolanaWalletInfo(wallet) {
230
+ return {
231
+ name: wallet.name,
232
+ icon: wallet.icon,
233
+ chains: wallet.chains,
234
+ accounts: wallet.accounts.map((account) => ({
235
+ address: account.address,
236
+ publicKey: Uint8Array.from(account.publicKey),
237
+ chains: account.chains,
238
+ label: account.label,
239
+ icon: account.icon
240
+ })),
241
+ wallet
242
+ };
243
+ }
244
+ function getSolanaAccount(accounts, chain) {
245
+ return accounts.find((account) => account.chains.some((accountChain) => accountChain === chain)) ?? accounts.find(
246
+ (account) => account.chains.some((accountChain) => SOLANA_CHAINS.includes(accountChain))
247
+ );
248
+ }
249
+ function getActiveAccount(account) {
250
+ if (!account) {
251
+ throw new Error("Solana wallet is not connected");
252
+ }
253
+ return account;
254
+ }
255
+ function getSolanaAccountChain(account) {
256
+ const chain = account.chains.find(
257
+ (accountChain) => SOLANA_CHAINS.includes(accountChain)
258
+ );
259
+ if (!chain) {
260
+ throw new Error("Solana wallet account does not support a Solana chain");
261
+ }
262
+ return chain;
263
+ }
264
+ function hasSignTransaction(wallet) {
265
+ return SolanaSignTransaction in wallet.features;
266
+ }
267
+ function hasSignAndSendTransaction(wallet) {
268
+ return SolanaSignAndSendTransaction in wallet.features;
269
+ }
270
+ function serializeTransaction(transaction) {
271
+ if (transaction instanceof Transaction) {
272
+ return transaction.serialize({ requireAllSignatures: false, verifySignatures: false });
273
+ }
274
+ return transaction.serialize();
275
+ }
276
+ function deserializeTransaction(source, bytes) {
277
+ if (source instanceof Transaction) {
278
+ return Transaction.from(bytes);
279
+ }
280
+ return VersionedTransaction.deserialize(bytes);
281
+ }
282
+
283
+ export { DEFAULT_CLUSTER, adaptSolanaStandardWallet, assertWalletCanSign, assertWalletConnected, createSolanaConnection, createSolanaContext, getClusterEndpoint, getClusterWebSocketEndpoint, getRegisteredSolanaWallets, getSolanaChain, getWebSocketEndpoint, isSolanaStandardWallet, isWalletConnected, signAndSendTransaction, subscribeSolanaWallets };
package/package.json CHANGED
@@ -1,22 +1,26 @@
1
1
  {
2
2
  "name": "@vue-solana/core",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Framework-agnostic primitives for Vue Solana libraries.",
5
5
  "license": "MIT",
6
- "type": "module",
7
- "homepage": "https://github.com/vue-solana/vue-solana#readme",
6
+ "keywords": [
7
+ "solana",
8
+ "vue",
9
+ "nuxt",
10
+ "web3",
11
+ "wallet",
12
+ "rpc"
13
+ ],
14
+ "homepage": "https://vue-solana-docs.vercel.app/packages/core",
15
+ "bugs": {
16
+ "url": "https://github.com/vue-solana/vue-solana/issues"
17
+ },
8
18
  "repository": {
9
19
  "type": "git",
10
20
  "url": "git+https://github.com/vue-solana/vue-solana.git",
11
21
  "directory": "packages/core"
12
22
  },
13
- "bugs": {
14
- "url": "https://github.com/vue-solana/vue-solana/issues"
15
- },
16
- "keywords": ["solana", "vue", "wallet", "rpc", "web3"],
17
- "publishConfig": {
18
- "access": "public"
19
- },
23
+ "type": "module",
20
24
  "main": "./dist/index.cjs",
21
25
  "module": "./dist/index.mjs",
22
26
  "types": "./dist/index.d.ts",
@@ -27,18 +31,28 @@
27
31
  "require": "./dist/index.cjs"
28
32
  }
29
33
  },
30
- "files": ["dist"],
31
- "scripts": {
32
- "build": "unbuild",
33
- "dev": "unbuild --stub",
34
- "typecheck": "tsc --noEmit",
35
- "clean": "rm -rf dist"
34
+ "files": [
35
+ "dist"
36
+ ],
37
+ "publishConfig": {
38
+ "access": "public"
36
39
  },
37
40
  "dependencies": {
38
- "@solana/web3-compat": "^0.0.21"
41
+ "@solana/wallet-standard-features": "^1.3.0",
42
+ "@solana/web3-compat": "^0.0.21",
43
+ "@wallet-standard/app": "^1.1.1",
44
+ "@wallet-standard/base": "^1.1.1",
45
+ "@wallet-standard/features": "^1.1.1",
46
+ "bs58": "^6.0.0"
39
47
  },
40
48
  "devDependencies": {
41
49
  "typescript": "^5.8.3",
42
50
  "unbuild": "^3.5.0"
51
+ },
52
+ "scripts": {
53
+ "build": "unbuild",
54
+ "dev": "unbuild --stub",
55
+ "typecheck": "tsc --noEmit",
56
+ "clean": "rm -rf dist"
43
57
  }
44
- }
58
+ }