@revibase/wallet-standard 0.8.5

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) 2025 Revibase
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,216 @@
1
+ # @revibase/wallet-standard
2
+
3
+ A [Wallet Standard](https://github.com/wallet-standard/wallet-standard) wrapper
4
+ around [`@revibase/lite`](../lite). Once a dApp registers it, Revibase appears in
5
+ that dApp's wallet picker through the standard
6
+ `registerWallet()` → `getWallets()` mechanism — the same registry the Mobile
7
+ Wallet Adapter entry uses — on both **desktop and mobile web**. dApps built on
8
+ `@solana/wallet-adapter`, wallet-standard modals, or framework-kit ConnectorKit
9
+ then connect to it like any other wallet.
10
+
11
+ > **This is opt-in per dApp, not auto-injected.** Unlike an extension wallet
12
+ > (Phantom, Solflare) that injects itself on every page, Revibase is an npm
13
+ > package. It only shows up in dApps that bundle this package **and** complete
14
+ > the backend setup below. See [Setup](#setup) and
15
+ > [How authorization works](#how-authorization-works).
16
+
17
+ ```bash
18
+ pnpm add @revibase/wallet-standard @revibase/lite
19
+ ```
20
+
21
+ Peer dependencies (provided by the host app, deduped to one copy):
22
+ `@wallet-standard/base`, `@wallet-standard/features`,
23
+ `@solana/wallet-standard-features`, `@solana/wallet-standard-chains`.
24
+
25
+ ## Quick start (checklist)
26
+
27
+ 1. **Generate keys** locally — one terminal command, no signup (Step 1).
28
+ 2. **Publish** `/.well-known/revibase.json` (public key + app title/description) at your origin.
29
+ 3. **Add a backend** route `POST /api/clientAuthorization` (uses your private key).
30
+ 4. **Register** the wallet on the frontend: `registerRevibaseWallet(new RevibaseProvider({ rpcEndpoint }))`.
31
+
32
+ That's it — "Revibase" then shows up in your wallet picker. Details below.
33
+
34
+ ## Setup
35
+
36
+ Integrating the Revibase wallet has **two layers**. Both are required — even
37
+ connecting (passkey sign-in) goes through your backend.
38
+
39
+ ### Step 1 — Generate keys (one-time, local)
40
+
41
+ Generate your own **Ed25519 / EdDSA** client keypair in your terminal — no
42
+ signup, no external service. Save as `gen-keys.mjs` and run `node gen-keys.mjs`:
43
+
44
+ ```js
45
+ // gen-keys.mjs — uses only Node built-ins, no dependencies
46
+ import { generateKeyPairSync } from "node:crypto";
47
+
48
+ const alg = "EdDSA";
49
+ const { publicKey, privateKey } = generateKeyPairSync("ed25519");
50
+ const b64 = (key) =>
51
+ Buffer.from(
52
+ JSON.stringify({ ...key.export({ format: "jwk" }), alg, use: "sig" }),
53
+ ).toString("base64");
54
+
55
+ console.log("PRIVATE_KEY=" + b64(privateKey)); // keep secret, server-only
56
+ console.log("PUBLIC_KEY=" + b64(publicKey)); // safe to publish
57
+ ```
58
+
59
+ It prints two base64 strings:
60
+
61
+ - **`PRIVATE_KEY`** — server-only env var; signs authorization requests (Step 3).
62
+ Never expose it to the browser or commit it.
63
+ - **`PUBLIC_KEY`** — backend env var; you also publish it (Step 2).
64
+
65
+ ### Step 2 — Publish `/.well-known/revibase.json`
66
+
67
+ Serve this at your app's origin (e.g. `https://your-app.com/.well-known/revibase.json`).
68
+ Revibase's auth UI fetches it to verify requests really came from your origin and
69
+ to show users *which app* is asking for approval.
70
+
71
+ ```json
72
+ {
73
+ "clientJwk": "<your PUBLIC_KEY from Step 1>",
74
+ "title": "Your App",
75
+ "description": "Short description shown in the approval prompt"
76
+ }
77
+ ```
78
+
79
+ ### Step 3 — Backend endpoint `POST /api/clientAuthorization`
80
+
81
+ Keep `PRIVATE_KEY` server-only. Install the WebAuthn verifier alongside the SDK:
82
+ `pnpm add @revibase/lite @simplewebauthn/server`.
83
+
84
+ ```ts
85
+ // app/api/clientAuthorization/route.ts (Next.js example)
86
+ import { processClientAuthCallback } from "@revibase/lite/server";
87
+
88
+ export async function POST(req: Request) {
89
+ try {
90
+ const result = await processClientAuthCallback({
91
+ request: await req.json(),
92
+ publicKey: process.env.PUBLIC_KEY!, // Revibase client public key (base64)
93
+ privateKey: process.env.PRIVATE_KEY!, // your private key — server-only
94
+ allowedClientOrigins: [process.env.CLIENT_ORIGIN!], // e.g. "https://your-app.com"
95
+ });
96
+ return Response.json(result);
97
+ } catch (e) {
98
+ return Response.json(
99
+ { error: e instanceof Error ? e.message : String(e) },
100
+ { status: 500 },
101
+ );
102
+ }
103
+ }
104
+ ```
105
+
106
+ See the [`@revibase/lite` README](../lite/README.md) for the full backend
107
+ reference (including the optional Jito endpoints used by `executeTransaction`).
108
+
109
+ ### Step 4 — Register the wallet (frontend)
110
+
111
+ ```ts
112
+ import { RevibaseProvider } from "@revibase/lite";
113
+ import { registerRevibaseWallet } from "@revibase/wallet-standard";
114
+
115
+ const provider = new RevibaseProvider({
116
+ rpcEndpoint: "https://api.mainnet-beta.solana.com",
117
+ });
118
+
119
+ // Call once at startup. Order vs. your wallet-adapter mount doesn't matter —
120
+ // registerWallet dispatches an event the app listens for either way.
121
+ // By default the provider POSTs to YOUR /api/clientAuthorization (same origin).
122
+ registerRevibaseWallet(provider);
123
+ ```
124
+
125
+ "Revibase" now appears in the wallet picker. Selecting it triggers the passkey
126
+ sign-in popup/iframe; transactions are approved with the passkey and broadcast
127
+ by Revibase.
128
+
129
+ ## How authorization works
130
+
131
+ Revibase ties each request to your app's origin via the keypair from Step 1:
132
+
133
+ 1. The frontend (`RevibaseProvider`) POSTs the request to your
134
+ `/api/clientAuthorization`.
135
+ 2. Your backend signs the request challenge as a JWS with your **private key**
136
+ and rejects any `clientOrigin` not in `allowedClientOrigins`.
137
+ 3. `auth.revibase.com` fetches `your-origin/.well-known/revibase.json`, verifies
138
+ the JWS against your **public key**, and shows the user your app's title +
139
+ description before they approve with their passkey.
140
+
141
+ This is why a dApp that imports the adapter but skips Steps 1–3 will still show
142
+ "Revibase" in its picker, but every operation fails at `/api/clientAuthorization`.
143
+
144
+ ### Options
145
+
146
+ ```ts
147
+ registerRevibaseWallet(provider, {
148
+ name: "Revibase", // display name
149
+ icon: "data:image/svg+xml;base64,...", // custom data-URI icon
150
+ chains: ["solana:mainnet"], // defaults to mainnet + devnet
151
+ });
152
+ ```
153
+
154
+ ## Supported features
155
+
156
+ | Feature | Supported | Notes |
157
+ | ------- | --------- | ----- |
158
+ | `standard:connect` | ✅ | Runs Revibase passkey sign-in, exposes the vault account |
159
+ | `standard:disconnect` | ✅ | Clears the connected account |
160
+ | `standard:events` | ✅ | Emits `change` when accounts change |
161
+ | `solana:signAndSendTransaction` | ✅ | Rebuilds as a vault-paid tx, signs with passkey, broadcasts |
162
+ | `solana:signTransaction` | ❌ | Not possible — see Constraints |
163
+ | `solana:signMessage` | ❌ | Incompatible by design — ed25519-only output, see Constraints |
164
+ | `solana:signIn` (SIWS) | ❌ | Incompatible by design — ed25519-only output, see Constraints |
165
+
166
+ ## Constraints (read this)
167
+
168
+ These come from Revibase's architecture, not the wrapper:
169
+
170
+ - **No raw `signTransaction`.** A Revibase approval is a secp256r1/WebAuthn proof
171
+ consumed **on-chain** by the `multi_wallet` program — not an ed25519 signature
172
+ over the wire. There is no signed-but-unsent transaction to hand back, so only
173
+ `solana:signAndSendTransaction` is offered. dApps that strictly require
174
+ sign-only will skip Revibase gracefully.
175
+ - **The dApp's fee payer / blockhash are replaced.** `executeTransaction` rebuilds
176
+ the transaction with the Revibase vault as payer and its own fee payer/blockhash.
177
+ The wrapper decodes the incoming serialized transaction back into instructions
178
+ (resolving address lookup tables via RPC) and feeds those instructions to
179
+ Revibase. Anything the dApp encoded in the fee payer/blockhash is discarded.
180
+ - **`account.address` is the vault** (`UserInfo.walletAddress`), a PDA — not an
181
+ ed25519 key. `account.publicKey` is the decoded address bytes; don't ed25519-verify
182
+ against it.
183
+ - **`solana:signIn` / `solana:signMessage` are intentionally omitted — permanently.**
184
+ These features exist so a dApp can verify a signature **off-chain against the
185
+ account's key**, and the Wallet Standard types hardcode that to ed25519
186
+ (`signatureType?: 'ed25519'`, and "if not provided, the signature must be
187
+ Ed25519"). Revibase is fundamentally incompatible with that model:
188
+ - **Curve:** the passkey signs with **secp256r1**, so `ed25519.verify(...)` fails.
189
+ - **Envelope:** WebAuthn does not sign the raw message — it signs
190
+ `authenticatorData ‖ sha256(clientDataJSON)` (the message is the embedded
191
+ challenge), so the signature won't verify against the returned `signedMessage`
192
+ bytes even with a secp256r1 verifier.
193
+ - **Key:** the verifying key is the passkey's secp256r1 public key, not
194
+ `account.publicKey` (the vault PDA).
195
+
196
+ Revibase instead authenticates the user via the passkey through its own backend
197
+ (`/api/clientAuthorization`). dApps that prefer SIWS simply fall back to
198
+ `standard:connect`, which is the correct behavior here.
199
+
200
+ ## Public API
201
+
202
+ - `registerRevibaseWallet(provider, options?) => RevibaseWallet` — register and return the wallet.
203
+ - `RevibaseWallet` — the Wallet Standard wallet class (construct directly for custom registration).
204
+ - `RevibaseWalletAccount` — the account type backing a connected vault.
205
+ - `decompileTransactionToInstructions(serializedTx, rpc)` — helper used internally; exported for reuse/testing.
206
+ - `REVIBASE_ICON` — the default data-URI icon.
207
+
208
+ ## Tests
209
+
210
+ Headless checks live in `test/` (run with Node after `pnpm build`):
211
+
212
+ ```bash
213
+ pnpm build
214
+ node test/verify.mjs # wallet object shape + decompile round-trip
215
+ node test/discover.mjs # registerRevibaseWallet -> getWallets() discovery
216
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict';var kit=require('@solana/kit'),wallet=require('@wallet-standard/wallet'),core=require('@revibase/core'),lite=require('@revibase/lite'),walletStandardChains=require('@solana/wallet-standard-chains'),walletStandardFeatures=require('@solana/wallet-standard-features'),features=require('@wallet-standard/features');async function s(n,t){let e=kit.getTransactionDecoder().decode(n),r=kit.getCompiledTransactionMessageDecoder().decode(e.messageBytes);return [...(await kit.decompileTransactionMessageFetchingLookupTables(r,t)).instructions]}var i=`data:image/svg+xml;base64,${m('<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><rect width="64" height="64" rx="14" fill="#0B0B0F"/><path d="M20 44V20h13c6 0 10 3.6 10 9 0 3.8-2 6.6-5.3 8L44 44h-7l-5.4-6.4H27V44h-7Zm7-12.4h5.4c2.4 0 3.8-1.3 3.8-3.3s-1.4-3.3-3.8-3.3H27v6.6Z" fill="#fff"/></svg>')}`;function m(n){return typeof btoa=="function"?btoa(unescape(encodeURIComponent(n))):Buffer.from(n,"utf-8").toString("base64")}var a=class extends wallet.ReadonlyWalletAccount{constructor(t,e){super({address:t,publicKey:new Uint8Array(kit.getAddressEncoder().encode(kit.address(t))),chains:e,features:["solana:signAndSendTransaction"]});}};var x="Revibase",C=[walletStandardChains.SOLANA_MAINNET_CHAIN,walletStandardChains.SOLANA_DEVNET_CHAIN],o=class{#r;#o;#s;#a;#e=null;#t=null;#n=[];constructor(t,e){this.#r=t,this.#o=e?.name??x,this.#s=e?.icon??i,this.#a=e?.chains??C;}get version(){return "1.0.0"}get name(){return this.#o}get icon(){return this.#s}get chains(){return this.#a.slice()}get accounts(){return this.#e?[this.#e]:[]}get features(){return {[features.StandardConnect]:{version:"1.0.0",connect:this.#c},[features.StandardDisconnect]:{version:"1.0.0",disconnect:this.#d},[features.StandardEvents]:{version:"1.0.0",on:this.#l},[walletStandardFeatures.SolanaSignAndSendTransaction]:{version:"1.0.0",supportedTransactionVersions:["legacy",0],signAndSendTransaction:this.#p}}}#c=async t=>{if(!this.#e){if(t?.silent)return {accounts:this.accounts};let{user:e}=await lite.signIn(this.#r);if(!e.walletAddress)throw new Error("Revibase sign-in returned no walletAddress; cannot expose an account.");this.#t=e,this.#e=new a(e.walletAddress,this.#a),this.#i({accounts:this.accounts});}return {accounts:this.accounts}};#d=async()=>{this.#e&&(this.#e=null,this.#t=null,this.#i({accounts:this.accounts}));};#l=(t,e)=>t!=="change"?()=>{}:(this.#n.push(e),()=>{let r=this.#n.indexOf(e);r!==-1&&this.#n.splice(r,1);});#i(t){for(let e of this.#n.slice())e(t);}#p=async(...t)=>{if(!this.#t)throw new Error("Wallet not connected. Call connect() first.");let e=core.getSolanaRpc(),r=[];for(let{transaction:c}of t){let l=await s(c,e),{txSig:d}=await lite.executeTransaction(this.#r,{instructions:l,signer:this.#t});if(!d)throw new Error("Revibase did not return a transaction signature.");r.push({signature:new Uint8Array(kit.getBase58Encoder().encode(d))});}return r}};function M(n,t){let e=new o(n,t);return wallet.registerWallet(e),e}
2
+ exports.REVIBASE_ICON=i;exports.RevibaseWallet=o;exports.RevibaseWalletAccount=a;exports.decompileTransactionToInstructions=s;exports.registerRevibaseWallet=M;//# sourceMappingURL=index.cjs.map
3
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/decompile.ts","../src/icon.ts","../src/account.ts","../src/wallet.ts","../src/register.ts"],"names":["decompileTransactionToInstructions","serializedTransaction","rpc","transaction","getTransactionDecoder","compiledMessage","getCompiledTransactionMessageDecoder","decompileTransactionMessageFetchingLookupTables","REVIBASE_ICON","btoaUtf8","input","RevibaseWalletAccount","ReadonlyWalletAccount","walletAddress","chains","getAddressEncoder","address","DEFAULT_NAME","DEFAULT_CHAINS","SOLANA_MAINNET_CHAIN","SOLANA_DEVNET_CHAIN","RevibaseWallet","#provider","#name","#icon","#chains","#account","#user","#changeListeners","provider","options","StandardConnect","#connect","StandardDisconnect","#disconnect","StandardEvents","#on","SolanaSignAndSendTransaction","#signAndSendTransaction","user","signIn","#emitChange","event","listener","index","properties","inputs","getSolanaRpc","outputs","instructions","txSig","executeTransaction","getBase58Encoder","registerRevibaseWallet","wallet","registerWallet"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n decompileTransactionMessageFetchingLookupTables,\n getCompiledTransactionMessageDecoder,\n getTransactionDecoder,\n type Instruction,\n type Rpc,\n type SolanaRpcApi,\n} from \"@solana/kit\";\n\n/**\n * Wallet Standard hands the wallet a fully serialized transaction. Revibase,\n * however, rebuilds its own vault-paid transaction from raw instructions\n * (see `executeTransaction` in @revibase/lite). So we decode the wire\n * transaction back into instructions, resolving any address lookup tables via\n * the RPC. The original fee payer and blockhash are intentionally dropped —\n * Revibase sets the vault as payer and supplies its own fee payer/blockhash.\n */\nexport async function decompileTransactionToInstructions(\n serializedTransaction: Uint8Array,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<Instruction[]> {\n const transaction = getTransactionDecoder().decode(serializedTransaction);\n const compiledMessage = getCompiledTransactionMessageDecoder().decode(\n transaction.messageBytes,\n );\n const decompiled = await decompileTransactionMessageFetchingLookupTables(\n compiledMessage,\n rpc,\n );\n return [...decompiled.instructions];\n}\n","import type { WalletIcon } from \"@wallet-standard/base\";\n\n/**\n * Inline (data-URI) wallet icon shown in dApp wallet pickers. Kept as an SVG\n * data URI so the package has no binary assets and works in any bundler.\n * Replace with the official Revibase brand mark when available.\n */\nexport const REVIBASE_ICON: WalletIcon =\n `data:image/svg+xml;base64,${btoaUtf8(\n `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">` +\n `<rect width=\"64\" height=\"64\" rx=\"14\" fill=\"#0B0B0F\"/>` +\n `<path d=\"M20 44V20h13c6 0 10 3.6 10 9 0 3.8-2 6.6-5.3 8L44 44h-7l-5.4-6.4H27V44h-7Zm7-12.4h5.4c2.4 0 3.8-1.3 3.8-3.3s-1.4-3.3-3.8-3.3H27v6.6Z\" fill=\"#fff\"/>` +\n `</svg>`,\n )}` as WalletIcon;\n\n/** Minimal, environment-agnostic UTF-8 safe base64 encoder. */\nfunction btoaUtf8(input: string): string {\n if (typeof btoa === \"function\") {\n return btoa(unescape(encodeURIComponent(input)));\n }\n // Node fallback (used in tests / SSR)\n return Buffer.from(input, \"utf-8\").toString(\"base64\");\n}\n","import { address, getAddressEncoder } from \"@solana/kit\";\nimport type { IdentifierString } from \"@wallet-standard/base\";\nimport { ReadonlyWalletAccount } from \"@wallet-standard/wallet\";\n\n/**\n * A Wallet Standard account backed by a Revibase multisig vault.\n *\n * `address` is the on-chain vault (`UserInfo.walletAddress`) — the account a\n * dApp transacts with. `publicKey` is the decoded bytes of that address; note\n * it is a PDA, not an ed25519 keypair, so callers cannot ed25519-verify\n * signatures against it.\n */\nexport class RevibaseWalletAccount extends ReadonlyWalletAccount {\n constructor(walletAddress: string, chains: readonly IdentifierString[]) {\n super({\n address: walletAddress,\n publicKey: new Uint8Array(\n getAddressEncoder().encode(address(walletAddress)),\n ),\n chains,\n // Only sign-and-send is supported today (see README \"Constraints\").\n features: [\"solana:signAndSendTransaction\"],\n });\n }\n}\n","import { getSolanaRpc, type UserInfo } from \"@revibase/core\";\nimport {\n executeTransaction,\n signIn,\n type RevibaseProvider,\n} from \"@revibase/lite\";\nimport { getBase58Encoder } from \"@solana/kit\";\nimport {\n SOLANA_DEVNET_CHAIN,\n SOLANA_MAINNET_CHAIN,\n} from \"@solana/wallet-standard-chains\";\nimport {\n SolanaSignAndSendTransaction,\n type SolanaSignAndSendTransactionFeature,\n type SolanaSignAndSendTransactionMethod,\n} from \"@solana/wallet-standard-features\";\nimport type {\n IdentifierArray,\n Wallet,\n WalletAccount,\n WalletIcon,\n} from \"@wallet-standard/base\";\nimport {\n StandardConnect,\n StandardDisconnect,\n StandardEvents,\n type StandardConnectFeature,\n type StandardConnectMethod,\n type StandardDisconnectFeature,\n type StandardDisconnectMethod,\n type StandardEventsChangeProperties,\n type StandardEventsFeature,\n type StandardEventsListeners,\n type StandardEventsOnMethod,\n} from \"@wallet-standard/features\";\nimport { RevibaseWalletAccount } from \"./account\";\nimport { decompileTransactionToInstructions } from \"./decompile\";\nimport { REVIBASE_ICON } from \"./icon\";\n\nexport type RevibaseWalletOptions = {\n /** Display name shown in wallet pickers. Defaults to \"Revibase\". */\n name?: string;\n /** Inline icon (data URI). Defaults to the bundled Revibase mark. */\n icon?: WalletIcon;\n /** Chains to advertise. Defaults to Solana mainnet + devnet. */\n chains?: IdentifierArray;\n};\n\nconst DEFAULT_NAME = \"Revibase\";\nconst DEFAULT_CHAINS: IdentifierArray = [\n SOLANA_MAINNET_CHAIN,\n SOLANA_DEVNET_CHAIN,\n];\n\ntype RevibaseFeature = StandardConnectFeature &\n StandardDisconnectFeature &\n StandardEventsFeature &\n SolanaSignAndSendTransactionFeature;\n\n/**\n * Wraps an existing {@link RevibaseProvider} as a Wallet Standard wallet so\n * Solana dApps discover and connect to Revibase via `registerWallet()` /\n * `getWallets()`.\n *\n * Supported features: `standard:connect`, `standard:disconnect`,\n * `standard:events`, and `solana:signAndSendTransaction`. Raw\n * `solana:signTransaction`, `solana:signMessage`, and `solana:signIn` are\n * intentionally NOT advertised — see the package README \"Constraints\".\n */\nexport class RevibaseWallet implements Wallet {\n readonly #provider: RevibaseProvider;\n readonly #name: string;\n readonly #icon: WalletIcon;\n readonly #chains: IdentifierArray;\n\n #account: RevibaseWalletAccount | null = null;\n #user: UserInfo | null = null;\n // The only Wallet Standard event is \"change\".\n readonly #changeListeners: StandardEventsListeners[\"change\"][] = [];\n\n constructor(provider: RevibaseProvider, options?: RevibaseWalletOptions) {\n this.#provider = provider;\n this.#name = options?.name ?? DEFAULT_NAME;\n this.#icon = options?.icon ?? REVIBASE_ICON;\n this.#chains = options?.chains ?? DEFAULT_CHAINS;\n }\n\n get version() {\n return \"1.0.0\" as const;\n }\n\n get name() {\n return this.#name;\n }\n\n get icon() {\n return this.#icon;\n }\n\n get chains() {\n return this.#chains.slice();\n }\n\n get accounts(): readonly WalletAccount[] {\n return this.#account ? [this.#account] : [];\n }\n\n get features(): RevibaseFeature {\n return {\n [StandardConnect]: {\n version: \"1.0.0\",\n connect: this.#connect,\n },\n [StandardDisconnect]: {\n version: \"1.0.0\",\n disconnect: this.#disconnect,\n },\n [StandardEvents]: {\n version: \"1.0.0\",\n on: this.#on,\n },\n [SolanaSignAndSendTransaction]: {\n version: \"1.0.0\",\n supportedTransactionVersions: [\"legacy\", 0],\n signAndSendTransaction: this.#signAndSendTransaction,\n },\n };\n }\n\n #connect: StandardConnectMethod = async (input) => {\n if (!this.#account) {\n if (input?.silent) {\n // Revibase has no silent/auto-connect path (requires a passkey prompt).\n return { accounts: this.accounts };\n }\n const { user } = await signIn(this.#provider);\n if (!user.walletAddress) {\n throw new Error(\n \"Revibase sign-in returned no walletAddress; cannot expose an account.\",\n );\n }\n this.#user = user;\n this.#account = new RevibaseWalletAccount(user.walletAddress, this.#chains);\n this.#emitChange({ accounts: this.accounts });\n }\n return { accounts: this.accounts };\n };\n\n #disconnect: StandardDisconnectMethod = async () => {\n if (this.#account) {\n this.#account = null;\n this.#user = null;\n this.#emitChange({ accounts: this.accounts });\n }\n };\n\n #on: StandardEventsOnMethod = (event, listener) => {\n if (event !== \"change\") return () => {};\n this.#changeListeners.push(listener);\n return () => {\n const index = this.#changeListeners.indexOf(listener);\n if (index !== -1) this.#changeListeners.splice(index, 1);\n };\n };\n\n #emitChange(properties: StandardEventsChangeProperties): void {\n for (const listener of this.#changeListeners.slice()) {\n listener(properties);\n }\n }\n\n #signAndSendTransaction: SolanaSignAndSendTransactionMethod = async (\n ...inputs\n ) => {\n if (!this.#user) {\n throw new Error(\"Wallet not connected. Call connect() first.\");\n }\n const rpc = getSolanaRpc();\n const outputs: { signature: Uint8Array }[] = [];\n // Process sequentially: each requires its own passkey approval popup.\n for (const { transaction } of inputs) {\n const instructions = await decompileTransactionToInstructions(\n transaction,\n rpc,\n );\n const { txSig } = await executeTransaction(this.#provider, {\n instructions,\n signer: this.#user,\n });\n if (!txSig) {\n throw new Error(\"Revibase did not return a transaction signature.\");\n }\n outputs.push({\n signature: new Uint8Array(getBase58Encoder().encode(txSig)),\n });\n }\n return outputs;\n };\n}\n\n// Re-export for consumers that want the event property type.\nexport type { StandardEventsChangeProperties };\n","import type { RevibaseProvider } from \"@revibase/lite\";\nimport { registerWallet } from \"@wallet-standard/wallet\";\nimport { RevibaseWallet, type RevibaseWalletOptions } from \"./wallet\";\n\n/**\n * Registers Revibase as a Wallet Standard wallet so any Solana dApp\n * (`@solana/wallet-adapter`, wallet-standard modals, framework-kit\n * ConnectorKit, …) discovers it via `getWallets()`.\n *\n * Call once at app startup. `registerWallet` dispatches the registration\n * event, so it does not matter whether the dApp's adapter mounts before or\n * after this call.\n *\n * @param provider A configured {@link RevibaseProvider} (needs `rpcEndpoint`\n * and a backend `/api/clientAuthorization` callback).\n * @returns The {@link RevibaseWallet} instance that was registered.\n */\nexport function registerRevibaseWallet(\n provider: RevibaseProvider,\n options?: RevibaseWalletOptions,\n): RevibaseWallet {\n const wallet = new RevibaseWallet(provider, options);\n registerWallet(wallet);\n return wallet;\n}\n"]}
@@ -0,0 +1,36 @@
1
+ import { Rpc, SolanaRpcApi, Instruction } from '@solana/kit';
2
+ import { WalletIcon, IdentifierArray, Wallet, WalletAccount, IdentifierString } from '@wallet-standard/base';
3
+ import { RevibaseProvider } from '@revibase/lite';
4
+ import { SolanaSignAndSendTransactionFeature } from '@solana/wallet-standard-features';
5
+ import { StandardConnectFeature, StandardDisconnectFeature, StandardEventsFeature } from '@wallet-standard/features';
6
+ export { StandardEventsChangeProperties } from '@wallet-standard/features';
7
+ import { ReadonlyWalletAccount } from '@wallet-standard/wallet';
8
+
9
+ declare function decompileTransactionToInstructions(serializedTransaction: Uint8Array, rpc: Rpc<SolanaRpcApi>): Promise<Instruction[]>;
10
+
11
+ declare const REVIBASE_ICON: WalletIcon;
12
+
13
+ type RevibaseWalletOptions = {
14
+ name?: string;
15
+ icon?: WalletIcon;
16
+ chains?: IdentifierArray;
17
+ };
18
+ type RevibaseFeature = StandardConnectFeature & StandardDisconnectFeature & StandardEventsFeature & SolanaSignAndSendTransactionFeature;
19
+ declare class RevibaseWallet implements Wallet {
20
+ #private;
21
+ constructor(provider: RevibaseProvider, options?: RevibaseWalletOptions);
22
+ get version(): "1.0.0";
23
+ get name(): string;
24
+ get icon(): `data:image/svg+xml;base64,${string}` | `data:image/webp;base64,${string}` | `data:image/png;base64,${string}` | `data:image/gif;base64,${string}`;
25
+ get chains(): `${string}:${string}`[];
26
+ get accounts(): readonly WalletAccount[];
27
+ get features(): RevibaseFeature;
28
+ }
29
+
30
+ declare function registerRevibaseWallet(provider: RevibaseProvider, options?: RevibaseWalletOptions): RevibaseWallet;
31
+
32
+ declare class RevibaseWalletAccount extends ReadonlyWalletAccount {
33
+ constructor(walletAddress: string, chains: readonly IdentifierString[]);
34
+ }
35
+
36
+ export { REVIBASE_ICON, RevibaseWallet, RevibaseWalletAccount, type RevibaseWalletOptions, decompileTransactionToInstructions, registerRevibaseWallet };
@@ -0,0 +1,36 @@
1
+ import { Rpc, SolanaRpcApi, Instruction } from '@solana/kit';
2
+ import { WalletIcon, IdentifierArray, Wallet, WalletAccount, IdentifierString } from '@wallet-standard/base';
3
+ import { RevibaseProvider } from '@revibase/lite';
4
+ import { SolanaSignAndSendTransactionFeature } from '@solana/wallet-standard-features';
5
+ import { StandardConnectFeature, StandardDisconnectFeature, StandardEventsFeature } from '@wallet-standard/features';
6
+ export { StandardEventsChangeProperties } from '@wallet-standard/features';
7
+ import { ReadonlyWalletAccount } from '@wallet-standard/wallet';
8
+
9
+ declare function decompileTransactionToInstructions(serializedTransaction: Uint8Array, rpc: Rpc<SolanaRpcApi>): Promise<Instruction[]>;
10
+
11
+ declare const REVIBASE_ICON: WalletIcon;
12
+
13
+ type RevibaseWalletOptions = {
14
+ name?: string;
15
+ icon?: WalletIcon;
16
+ chains?: IdentifierArray;
17
+ };
18
+ type RevibaseFeature = StandardConnectFeature & StandardDisconnectFeature & StandardEventsFeature & SolanaSignAndSendTransactionFeature;
19
+ declare class RevibaseWallet implements Wallet {
20
+ #private;
21
+ constructor(provider: RevibaseProvider, options?: RevibaseWalletOptions);
22
+ get version(): "1.0.0";
23
+ get name(): string;
24
+ get icon(): `data:image/svg+xml;base64,${string}` | `data:image/webp;base64,${string}` | `data:image/png;base64,${string}` | `data:image/gif;base64,${string}`;
25
+ get chains(): `${string}:${string}`[];
26
+ get accounts(): readonly WalletAccount[];
27
+ get features(): RevibaseFeature;
28
+ }
29
+
30
+ declare function registerRevibaseWallet(provider: RevibaseProvider, options?: RevibaseWalletOptions): RevibaseWallet;
31
+
32
+ declare class RevibaseWalletAccount extends ReadonlyWalletAccount {
33
+ constructor(walletAddress: string, chains: readonly IdentifierString[]);
34
+ }
35
+
36
+ export { REVIBASE_ICON, RevibaseWallet, RevibaseWalletAccount, type RevibaseWalletOptions, decompileTransactionToInstructions, registerRevibaseWallet };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import {getTransactionDecoder,getCompiledTransactionMessageDecoder,decompileTransactionMessageFetchingLookupTables,getAddressEncoder,address,getBase58Encoder}from'@solana/kit';import {ReadonlyWalletAccount,registerWallet}from'@wallet-standard/wallet';import {getSolanaRpc}from'@revibase/core';import {signIn,executeTransaction}from'@revibase/lite';import {SOLANA_MAINNET_CHAIN,SOLANA_DEVNET_CHAIN}from'@solana/wallet-standard-chains';import {SolanaSignAndSendTransaction}from'@solana/wallet-standard-features';import {StandardEvents,StandardDisconnect,StandardConnect}from'@wallet-standard/features';async function s(n,t){let e=getTransactionDecoder().decode(n),r=getCompiledTransactionMessageDecoder().decode(e.messageBytes);return [...(await decompileTransactionMessageFetchingLookupTables(r,t)).instructions]}var i=`data:image/svg+xml;base64,${m('<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><rect width="64" height="64" rx="14" fill="#0B0B0F"/><path d="M20 44V20h13c6 0 10 3.6 10 9 0 3.8-2 6.6-5.3 8L44 44h-7l-5.4-6.4H27V44h-7Zm7-12.4h5.4c2.4 0 3.8-1.3 3.8-3.3s-1.4-3.3-3.8-3.3H27v6.6Z" fill="#fff"/></svg>')}`;function m(n){return typeof btoa=="function"?btoa(unescape(encodeURIComponent(n))):Buffer.from(n,"utf-8").toString("base64")}var a=class extends ReadonlyWalletAccount{constructor(t,e){super({address:t,publicKey:new Uint8Array(getAddressEncoder().encode(address(t))),chains:e,features:["solana:signAndSendTransaction"]});}};var x="Revibase",C=[SOLANA_MAINNET_CHAIN,SOLANA_DEVNET_CHAIN],o=class{#r;#o;#s;#a;#e=null;#t=null;#n=[];constructor(t,e){this.#r=t,this.#o=e?.name??x,this.#s=e?.icon??i,this.#a=e?.chains??C;}get version(){return "1.0.0"}get name(){return this.#o}get icon(){return this.#s}get chains(){return this.#a.slice()}get accounts(){return this.#e?[this.#e]:[]}get features(){return {[StandardConnect]:{version:"1.0.0",connect:this.#c},[StandardDisconnect]:{version:"1.0.0",disconnect:this.#d},[StandardEvents]:{version:"1.0.0",on:this.#l},[SolanaSignAndSendTransaction]:{version:"1.0.0",supportedTransactionVersions:["legacy",0],signAndSendTransaction:this.#p}}}#c=async t=>{if(!this.#e){if(t?.silent)return {accounts:this.accounts};let{user:e}=await signIn(this.#r);if(!e.walletAddress)throw new Error("Revibase sign-in returned no walletAddress; cannot expose an account.");this.#t=e,this.#e=new a(e.walletAddress,this.#a),this.#i({accounts:this.accounts});}return {accounts:this.accounts}};#d=async()=>{this.#e&&(this.#e=null,this.#t=null,this.#i({accounts:this.accounts}));};#l=(t,e)=>t!=="change"?()=>{}:(this.#n.push(e),()=>{let r=this.#n.indexOf(e);r!==-1&&this.#n.splice(r,1);});#i(t){for(let e of this.#n.slice())e(t);}#p=async(...t)=>{if(!this.#t)throw new Error("Wallet not connected. Call connect() first.");let e=getSolanaRpc(),r=[];for(let{transaction:c}of t){let l=await s(c,e),{txSig:d}=await executeTransaction(this.#r,{instructions:l,signer:this.#t});if(!d)throw new Error("Revibase did not return a transaction signature.");r.push({signature:new Uint8Array(getBase58Encoder().encode(d))});}return r}};function M(n,t){let e=new o(n,t);return registerWallet(e),e}
2
+ export{i as REVIBASE_ICON,o as RevibaseWallet,a as RevibaseWalletAccount,s as decompileTransactionToInstructions,M as registerRevibaseWallet};//# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/decompile.ts","../src/icon.ts","../src/account.ts","../src/wallet.ts","../src/register.ts"],"names":["decompileTransactionToInstructions","serializedTransaction","rpc","transaction","getTransactionDecoder","compiledMessage","getCompiledTransactionMessageDecoder","decompileTransactionMessageFetchingLookupTables","REVIBASE_ICON","btoaUtf8","input","RevibaseWalletAccount","ReadonlyWalletAccount","walletAddress","chains","getAddressEncoder","address","DEFAULT_NAME","DEFAULT_CHAINS","SOLANA_MAINNET_CHAIN","SOLANA_DEVNET_CHAIN","RevibaseWallet","#provider","#name","#icon","#chains","#account","#user","#changeListeners","provider","options","StandardConnect","#connect","StandardDisconnect","#disconnect","StandardEvents","#on","SolanaSignAndSendTransaction","#signAndSendTransaction","user","signIn","#emitChange","event","listener","index","properties","inputs","getSolanaRpc","outputs","instructions","txSig","executeTransaction","getBase58Encoder","registerRevibaseWallet","wallet","registerWallet"],"mappings":"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","file":"index.js","sourcesContent":["import {\n decompileTransactionMessageFetchingLookupTables,\n getCompiledTransactionMessageDecoder,\n getTransactionDecoder,\n type Instruction,\n type Rpc,\n type SolanaRpcApi,\n} from \"@solana/kit\";\n\n/**\n * Wallet Standard hands the wallet a fully serialized transaction. Revibase,\n * however, rebuilds its own vault-paid transaction from raw instructions\n * (see `executeTransaction` in @revibase/lite). So we decode the wire\n * transaction back into instructions, resolving any address lookup tables via\n * the RPC. The original fee payer and blockhash are intentionally dropped —\n * Revibase sets the vault as payer and supplies its own fee payer/blockhash.\n */\nexport async function decompileTransactionToInstructions(\n serializedTransaction: Uint8Array,\n rpc: Rpc<SolanaRpcApi>,\n): Promise<Instruction[]> {\n const transaction = getTransactionDecoder().decode(serializedTransaction);\n const compiledMessage = getCompiledTransactionMessageDecoder().decode(\n transaction.messageBytes,\n );\n const decompiled = await decompileTransactionMessageFetchingLookupTables(\n compiledMessage,\n rpc,\n );\n return [...decompiled.instructions];\n}\n","import type { WalletIcon } from \"@wallet-standard/base\";\n\n/**\n * Inline (data-URI) wallet icon shown in dApp wallet pickers. Kept as an SVG\n * data URI so the package has no binary assets and works in any bundler.\n * Replace with the official Revibase brand mark when available.\n */\nexport const REVIBASE_ICON: WalletIcon =\n `data:image/svg+xml;base64,${btoaUtf8(\n `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">` +\n `<rect width=\"64\" height=\"64\" rx=\"14\" fill=\"#0B0B0F\"/>` +\n `<path d=\"M20 44V20h13c6 0 10 3.6 10 9 0 3.8-2 6.6-5.3 8L44 44h-7l-5.4-6.4H27V44h-7Zm7-12.4h5.4c2.4 0 3.8-1.3 3.8-3.3s-1.4-3.3-3.8-3.3H27v6.6Z\" fill=\"#fff\"/>` +\n `</svg>`,\n )}` as WalletIcon;\n\n/** Minimal, environment-agnostic UTF-8 safe base64 encoder. */\nfunction btoaUtf8(input: string): string {\n if (typeof btoa === \"function\") {\n return btoa(unescape(encodeURIComponent(input)));\n }\n // Node fallback (used in tests / SSR)\n return Buffer.from(input, \"utf-8\").toString(\"base64\");\n}\n","import { address, getAddressEncoder } from \"@solana/kit\";\nimport type { IdentifierString } from \"@wallet-standard/base\";\nimport { ReadonlyWalletAccount } from \"@wallet-standard/wallet\";\n\n/**\n * A Wallet Standard account backed by a Revibase multisig vault.\n *\n * `address` is the on-chain vault (`UserInfo.walletAddress`) — the account a\n * dApp transacts with. `publicKey` is the decoded bytes of that address; note\n * it is a PDA, not an ed25519 keypair, so callers cannot ed25519-verify\n * signatures against it.\n */\nexport class RevibaseWalletAccount extends ReadonlyWalletAccount {\n constructor(walletAddress: string, chains: readonly IdentifierString[]) {\n super({\n address: walletAddress,\n publicKey: new Uint8Array(\n getAddressEncoder().encode(address(walletAddress)),\n ),\n chains,\n // Only sign-and-send is supported today (see README \"Constraints\").\n features: [\"solana:signAndSendTransaction\"],\n });\n }\n}\n","import { getSolanaRpc, type UserInfo } from \"@revibase/core\";\nimport {\n executeTransaction,\n signIn,\n type RevibaseProvider,\n} from \"@revibase/lite\";\nimport { getBase58Encoder } from \"@solana/kit\";\nimport {\n SOLANA_DEVNET_CHAIN,\n SOLANA_MAINNET_CHAIN,\n} from \"@solana/wallet-standard-chains\";\nimport {\n SolanaSignAndSendTransaction,\n type SolanaSignAndSendTransactionFeature,\n type SolanaSignAndSendTransactionMethod,\n} from \"@solana/wallet-standard-features\";\nimport type {\n IdentifierArray,\n Wallet,\n WalletAccount,\n WalletIcon,\n} from \"@wallet-standard/base\";\nimport {\n StandardConnect,\n StandardDisconnect,\n StandardEvents,\n type StandardConnectFeature,\n type StandardConnectMethod,\n type StandardDisconnectFeature,\n type StandardDisconnectMethod,\n type StandardEventsChangeProperties,\n type StandardEventsFeature,\n type StandardEventsListeners,\n type StandardEventsOnMethod,\n} from \"@wallet-standard/features\";\nimport { RevibaseWalletAccount } from \"./account\";\nimport { decompileTransactionToInstructions } from \"./decompile\";\nimport { REVIBASE_ICON } from \"./icon\";\n\nexport type RevibaseWalletOptions = {\n /** Display name shown in wallet pickers. Defaults to \"Revibase\". */\n name?: string;\n /** Inline icon (data URI). Defaults to the bundled Revibase mark. */\n icon?: WalletIcon;\n /** Chains to advertise. Defaults to Solana mainnet + devnet. */\n chains?: IdentifierArray;\n};\n\nconst DEFAULT_NAME = \"Revibase\";\nconst DEFAULT_CHAINS: IdentifierArray = [\n SOLANA_MAINNET_CHAIN,\n SOLANA_DEVNET_CHAIN,\n];\n\ntype RevibaseFeature = StandardConnectFeature &\n StandardDisconnectFeature &\n StandardEventsFeature &\n SolanaSignAndSendTransactionFeature;\n\n/**\n * Wraps an existing {@link RevibaseProvider} as a Wallet Standard wallet so\n * Solana dApps discover and connect to Revibase via `registerWallet()` /\n * `getWallets()`.\n *\n * Supported features: `standard:connect`, `standard:disconnect`,\n * `standard:events`, and `solana:signAndSendTransaction`. Raw\n * `solana:signTransaction`, `solana:signMessage`, and `solana:signIn` are\n * intentionally NOT advertised — see the package README \"Constraints\".\n */\nexport class RevibaseWallet implements Wallet {\n readonly #provider: RevibaseProvider;\n readonly #name: string;\n readonly #icon: WalletIcon;\n readonly #chains: IdentifierArray;\n\n #account: RevibaseWalletAccount | null = null;\n #user: UserInfo | null = null;\n // The only Wallet Standard event is \"change\".\n readonly #changeListeners: StandardEventsListeners[\"change\"][] = [];\n\n constructor(provider: RevibaseProvider, options?: RevibaseWalletOptions) {\n this.#provider = provider;\n this.#name = options?.name ?? DEFAULT_NAME;\n this.#icon = options?.icon ?? REVIBASE_ICON;\n this.#chains = options?.chains ?? DEFAULT_CHAINS;\n }\n\n get version() {\n return \"1.0.0\" as const;\n }\n\n get name() {\n return this.#name;\n }\n\n get icon() {\n return this.#icon;\n }\n\n get chains() {\n return this.#chains.slice();\n }\n\n get accounts(): readonly WalletAccount[] {\n return this.#account ? [this.#account] : [];\n }\n\n get features(): RevibaseFeature {\n return {\n [StandardConnect]: {\n version: \"1.0.0\",\n connect: this.#connect,\n },\n [StandardDisconnect]: {\n version: \"1.0.0\",\n disconnect: this.#disconnect,\n },\n [StandardEvents]: {\n version: \"1.0.0\",\n on: this.#on,\n },\n [SolanaSignAndSendTransaction]: {\n version: \"1.0.0\",\n supportedTransactionVersions: [\"legacy\", 0],\n signAndSendTransaction: this.#signAndSendTransaction,\n },\n };\n }\n\n #connect: StandardConnectMethod = async (input) => {\n if (!this.#account) {\n if (input?.silent) {\n // Revibase has no silent/auto-connect path (requires a passkey prompt).\n return { accounts: this.accounts };\n }\n const { user } = await signIn(this.#provider);\n if (!user.walletAddress) {\n throw new Error(\n \"Revibase sign-in returned no walletAddress; cannot expose an account.\",\n );\n }\n this.#user = user;\n this.#account = new RevibaseWalletAccount(user.walletAddress, this.#chains);\n this.#emitChange({ accounts: this.accounts });\n }\n return { accounts: this.accounts };\n };\n\n #disconnect: StandardDisconnectMethod = async () => {\n if (this.#account) {\n this.#account = null;\n this.#user = null;\n this.#emitChange({ accounts: this.accounts });\n }\n };\n\n #on: StandardEventsOnMethod = (event, listener) => {\n if (event !== \"change\") return () => {};\n this.#changeListeners.push(listener);\n return () => {\n const index = this.#changeListeners.indexOf(listener);\n if (index !== -1) this.#changeListeners.splice(index, 1);\n };\n };\n\n #emitChange(properties: StandardEventsChangeProperties): void {\n for (const listener of this.#changeListeners.slice()) {\n listener(properties);\n }\n }\n\n #signAndSendTransaction: SolanaSignAndSendTransactionMethod = async (\n ...inputs\n ) => {\n if (!this.#user) {\n throw new Error(\"Wallet not connected. Call connect() first.\");\n }\n const rpc = getSolanaRpc();\n const outputs: { signature: Uint8Array }[] = [];\n // Process sequentially: each requires its own passkey approval popup.\n for (const { transaction } of inputs) {\n const instructions = await decompileTransactionToInstructions(\n transaction,\n rpc,\n );\n const { txSig } = await executeTransaction(this.#provider, {\n instructions,\n signer: this.#user,\n });\n if (!txSig) {\n throw new Error(\"Revibase did not return a transaction signature.\");\n }\n outputs.push({\n signature: new Uint8Array(getBase58Encoder().encode(txSig)),\n });\n }\n return outputs;\n };\n}\n\n// Re-export for consumers that want the event property type.\nexport type { StandardEventsChangeProperties };\n","import type { RevibaseProvider } from \"@revibase/lite\";\nimport { registerWallet } from \"@wallet-standard/wallet\";\nimport { RevibaseWallet, type RevibaseWalletOptions } from \"./wallet\";\n\n/**\n * Registers Revibase as a Wallet Standard wallet so any Solana dApp\n * (`@solana/wallet-adapter`, wallet-standard modals, framework-kit\n * ConnectorKit, …) discovers it via `getWallets()`.\n *\n * Call once at app startup. `registerWallet` dispatches the registration\n * event, so it does not matter whether the dApp's adapter mounts before or\n * after this call.\n *\n * @param provider A configured {@link RevibaseProvider} (needs `rpcEndpoint`\n * and a backend `/api/clientAuthorization` callback).\n * @returns The {@link RevibaseWallet} instance that was registered.\n */\nexport function registerRevibaseWallet(\n provider: RevibaseProvider,\n options?: RevibaseWalletOptions,\n): RevibaseWallet {\n const wallet = new RevibaseWallet(provider, options);\n registerWallet(wallet);\n return wallet;\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@revibase/wallet-standard",
3
+ "version": "0.8.5",
4
+ "type": "module",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "license": "MIT",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/Revibase/multi-wallet.git",
22
+ "directory": "packages/wallet-standard"
23
+ },
24
+ "author": "jychab",
25
+ "bugs": {
26
+ "url": "https://github.com/Revibase/multi-wallet/issues"
27
+ },
28
+ "homepage": "https://github.com/Revibase/multi-wallet/blob/master/packages/wallet-standard",
29
+ "description": "Wallet Standard wrapper for @revibase/lite: makes the Revibase passkey wallet discoverable by Solana dApps (desktop and mobile web).",
30
+ "dependencies": {
31
+ "@solana/kit": "^6.9.0",
32
+ "@wallet-standard/wallet": "^1.1.0",
33
+ "@revibase/core": "0.8.3",
34
+ "@revibase/lite": "0.8.5"
35
+ },
36
+ "peerDependencies": {
37
+ "@solana/wallet-standard-chains": "^1.1.0",
38
+ "@solana/wallet-standard-features": "^1.3.0",
39
+ "@wallet-standard/base": "^1.1.0",
40
+ "@wallet-standard/features": "^1.1.0"
41
+ },
42
+ "devDependencies": {
43
+ "@wallet-standard/app": "^1.1.0",
44
+ "@solana/wallet-standard-chains": "^1.1.0",
45
+ "@solana/wallet-standard-features": "^1.3.0",
46
+ "@wallet-standard/base": "^1.1.0",
47
+ "@wallet-standard/features": "^1.1.0",
48
+ "@types/node": "24.3.1",
49
+ "prettier": "^3.6.2",
50
+ "rimraf": "^6.0.1",
51
+ "tsup": "8.5.0",
52
+ "typescript": "5.9.3"
53
+ },
54
+ "scripts": {
55
+ "build": "rimraf dist && tsup",
56
+ "clean": "rimraf dist"
57
+ }
58
+ }