@walletconnect/cli-sdk 0.1.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/dist/index.cjs ADDED
@@ -0,0 +1,108 @@
1
+ "use strict";var $=Object.create;var f=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,F=Object.prototype.hasOwnProperty;var K=(n,s)=>{for(var e in s)f(n,e,{get:s[e],enumerable:!0})},I=(n,s,e,t)=>{if(s&&typeof s=="object"||typeof s=="function")for(let o of D(s))!F.call(n,o)&&o!==e&&f(n,o,{get:()=>s[o],enumerable:!(t=A(s,o))||t.enumerable});return n};var y=(n,s,e)=>(e=n!=null?$(B(n)):{},I(s||!n||!n.__esModule?f(e,"default",{value:n,enumerable:!0}):e,n)),V=n=>I(f({},"__esModule",{value:!0}),n);var Z={};K(Z,{WalletConnectCLI:()=>p,createBrowserUI:()=>h,createSessionManager:()=>C,createTerminalUI:()=>m,getConfigValue:()=>S,resolveProjectId:()=>N,setConfigValue:()=>M,withWallet:()=>X});module.exports=V(Z);var U=require("events"),O=require("child_process"),R=require("os"),W=require("path"),j=require("@walletconnect/keyvaluestorage"),k=require("@walletconnect/sign-client");var T=y(require("http"),1),x="</script>";function J(n){return`<!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>WalletConnect \u2014 Connect Wallet</title>
7
+ <style>
8
+ * { margin: 0; padding: 0; box-sizing: border-box; }
9
+ body {
10
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
11
+ background: #1a1a2e;
12
+ color: #e0e0e0;
13
+ display: flex;
14
+ justify-content: center;
15
+ align-items: center;
16
+ min-height: 100vh;
17
+ }
18
+ .container {
19
+ text-align: center;
20
+ padding: 2rem;
21
+ max-width: 420px;
22
+ }
23
+ h1 { font-size: 1.5rem; margin-bottom: 0.5rem; color: #fff; }
24
+ .subtitle { color: #8888aa; margin-bottom: 2rem; }
25
+ #qr-container {
26
+ background: #fff;
27
+ border-radius: 16px;
28
+ padding: 24px;
29
+ display: inline-block;
30
+ margin-bottom: 1.5rem;
31
+ }
32
+ #qr-container canvas { display: block; }
33
+ .uri-box {
34
+ background: #16213e;
35
+ border: 1px solid #333;
36
+ border-radius: 8px;
37
+ padding: 12px;
38
+ word-break: break-all;
39
+ font-size: 0.75rem;
40
+ color: #8888aa;
41
+ margin-bottom: 1.5rem;
42
+ cursor: pointer;
43
+ transition: border-color 0.2s;
44
+ }
45
+ .uri-box:hover { border-color: #5566ff; }
46
+ .uri-box:active { border-color: #3344dd; }
47
+ #status {
48
+ font-size: 0.9rem;
49
+ padding: 8px 16px;
50
+ border-radius: 8px;
51
+ display: inline-block;
52
+ }
53
+ .status-waiting { background: #16213e; color: #8888aa; }
54
+ .status-connected { background: #0a3d2a; color: #4ade80; }
55
+ .status-error { background: #3d0a0a; color: #f87171; }
56
+ </style>
57
+ </head>
58
+ <body>
59
+ <div class="container">
60
+ <h1>Connect Your Wallet</h1>
61
+ <p class="subtitle">Scan the QR code with your mobile wallet</p>
62
+ <div id="qr-container"><canvas id="qr"></canvas></div>
63
+ <div class="uri-box" onclick="navigator.clipboard.writeText('${n}').then(()=>this.textContent='Copied!').catch(()=>{})">
64
+ ${n}
65
+ </div>
66
+ <div id="status" class="status-waiting">Waiting for connection...</div>
67
+ </div>
68
+ <script src="https://cdn.jsdelivr.net/npm/qrcode@1/build/qrcode.min.js">${x}
69
+ <script>
70
+ QRCode.toCanvas(document.getElementById("qr"), "${n}", {
71
+ width: 280,
72
+ margin: 0,
73
+ color: { dark: "#1a1a2e", light: "#ffffff" }
74
+ });
75
+
76
+ const evtSource = new EventSource("/events");
77
+ evtSource.onmessage = function(event) {
78
+ const data = JSON.parse(event.data);
79
+ const el = document.getElementById("status");
80
+ el.className = "status-" + data.status;
81
+ el.textContent = data.message || data.status;
82
+ if (data.status === "connected") {
83
+ evtSource.close();
84
+ setTimeout(() => window.close(), 2000);
85
+ }
86
+ };
87
+ ${x}
88
+ </body>
89
+ </html>`}function h(n){let s=null,e=[];return{async start(t){let o=J(t);s=T.default.createServer((a,c)=>{if(a.url==="/events"){c.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}),c.write(`data: ${JSON.stringify({status:"waiting",message:"Waiting for connection..."})}
90
+
91
+ `);let l={res:c};e.push(l),a.on("close",()=>{let u=e.indexOf(l);u!==-1&&e.splice(u,1)});return}c.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),c.end(o)});let i=await new Promise((a,c)=>{s.listen(n||0,"127.0.0.1",()=>{let l=s.address();a(l.port)}),s.on("error",c)}),r=`http://127.0.0.1:${i}`;try{let{default:a}=await import("open");await a(r)}catch{console.log(`Open your browser at: ${r}`)}return{port:i,url:r}},updateStatus(t,o){let i=JSON.stringify({status:t,message:o||t});for(let r of e)try{r.res.write(`data: ${i}
92
+
93
+ `)}catch{}},async stop(){for(let t of e)try{t.res.end()}catch{}e.length=0,s&&(await new Promise(t=>{s.close(()=>t())}),s=null)}}}function C(){return{getExistingSession(n){let s=n.session.getAll();if(s.length===0)return null;let e=Math.floor(Date.now()/1e3),t=s.filter(o=>o.expiry>e).sort((o,i)=>i.expiry-o.expiry);return t.length>0?t[0]:null},isSessionValid(n){let s=Math.floor(Date.now()/1e3);return n.expiry>s}}}var E=y(require("qrcode-terminal"),1);function m(){return{displayQR(n){console.log(`
94
+ Scan this QR code with your wallet app:
95
+ `),E.default.generate(n,{small:!0}),console.log(`
96
+ Or copy this URI:`,n),console.log(`
97
+ Waiting for wallet connection...
98
+ `)},showStatus(n){console.log(`[WalletConnect] ${n}`)},showError(n){console.error(`[WalletConnect] Error: ${n}`)},showSuccess(n){console.log(`[WalletConnect] ${n}`)}}}var Q=["eth_sendTransaction","eth_signTransaction","personal_sign","eth_sign","eth_signTypedData","eth_signTypedData_v4"],H=["chainChanged","accountsChanged"],z=["eip155:1"],G=(0,W.join)((0,R.homedir)(),".walletconnect-cli"),p=class extends U.EventEmitter{constructor(e){super();this.signClient=null;this.currentSession=null;this.browserUI=null;this.sessionManager=C();this.options=e}async tryRestore(){let e=await this.ensureClient(),t=this.sessionManager.getExistingSession(e);return t?(this.currentSession=t,this.buildConnectResult(t)):null}async connect(e){let t=await this.ensureClient();if(this.options.autoConnect!==!1){let g=this.sessionManager.getExistingSession(t);if(g){this.currentSession=g;let b=this.buildConnectResult(g);return this.emit("connect",b),b}}let o=this.options.chains||z,i=this.options.methods||Q,r=this.options.events||H,a=e?.optionalNamespaces||{eip155:{chains:o,methods:i,events:r}},{uri:c,approval:l}=await t.connect({optionalNamespaces:a});if(!c)throw new Error("Failed to generate WalletConnect URI");this.options.ui==="browser"?await this.showBrowserUI(c):m().displayQR(c);let u=await l();this.currentSession=u,this.browserUI&&(this.browserUI.updateStatus("connected",`Connected to ${u.peer.metadata.name}`),setTimeout(()=>this.browserUI?.stop(),3e3));let v=this.buildConnectResult(u);return this.emit("connect",v),v}async request(e){let t=await this.ensureClient(),o=e.topic||this.currentSession?.topic;if(!o)throw new Error("No active session. Call connect() first.");this.logRequestDetails(e);try{return await t.request({topic:o,chainId:e.chainId,request:e.request})}catch(i){let r=this.extractErrorMessage(i);if(r.includes("rejected")||r.includes("denied")||r.includes("cancelled"))throw new Error("Request rejected by user");if(typeof i=="object"&&i!==null){let a=i;if(a.code===0&&!a.message)throw new Error("Request rejected or timed out in wallet")}throw i}}async disconnect(){if(this.currentSession){try{let e=await this.ensureClient(),t=()=>{};e.core.relayer.on("error",t);try{await e.disconnect({topic:this.currentSession.topic,reason:{code:6e3,message:"User disconnected"}})}finally{e.core.relayer.off("error",t)}}catch{}this.currentSession=null,this.emit("disconnect")}}isConnected(){return this.currentSession?this.sessionManager.isSessionValid(this.currentSession):!1}getAccounts(){return this.currentSession?Object.values(this.currentSession.namespaces).flatMap(e=>e.accounts||[]):[]}getSession(){return this.currentSession}async destroy(){if(this.browserUI&&(await this.browserUI.stop(),this.browserUI=null),this.removeAllListeners(),this.signClient)try{await this.signClient.core.relayer.transportClose()}catch{}this.signClient=null,this.currentSession=null}on(e,t){return super.on(e,t)}once(e,t){return super.once(e,t)}off(e,t){return super.off(e,t)}emit(e,...t){return super.emit(e,...t)}logRequestDetails(e){let t=this.currentSession?.peer.metadata.name;if(t&&console.log(`
99
+ Requesting approval on ${t}...`),e.request.method==="eth_sendTransaction"){let i=e.request.params[0]?.data;if(i&&i!=="0x")try{let r=(0,O.execFileSync)("cast",["4d",i],{encoding:"utf-8",timeout:5e3,stdio:["pipe","pipe","pipe"]}).trim();r&&console.log(`
100
+ Decoded calldata:
101
+ ${r.split(`
102
+ `).map(a=>` ${a}`).join(`
103
+ `)}
104
+ `)}catch{}}}async ensureClient(){if(this.signClient)return this.signClient;let e=this.options.storagePath||G,t=new j.KeyValueStorage({database:e});return this.signClient=await k.SignClient.init({projectId:this.options.projectId,metadata:this.options.metadata,storage:t,logger:this.options.logger||"silent"}),this.signClient.on("session_update",({topic:o})=>{let i=this.signClient?.session.get(o);i&&(this.currentSession=i,this.emit("session_update",i))}),this.signClient.on("session_delete",({topic:o})=>{this.currentSession?.topic===o&&(this.currentSession=null),this.emit("session_delete",{topic:o}),this.emit("disconnect")}),this.signClient}async showBrowserUI(e){this.browserUI=h(this.options.port);try{let{url:t}=await this.browserUI.start(e);console.log(`
105
+ Connect your wallet at: ${t}
106
+ `)}catch{console.log("Could not open browser, falling back to terminal QR code."),m().displayQR(e),this.browserUI=null}}buildConnectResult(e){let t=Object.values(e.namespaces).flatMap(o=>o.accounts||[]);return{session:e,accounts:t,topic:e.topic}}extractErrorMessage(e){if(e instanceof Error)return e.message;if(typeof e=="object"&&e!==null){let t=e;return t.message?t.message:JSON.stringify(e)}return String(e)}};var L=require("os"),w=require("path"),d=require("fs"),q=(0,w.join)((0,L.homedir)(),".walletconnect-cli"),_=(0,w.join)(q,"config.json");function P(){try{return JSON.parse((0,d.readFileSync)(_,"utf-8"))}catch{return{}}}function Y(n){(0,d.mkdirSync)(q,{recursive:!0,mode:448}),(0,d.writeFileSync)(_,JSON.stringify(n,null,2)+`
107
+ `,{mode:384})}function S(n){return P()[n]}function M(n,s){let e=P();e[n]=s,Y(e)}function N(){return process.env.WALLETCONNECT_PROJECT_ID||S("projectId")}async function X(n,s){let e=new p(n);try{let t=await e.connect(n.connectOptions);await s(e,t),n.disconnectAfter!==!1&&await e.disconnect()}finally{await e.destroy()}}0&&(module.exports={WalletConnectCLI,createBrowserUI,createSessionManager,createTerminalUI,getConfigValue,resolveProjectId,setConfigValue,withWallet});
108
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/browser-ui/server.ts","../src/session.ts","../src/terminal-ui.ts","../src/config.ts"],"sourcesContent":["import { WalletConnectCLI } from \"./client.js\";\nimport type { WithWalletOptions, ConnectResult } from \"./types.js\";\n\nexport { WalletConnectCLI } from \"./client.js\";\nexport { createSessionManager } from \"./session.js\";\nexport { createTerminalUI } from \"./terminal-ui.js\";\nexport { createBrowserUI } from \"./browser-ui/server.js\";\nexport { getConfigValue, setConfigValue, resolveProjectId } from \"./config.js\";\n\nexport type {\n WalletConnectCLIOptions,\n ConnectOptions,\n ConnectResult,\n RequestOptions,\n WalletConnectCLIEvents,\n WithWalletOptions,\n TerminalUI,\n BrowserUI,\n} from \"./types.js\";\n\n/**\n * Higher-level helper that wraps the connect → callback → cleanup pattern.\n *\n * @example\n * ```ts\n * await withWallet({ projectId, metadata }, async (wallet, { accounts }) => {\n * const txHash = await wallet.request({\n * chainId: 'eip155:1',\n * request: { method: 'eth_sendTransaction', params: [tx] }\n * });\n * });\n * ```\n */\nexport async function withWallet(\n options: WithWalletOptions,\n callback: (wallet: WalletConnectCLI, result: ConnectResult) => Promise<void>,\n): Promise<void> {\n const wallet = new WalletConnectCLI(options);\n try {\n const result = await wallet.connect(options.connectOptions);\n await callback(wallet, result);\n if (options.disconnectAfter !== false) {\n await wallet.disconnect();\n }\n } finally {\n await wallet.destroy();\n }\n}\n","import { EventEmitter } from \"events\";\nimport { execFileSync } from \"child_process\";\nimport { homedir } from \"os\";\nimport { join } from \"path\";\nimport { KeyValueStorage } from \"@walletconnect/keyvaluestorage\";\nimport { SignClient } from \"@walletconnect/sign-client\";\nimport type { SessionTypes } from \"@walletconnect/types\";\nimport { createBrowserUI } from \"./browser-ui/server.js\";\nimport { createSessionManager } from \"./session.js\";\nimport { createTerminalUI } from \"./terminal-ui.js\";\nimport type {\n BrowserUI,\n ConnectOptions,\n ConnectResult,\n RequestOptions,\n WalletConnectCLIEvents,\n WalletConnectCLIOptions,\n} from \"./types.js\";\n\nconst DEFAULT_METHODS = [\n \"eth_sendTransaction\",\n \"eth_signTransaction\",\n \"personal_sign\",\n \"eth_sign\",\n \"eth_signTypedData\",\n \"eth_signTypedData_v4\",\n];\n\nconst DEFAULT_EVENTS = [\"chainChanged\", \"accountsChanged\"];\nconst DEFAULT_CHAINS = [\"eip155:1\"];\nconst DEFAULT_STORAGE_PATH = join(homedir(), \".walletconnect-cli\");\n\nexport class WalletConnectCLI extends EventEmitter {\n private readonly options: WalletConnectCLIOptions;\n private signClient: InstanceType<typeof SignClient> | null = null;\n private currentSession: SessionTypes.Struct | null = null;\n private browserUI: BrowserUI | null = null;\n private readonly sessionManager = createSessionManager();\n\n constructor(options: WalletConnectCLIOptions) {\n super();\n this.options = options;\n }\n\n // ---------- Public API ----------------------------------------------- //\n\n async tryRestore(): Promise<ConnectResult | null> {\n const client = await this.ensureClient();\n const existing = this.sessionManager.getExistingSession(client);\n if (!existing) return null;\n this.currentSession = existing;\n return this.buildConnectResult(existing);\n }\n\n async connect(connectOptions?: ConnectOptions): Promise<ConnectResult> {\n const client = await this.ensureClient();\n\n // Check for existing valid session\n if (this.options.autoConnect !== false) {\n const existing = this.sessionManager.getExistingSession(client);\n if (existing) {\n this.currentSession = existing;\n const result = this.buildConnectResult(existing);\n this.emit(\"connect\", result);\n return result;\n }\n }\n\n // Build namespaces\n const chains = this.options.chains || DEFAULT_CHAINS;\n const methods = this.options.methods || DEFAULT_METHODS;\n const events = this.options.events || DEFAULT_EVENTS;\n\n const optionalNamespaces = connectOptions?.optionalNamespaces || {\n eip155: { chains, methods, events },\n };\n\n // Initiate connection\n const { uri, approval } = await client.connect({ optionalNamespaces });\n\n if (!uri) {\n throw new Error(\"Failed to generate WalletConnect URI\");\n }\n\n // Display connection UI\n if (this.options.ui === \"browser\") {\n await this.showBrowserUI(uri);\n } else {\n const terminalUI = createTerminalUI();\n terminalUI.displayQR(uri);\n }\n\n // Wait for wallet approval\n const session = await approval();\n this.currentSession = session;\n\n // Update browser UI if active\n if (this.browserUI) {\n this.browserUI.updateStatus(\"connected\", `Connected to ${session.peer.metadata.name}`);\n // Give browser time to show success, then shut down\n setTimeout(() => this.browserUI?.stop(), 3000);\n }\n\n const result = this.buildConnectResult(session);\n this.emit(\"connect\", result);\n return result;\n }\n\n async request<T = unknown>(options: RequestOptions): Promise<T> {\n const client = await this.ensureClient();\n const topic = options.topic || this.currentSession?.topic;\n\n if (!topic) {\n throw new Error(\"No active session. Call connect() first.\");\n }\n\n this.logRequestDetails(options);\n\n try {\n return await client.request<T>({\n topic,\n chainId: options.chainId,\n request: options.request,\n });\n } catch (error: unknown) {\n const message = this.extractErrorMessage(error);\n\n if (message.includes(\"rejected\") || message.includes(\"denied\") || message.includes(\"cancelled\")) {\n throw new Error(\"Request rejected by user\");\n }\n\n if (typeof error === \"object\" && error !== null) {\n const errObj = error as { code?: number; message?: string };\n if (errObj.code === 0 && !errObj.message) {\n throw new Error(\"Request rejected or timed out in wallet\");\n }\n }\n\n throw error;\n }\n }\n\n async disconnect(): Promise<void> {\n if (!this.currentSession) return;\n\n try {\n const client = await this.ensureClient();\n // Absorb relay WebSocket errors during disconnect so they don't\n // surface as unhandled 'error' events that crash the process.\n const swallow = () => {};\n client.core.relayer.on(\"error\", swallow);\n try {\n await client.disconnect({\n topic: this.currentSession.topic,\n reason: { code: 6000, message: \"User disconnected\" },\n });\n } finally {\n client.core.relayer.off(\"error\", swallow);\n }\n } catch {\n // Ignore disconnect errors — session may have already expired\n }\n\n // Always clean up local state even if relay notification failed\n this.currentSession = null;\n this.emit(\"disconnect\");\n }\n\n isConnected(): boolean {\n if (!this.currentSession) return false;\n return this.sessionManager.isSessionValid(this.currentSession);\n }\n\n getAccounts(): string[] {\n if (!this.currentSession) return [];\n return Object.values(this.currentSession.namespaces)\n .flatMap((ns) => ns.accounts || []);\n }\n\n getSession(): SessionTypes.Struct | null {\n return this.currentSession;\n }\n\n async destroy(): Promise<void> {\n if (this.browserUI) {\n await this.browserUI.stop();\n this.browserUI = null;\n }\n this.removeAllListeners();\n if (this.signClient) {\n try {\n await this.signClient.core.relayer.transportClose();\n } catch {\n // ignore cleanup errors\n }\n }\n this.signClient = null;\n this.currentSession = null;\n }\n\n // Type-safe event emitter overrides\n override on<K extends keyof WalletConnectCLIEvents>(event: K, listener: WalletConnectCLIEvents[K]): this {\n return super.on(event, listener);\n }\n\n override once<K extends keyof WalletConnectCLIEvents>(event: K, listener: WalletConnectCLIEvents[K]): this {\n return super.once(event, listener);\n }\n\n override off<K extends keyof WalletConnectCLIEvents>(event: K, listener: WalletConnectCLIEvents[K]): this {\n return super.off(event, listener);\n }\n\n override emit<K extends keyof WalletConnectCLIEvents>(\n event: K,\n ...args: Parameters<WalletConnectCLIEvents[K]>\n ): boolean {\n return super.emit(event, ...args);\n }\n\n // ---------- Private -------------------------------------------------- //\n\n private logRequestDetails(options: RequestOptions): void {\n const walletName = this.currentSession?.peer.metadata.name;\n if (walletName) {\n console.log(`\\nRequesting approval on ${walletName}...`);\n }\n\n if (options.request.method === \"eth_sendTransaction\") {\n const params = options.request.params as Array<{ data?: string }>;\n const data = params[0]?.data;\n if (data && data !== \"0x\") {\n try {\n const decoded = execFileSync(\"cast\", [\"4d\", data], {\n encoding: \"utf-8\",\n timeout: 5000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim();\n if (decoded) {\n console.log(`\\n Decoded calldata:\\n${decoded.split(\"\\n\").map((l) => ` ${l}`).join(\"\\n\")}\\n`);\n }\n } catch {\n // cast not available or decode failed — skip silently\n }\n }\n }\n }\n\n private async ensureClient(): Promise<InstanceType<typeof SignClient>> {\n if (this.signClient) return this.signClient;\n\n const storagePath = this.options.storagePath || DEFAULT_STORAGE_PATH;\n const storage = new KeyValueStorage({ database: storagePath });\n\n this.signClient = await SignClient.init({\n projectId: this.options.projectId,\n metadata: this.options.metadata,\n storage,\n logger: this.options.logger || \"silent\",\n });\n\n // Forward sign-client events\n this.signClient.on(\"session_update\", ({ topic }) => {\n const session = this.signClient?.session.get(topic);\n if (session) {\n this.currentSession = session;\n this.emit(\"session_update\", session);\n }\n });\n\n this.signClient.on(\"session_delete\", ({ topic }) => {\n if (this.currentSession?.topic === topic) {\n this.currentSession = null;\n }\n this.emit(\"session_delete\", { topic });\n this.emit(\"disconnect\");\n });\n\n return this.signClient;\n }\n\n private async showBrowserUI(uri: string): Promise<void> {\n this.browserUI = createBrowserUI(this.options.port);\n try {\n const { url } = await this.browserUI.start(uri);\n console.log(`\\nConnect your wallet at: ${url}\\n`);\n } catch {\n // Fall back to terminal QR if browser fails\n console.log(\"Could not open browser, falling back to terminal QR code.\");\n const terminalUI = createTerminalUI();\n terminalUI.displayQR(uri);\n this.browserUI = null;\n }\n }\n\n private buildConnectResult(session: SessionTypes.Struct): ConnectResult {\n const accounts = Object.values(session.namespaces)\n .flatMap((ns) => ns.accounts || []);\n return {\n session,\n accounts,\n topic: session.topic,\n };\n }\n\n private extractErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (typeof error === \"object\" && error !== null) {\n const errObj = error as { message?: string };\n if (errObj.message) return errObj.message;\n return JSON.stringify(error);\n }\n return String(error);\n }\n}\n","import http from \"http\";\nimport type { AddressInfo } from \"net\";\nimport type { BrowserUI } from \"../types.js\";\n\ninterface SSEClient {\n res: http.ServerResponse;\n}\n\nconst SCRIPT_CLOSE = \"</script>\";\n\nfunction buildHTML(uri: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>WalletConnect — Connect Wallet</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n background: #1a1a2e;\n color: #e0e0e0;\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n }\n .container {\n text-align: center;\n padding: 2rem;\n max-width: 420px;\n }\n h1 { font-size: 1.5rem; margin-bottom: 0.5rem; color: #fff; }\n .subtitle { color: #8888aa; margin-bottom: 2rem; }\n #qr-container {\n background: #fff;\n border-radius: 16px;\n padding: 24px;\n display: inline-block;\n margin-bottom: 1.5rem;\n }\n #qr-container canvas { display: block; }\n .uri-box {\n background: #16213e;\n border: 1px solid #333;\n border-radius: 8px;\n padding: 12px;\n word-break: break-all;\n font-size: 0.75rem;\n color: #8888aa;\n margin-bottom: 1.5rem;\n cursor: pointer;\n transition: border-color 0.2s;\n }\n .uri-box:hover { border-color: #5566ff; }\n .uri-box:active { border-color: #3344dd; }\n #status {\n font-size: 0.9rem;\n padding: 8px 16px;\n border-radius: 8px;\n display: inline-block;\n }\n .status-waiting { background: #16213e; color: #8888aa; }\n .status-connected { background: #0a3d2a; color: #4ade80; }\n .status-error { background: #3d0a0a; color: #f87171; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <h1>Connect Your Wallet</h1>\n <p class=\"subtitle\">Scan the QR code with your mobile wallet</p>\n <div id=\"qr-container\"><canvas id=\"qr\"></canvas></div>\n <div class=\"uri-box\" onclick=\"navigator.clipboard.writeText('${uri}').then(()=>this.textContent='Copied!').catch(()=>{})\">\n ${uri}\n </div>\n <div id=\"status\" class=\"status-waiting\">Waiting for connection...</div>\n </div>\n <script src=\"https://cdn.jsdelivr.net/npm/qrcode@1/build/qrcode.min.js\">${SCRIPT_CLOSE}\n <script>\n QRCode.toCanvas(document.getElementById(\"qr\"), \"${uri}\", {\n width: 280,\n margin: 0,\n color: { dark: \"#1a1a2e\", light: \"#ffffff\" }\n });\n\n const evtSource = new EventSource(\"/events\");\n evtSource.onmessage = function(event) {\n const data = JSON.parse(event.data);\n const el = document.getElementById(\"status\");\n el.className = \"status-\" + data.status;\n el.textContent = data.message || data.status;\n if (data.status === \"connected\") {\n evtSource.close();\n setTimeout(() => window.close(), 2000);\n }\n };\n ${SCRIPT_CLOSE}\n</body>\n</html>`;\n}\n\nexport function createBrowserUI(preferredPort?: number): BrowserUI {\n let server: http.Server | null = null;\n const sseClients: SSEClient[] = [];\n\n return {\n async start(uri: string): Promise<{ port: number; url: string }> {\n const html = buildHTML(uri);\n\n server = http.createServer((req, res) => {\n if (req.url === \"/events\") {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n res.write(`data: ${JSON.stringify({ status: \"waiting\", message: \"Waiting for connection...\" })}\\n\\n`);\n const client: SSEClient = { res };\n sseClients.push(client);\n req.on(\"close\", () => {\n const idx = sseClients.indexOf(client);\n if (idx !== -1) sseClients.splice(idx, 1);\n });\n return;\n }\n\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(html);\n });\n\n const port = await new Promise<number>((resolve, reject) => {\n server!.listen(preferredPort || 0, \"127.0.0.1\", () => {\n const addr = server!.address() as AddressInfo;\n resolve(addr.port);\n });\n server!.on(\"error\", reject);\n });\n\n const url = `http://127.0.0.1:${port}`;\n\n // Dynamic import for ESM-only `open` package\n try {\n const { default: open } = await import(\"open\");\n await open(url);\n } catch {\n console.log(`Open your browser at: ${url}`);\n }\n\n return { port, url };\n },\n\n updateStatus(status: \"waiting\" | \"connected\" | \"error\", message?: string) {\n const payload = JSON.stringify({\n status,\n message: message || status,\n });\n for (const client of sseClients) {\n try {\n client.res.write(`data: ${payload}\\n\\n`);\n } catch {\n // Client disconnected — ignore\n }\n }\n },\n\n async stop() {\n for (const client of sseClients) {\n try {\n client.res.end();\n } catch {\n // Ignore\n }\n }\n sseClients.length = 0;\n\n if (server) {\n await new Promise<void>((resolve) => {\n server!.close(() => resolve());\n });\n server = null;\n }\n },\n };\n}\n","import type { SignClient } from \"@walletconnect/sign-client\";\nimport type { SessionTypes } from \"@walletconnect/types\";\n\nexport interface SessionManager {\n /** Returns the most recent valid (non-expired) session, or null */\n getExistingSession(client: InstanceType<typeof SignClient>): SessionTypes.Struct | null;\n /** Checks if a session has not expired */\n isSessionValid(session: SessionTypes.Struct): boolean;\n}\n\nexport function createSessionManager(): SessionManager {\n return {\n getExistingSession(client: InstanceType<typeof SignClient>): SessionTypes.Struct | null {\n const sessions = client.session.getAll();\n if (sessions.length === 0) return null;\n\n const now = Math.floor(Date.now() / 1000);\n const valid = sessions\n .filter((s) => s.expiry > now)\n .sort((a, b) => b.expiry - a.expiry);\n\n return valid.length > 0 ? valid[0] : null;\n },\n\n isSessionValid(session: SessionTypes.Struct): boolean {\n const now = Math.floor(Date.now() / 1000);\n return session.expiry > now;\n },\n };\n}\n","import qrcodeModule from \"qrcode-terminal\";\nimport type { TerminalUI } from \"./types.js\";\n\nexport function createTerminalUI(): TerminalUI {\n return {\n displayQR(uri: string) {\n console.log(\"\\nScan this QR code with your wallet app:\\n\");\n qrcodeModule.generate(uri, { small: true });\n console.log(\"\\nOr copy this URI:\", uri);\n console.log(\"\\nWaiting for wallet connection...\\n\");\n },\n\n showStatus(message: string) {\n console.log(`[WalletConnect] ${message}`);\n },\n\n showError(message: string) {\n console.error(`[WalletConnect] Error: ${message}`);\n },\n\n showSuccess(message: string) {\n console.log(`[WalletConnect] ${message}`);\n },\n };\n}\n","import { homedir } from \"os\";\nimport { join } from \"path\";\nimport { readFileSync, writeFileSync, mkdirSync } from \"fs\";\n\nconst CONFIG_DIR = join(homedir(), \".walletconnect-cli\");\nconst CONFIG_FILE = join(CONFIG_DIR, \"config.json\");\n\ninterface Config {\n projectId?: string;\n}\n\nfunction readConfig(): Config {\n try {\n return JSON.parse(readFileSync(CONFIG_FILE, \"utf-8\")) as Config;\n } catch {\n return {};\n }\n}\n\nfunction writeConfig(config: Config): void {\n mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + \"\\n\", { mode: 0o600 });\n}\n\n/** Get a config value */\nexport function getConfigValue(key: keyof Config): string | undefined {\n return readConfig()[key];\n}\n\n/** Set a config value */\nexport function setConfigValue(key: keyof Config, value: string): void {\n const config = readConfig();\n config[key] = value;\n writeConfig(config);\n}\n\n/** Resolve project ID: env var > config file. Returns undefined if neither is set. */\nexport function resolveProjectId(): string | undefined {\n return process.env.WALLETCONNECT_PROJECT_ID || getConfigValue(\"projectId\");\n}\n"],"mappings":"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","names":["index_exports","__export","WalletConnectCLI","createBrowserUI","createSessionManager","createTerminalUI","getConfigValue","resolveProjectId","setConfigValue","withWallet","__toCommonJS","import_events","import_child_process","import_os","import_path","import_keyvaluestorage","import_sign_client","import_http","SCRIPT_CLOSE","buildHTML","uri","createBrowserUI","preferredPort","server","sseClients","html","http","req","res","client","idx","port","resolve","reject","addr","url","open","status","message","payload","createSessionManager","client","sessions","now","valid","s","a","b","session","import_qrcode_terminal","createTerminalUI","uri","qrcodeModule","message","DEFAULT_METHODS","DEFAULT_EVENTS","DEFAULT_CHAINS","DEFAULT_STORAGE_PATH","WalletConnectCLI","options","createSessionManager","client","existing","connectOptions","result","chains","methods","events","optionalNamespaces","uri","approval","createTerminalUI","session","topic","error","message","errObj","swallow","ns","event","listener","args","walletName","data","decoded","l","storagePath","storage","createBrowserUI","url","accounts","import_os","import_path","import_fs","CONFIG_DIR","CONFIG_FILE","readConfig","writeConfig","config","getConfigValue","key","setConfigValue","value","resolveProjectId","withWallet","options","callback","wallet","WalletConnectCLI","result"]}
@@ -0,0 +1,146 @@
1
+ import { EventEmitter } from 'events';
2
+ import { SessionTypes, SignClientTypes } from '@walletconnect/types';
3
+ import { SignClient } from '@walletconnect/sign-client';
4
+
5
+ interface WalletConnectCLIOptions {
6
+ /** WalletConnect Cloud project ID (required) */
7
+ projectId: string;
8
+ /** App metadata shown to wallet during pairing */
9
+ metadata: SignClientTypes.Metadata;
10
+ /** Directory path for persistent session storage. Default: ~/.walletconnect-cli/ */
11
+ storagePath?: string;
12
+ /** Connection UI mode. Default: 'terminal' */
13
+ ui?: "terminal" | "browser";
14
+ /** CAIP-2 chain IDs to request. Default: ['eip155:1'] */
15
+ chains?: string[];
16
+ /** JSON-RPC methods to request. Default: common EVM signing methods */
17
+ methods?: string[];
18
+ /** Events to subscribe to. Default: ['chainChanged', 'accountsChanged'] */
19
+ events?: string[];
20
+ /** Port for browser UI server. Default: auto-assigned */
21
+ port?: number;
22
+ /** Auto-restore previous session on connect(). Default: true */
23
+ autoConnect?: boolean;
24
+ /** Log verbosity level. Default: 'silent' */
25
+ logger?: "info" | "debug" | "silent";
26
+ }
27
+ interface ConnectOptions {
28
+ /** Override the namespaces for this connection attempt */
29
+ optionalNamespaces?: Record<string, {
30
+ chains: string[];
31
+ methods: string[];
32
+ events: string[];
33
+ }>;
34
+ }
35
+ interface ConnectResult {
36
+ /** The approved session */
37
+ session: SessionTypes.Struct;
38
+ /** CAIP-10 account IDs (e.g. 'eip155:1:0xABC...') */
39
+ accounts: string[];
40
+ /** Session topic for subsequent requests */
41
+ topic: string;
42
+ }
43
+ interface RequestOptions {
44
+ /** Session topic. If omitted, uses the current active session topic */
45
+ topic?: string;
46
+ /** CAIP-2 chain ID (e.g. 'eip155:1') */
47
+ chainId: string;
48
+ /** JSON-RPC request */
49
+ request: {
50
+ method: string;
51
+ params: unknown[];
52
+ };
53
+ }
54
+ interface WalletConnectCLIEvents {
55
+ connect: (result: ConnectResult) => void;
56
+ disconnect: () => void;
57
+ session_update: (session: SessionTypes.Struct) => void;
58
+ session_delete: (event: {
59
+ topic: string;
60
+ }) => void;
61
+ }
62
+ interface WithWalletOptions extends WalletConnectCLIOptions {
63
+ /** Options to pass to connect() */
64
+ connectOptions?: ConnectOptions;
65
+ /** If false, skip disconnect after callback completes. Default: true */
66
+ disconnectAfter?: boolean;
67
+ }
68
+ interface TerminalUI {
69
+ displayQR(uri: string): void;
70
+ showStatus(message: string): void;
71
+ showError(message: string): void;
72
+ showSuccess(message: string): void;
73
+ }
74
+ interface BrowserUI {
75
+ start(uri: string): Promise<{
76
+ port: number;
77
+ url: string;
78
+ }>;
79
+ updateStatus(status: "waiting" | "connected" | "error", message?: string): void;
80
+ stop(): Promise<void>;
81
+ }
82
+
83
+ declare class WalletConnectCLI extends EventEmitter {
84
+ private readonly options;
85
+ private signClient;
86
+ private currentSession;
87
+ private browserUI;
88
+ private readonly sessionManager;
89
+ constructor(options: WalletConnectCLIOptions);
90
+ tryRestore(): Promise<ConnectResult | null>;
91
+ connect(connectOptions?: ConnectOptions): Promise<ConnectResult>;
92
+ request<T = unknown>(options: RequestOptions): Promise<T>;
93
+ disconnect(): Promise<void>;
94
+ isConnected(): boolean;
95
+ getAccounts(): string[];
96
+ getSession(): SessionTypes.Struct | null;
97
+ destroy(): Promise<void>;
98
+ on<K extends keyof WalletConnectCLIEvents>(event: K, listener: WalletConnectCLIEvents[K]): this;
99
+ once<K extends keyof WalletConnectCLIEvents>(event: K, listener: WalletConnectCLIEvents[K]): this;
100
+ off<K extends keyof WalletConnectCLIEvents>(event: K, listener: WalletConnectCLIEvents[K]): this;
101
+ emit<K extends keyof WalletConnectCLIEvents>(event: K, ...args: Parameters<WalletConnectCLIEvents[K]>): boolean;
102
+ private logRequestDetails;
103
+ private ensureClient;
104
+ private showBrowserUI;
105
+ private buildConnectResult;
106
+ private extractErrorMessage;
107
+ }
108
+
109
+ interface SessionManager {
110
+ /** Returns the most recent valid (non-expired) session, or null */
111
+ getExistingSession(client: InstanceType<typeof SignClient>): SessionTypes.Struct | null;
112
+ /** Checks if a session has not expired */
113
+ isSessionValid(session: SessionTypes.Struct): boolean;
114
+ }
115
+ declare function createSessionManager(): SessionManager;
116
+
117
+ declare function createTerminalUI(): TerminalUI;
118
+
119
+ declare function createBrowserUI(preferredPort?: number): BrowserUI;
120
+
121
+ interface Config {
122
+ projectId?: string;
123
+ }
124
+ /** Get a config value */
125
+ declare function getConfigValue(key: keyof Config): string | undefined;
126
+ /** Set a config value */
127
+ declare function setConfigValue(key: keyof Config, value: string): void;
128
+ /** Resolve project ID: env var > config file. Returns undefined if neither is set. */
129
+ declare function resolveProjectId(): string | undefined;
130
+
131
+ /**
132
+ * Higher-level helper that wraps the connect → callback → cleanup pattern.
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * await withWallet({ projectId, metadata }, async (wallet, { accounts }) => {
137
+ * const txHash = await wallet.request({
138
+ * chainId: 'eip155:1',
139
+ * request: { method: 'eth_sendTransaction', params: [tx] }
140
+ * });
141
+ * });
142
+ * ```
143
+ */
144
+ declare function withWallet(options: WithWalletOptions, callback: (wallet: WalletConnectCLI, result: ConnectResult) => Promise<void>): Promise<void>;
145
+
146
+ export { type BrowserUI, type ConnectOptions, type ConnectResult, type RequestOptions, type TerminalUI, WalletConnectCLI, type WalletConnectCLIEvents, type WalletConnectCLIOptions, type WithWalletOptions, createBrowserUI, createSessionManager, createTerminalUI, getConfigValue, resolveProjectId, setConfigValue, withWallet };
@@ -0,0 +1,146 @@
1
+ import { EventEmitter } from 'events';
2
+ import { SessionTypes, SignClientTypes } from '@walletconnect/types';
3
+ import { SignClient } from '@walletconnect/sign-client';
4
+
5
+ interface WalletConnectCLIOptions {
6
+ /** WalletConnect Cloud project ID (required) */
7
+ projectId: string;
8
+ /** App metadata shown to wallet during pairing */
9
+ metadata: SignClientTypes.Metadata;
10
+ /** Directory path for persistent session storage. Default: ~/.walletconnect-cli/ */
11
+ storagePath?: string;
12
+ /** Connection UI mode. Default: 'terminal' */
13
+ ui?: "terminal" | "browser";
14
+ /** CAIP-2 chain IDs to request. Default: ['eip155:1'] */
15
+ chains?: string[];
16
+ /** JSON-RPC methods to request. Default: common EVM signing methods */
17
+ methods?: string[];
18
+ /** Events to subscribe to. Default: ['chainChanged', 'accountsChanged'] */
19
+ events?: string[];
20
+ /** Port for browser UI server. Default: auto-assigned */
21
+ port?: number;
22
+ /** Auto-restore previous session on connect(). Default: true */
23
+ autoConnect?: boolean;
24
+ /** Log verbosity level. Default: 'silent' */
25
+ logger?: "info" | "debug" | "silent";
26
+ }
27
+ interface ConnectOptions {
28
+ /** Override the namespaces for this connection attempt */
29
+ optionalNamespaces?: Record<string, {
30
+ chains: string[];
31
+ methods: string[];
32
+ events: string[];
33
+ }>;
34
+ }
35
+ interface ConnectResult {
36
+ /** The approved session */
37
+ session: SessionTypes.Struct;
38
+ /** CAIP-10 account IDs (e.g. 'eip155:1:0xABC...') */
39
+ accounts: string[];
40
+ /** Session topic for subsequent requests */
41
+ topic: string;
42
+ }
43
+ interface RequestOptions {
44
+ /** Session topic. If omitted, uses the current active session topic */
45
+ topic?: string;
46
+ /** CAIP-2 chain ID (e.g. 'eip155:1') */
47
+ chainId: string;
48
+ /** JSON-RPC request */
49
+ request: {
50
+ method: string;
51
+ params: unknown[];
52
+ };
53
+ }
54
+ interface WalletConnectCLIEvents {
55
+ connect: (result: ConnectResult) => void;
56
+ disconnect: () => void;
57
+ session_update: (session: SessionTypes.Struct) => void;
58
+ session_delete: (event: {
59
+ topic: string;
60
+ }) => void;
61
+ }
62
+ interface WithWalletOptions extends WalletConnectCLIOptions {
63
+ /** Options to pass to connect() */
64
+ connectOptions?: ConnectOptions;
65
+ /** If false, skip disconnect after callback completes. Default: true */
66
+ disconnectAfter?: boolean;
67
+ }
68
+ interface TerminalUI {
69
+ displayQR(uri: string): void;
70
+ showStatus(message: string): void;
71
+ showError(message: string): void;
72
+ showSuccess(message: string): void;
73
+ }
74
+ interface BrowserUI {
75
+ start(uri: string): Promise<{
76
+ port: number;
77
+ url: string;
78
+ }>;
79
+ updateStatus(status: "waiting" | "connected" | "error", message?: string): void;
80
+ stop(): Promise<void>;
81
+ }
82
+
83
+ declare class WalletConnectCLI extends EventEmitter {
84
+ private readonly options;
85
+ private signClient;
86
+ private currentSession;
87
+ private browserUI;
88
+ private readonly sessionManager;
89
+ constructor(options: WalletConnectCLIOptions);
90
+ tryRestore(): Promise<ConnectResult | null>;
91
+ connect(connectOptions?: ConnectOptions): Promise<ConnectResult>;
92
+ request<T = unknown>(options: RequestOptions): Promise<T>;
93
+ disconnect(): Promise<void>;
94
+ isConnected(): boolean;
95
+ getAccounts(): string[];
96
+ getSession(): SessionTypes.Struct | null;
97
+ destroy(): Promise<void>;
98
+ on<K extends keyof WalletConnectCLIEvents>(event: K, listener: WalletConnectCLIEvents[K]): this;
99
+ once<K extends keyof WalletConnectCLIEvents>(event: K, listener: WalletConnectCLIEvents[K]): this;
100
+ off<K extends keyof WalletConnectCLIEvents>(event: K, listener: WalletConnectCLIEvents[K]): this;
101
+ emit<K extends keyof WalletConnectCLIEvents>(event: K, ...args: Parameters<WalletConnectCLIEvents[K]>): boolean;
102
+ private logRequestDetails;
103
+ private ensureClient;
104
+ private showBrowserUI;
105
+ private buildConnectResult;
106
+ private extractErrorMessage;
107
+ }
108
+
109
+ interface SessionManager {
110
+ /** Returns the most recent valid (non-expired) session, or null */
111
+ getExistingSession(client: InstanceType<typeof SignClient>): SessionTypes.Struct | null;
112
+ /** Checks if a session has not expired */
113
+ isSessionValid(session: SessionTypes.Struct): boolean;
114
+ }
115
+ declare function createSessionManager(): SessionManager;
116
+
117
+ declare function createTerminalUI(): TerminalUI;
118
+
119
+ declare function createBrowserUI(preferredPort?: number): BrowserUI;
120
+
121
+ interface Config {
122
+ projectId?: string;
123
+ }
124
+ /** Get a config value */
125
+ declare function getConfigValue(key: keyof Config): string | undefined;
126
+ /** Set a config value */
127
+ declare function setConfigValue(key: keyof Config, value: string): void;
128
+ /** Resolve project ID: env var > config file. Returns undefined if neither is set. */
129
+ declare function resolveProjectId(): string | undefined;
130
+
131
+ /**
132
+ * Higher-level helper that wraps the connect → callback → cleanup pattern.
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * await withWallet({ projectId, metadata }, async (wallet, { accounts }) => {
137
+ * const txHash = await wallet.request({
138
+ * chainId: 'eip155:1',
139
+ * request: { method: 'eth_sendTransaction', params: [tx] }
140
+ * });
141
+ * });
142
+ * ```
143
+ */
144
+ declare function withWallet(options: WithWalletOptions, callback: (wallet: WalletConnectCLI, result: ConnectResult) => Promise<void>): Promise<void>;
145
+
146
+ export { type BrowserUI, type ConnectOptions, type ConnectResult, type RequestOptions, type TerminalUI, WalletConnectCLI, type WalletConnectCLIEvents, type WalletConnectCLIOptions, type WithWalletOptions, createBrowserUI, createSessionManager, createTerminalUI, getConfigValue, resolveProjectId, setConfigValue, withWallet };
package/dist/index.js ADDED
@@ -0,0 +1,108 @@
1
+ import{EventEmitter as U}from"events";import{execFileSync as O}from"child_process";import{homedir as R}from"os";import{join as W}from"path";import{KeyValueStorage as j}from"@walletconnect/keyvaluestorage";import{SignClient as k}from"@walletconnect/sign-client";import x from"http";var y="</script>";function T(n){return`<!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>WalletConnect \u2014 Connect Wallet</title>
7
+ <style>
8
+ * { margin: 0; padding: 0; box-sizing: border-box; }
9
+ body {
10
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
11
+ background: #1a1a2e;
12
+ color: #e0e0e0;
13
+ display: flex;
14
+ justify-content: center;
15
+ align-items: center;
16
+ min-height: 100vh;
17
+ }
18
+ .container {
19
+ text-align: center;
20
+ padding: 2rem;
21
+ max-width: 420px;
22
+ }
23
+ h1 { font-size: 1.5rem; margin-bottom: 0.5rem; color: #fff; }
24
+ .subtitle { color: #8888aa; margin-bottom: 2rem; }
25
+ #qr-container {
26
+ background: #fff;
27
+ border-radius: 16px;
28
+ padding: 24px;
29
+ display: inline-block;
30
+ margin-bottom: 1.5rem;
31
+ }
32
+ #qr-container canvas { display: block; }
33
+ .uri-box {
34
+ background: #16213e;
35
+ border: 1px solid #333;
36
+ border-radius: 8px;
37
+ padding: 12px;
38
+ word-break: break-all;
39
+ font-size: 0.75rem;
40
+ color: #8888aa;
41
+ margin-bottom: 1.5rem;
42
+ cursor: pointer;
43
+ transition: border-color 0.2s;
44
+ }
45
+ .uri-box:hover { border-color: #5566ff; }
46
+ .uri-box:active { border-color: #3344dd; }
47
+ #status {
48
+ font-size: 0.9rem;
49
+ padding: 8px 16px;
50
+ border-radius: 8px;
51
+ display: inline-block;
52
+ }
53
+ .status-waiting { background: #16213e; color: #8888aa; }
54
+ .status-connected { background: #0a3d2a; color: #4ade80; }
55
+ .status-error { background: #3d0a0a; color: #f87171; }
56
+ </style>
57
+ </head>
58
+ <body>
59
+ <div class="container">
60
+ <h1>Connect Your Wallet</h1>
61
+ <p class="subtitle">Scan the QR code with your mobile wallet</p>
62
+ <div id="qr-container"><canvas id="qr"></canvas></div>
63
+ <div class="uri-box" onclick="navigator.clipboard.writeText('${n}').then(()=>this.textContent='Copied!').catch(()=>{})">
64
+ ${n}
65
+ </div>
66
+ <div id="status" class="status-waiting">Waiting for connection...</div>
67
+ </div>
68
+ <script src="https://cdn.jsdelivr.net/npm/qrcode@1/build/qrcode.min.js">${y}
69
+ <script>
70
+ QRCode.toCanvas(document.getElementById("qr"), "${n}", {
71
+ width: 280,
72
+ margin: 0,
73
+ color: { dark: "#1a1a2e", light: "#ffffff" }
74
+ });
75
+
76
+ const evtSource = new EventSource("/events");
77
+ evtSource.onmessage = function(event) {
78
+ const data = JSON.parse(event.data);
79
+ const el = document.getElementById("status");
80
+ el.className = "status-" + data.status;
81
+ el.textContent = data.message || data.status;
82
+ if (data.status === "connected") {
83
+ evtSource.close();
84
+ setTimeout(() => window.close(), 2000);
85
+ }
86
+ };
87
+ ${y}
88
+ </body>
89
+ </html>`}function g(n){let i=null,e=[];return{async start(t){let o=T(t);i=x.createServer((a,c)=>{if(a.url==="/events"){c.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}),c.write(`data: ${JSON.stringify({status:"waiting",message:"Waiting for connection..."})}
90
+
91
+ `);let l={res:c};e.push(l),a.on("close",()=>{let u=e.indexOf(l);u!==-1&&e.splice(u,1)});return}c.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),c.end(o)});let s=await new Promise((a,c)=>{i.listen(n||0,"127.0.0.1",()=>{let l=i.address();a(l.port)}),i.on("error",c)}),r=`http://127.0.0.1:${s}`;try{let{default:a}=await import("open");await a(r)}catch{console.log(`Open your browser at: ${r}`)}return{port:s,url:r}},updateStatus(t,o){let s=JSON.stringify({status:t,message:o||t});for(let r of e)try{r.res.write(`data: ${s}
92
+
93
+ `)}catch{}},async stop(){for(let t of e)try{t.res.end()}catch{}e.length=0,i&&(await new Promise(t=>{i.close(()=>t())}),i=null)}}}function f(){return{getExistingSession(n){let i=n.session.getAll();if(i.length===0)return null;let e=Math.floor(Date.now()/1e3),t=i.filter(o=>o.expiry>e).sort((o,s)=>s.expiry-o.expiry);return t.length>0?t[0]:null},isSessionValid(n){let i=Math.floor(Date.now()/1e3);return n.expiry>i}}}import E from"qrcode-terminal";function m(){return{displayQR(n){console.log(`
94
+ Scan this QR code with your wallet app:
95
+ `),E.generate(n,{small:!0}),console.log(`
96
+ Or copy this URI:`,n),console.log(`
97
+ Waiting for wallet connection...
98
+ `)},showStatus(n){console.log(`[WalletConnect] ${n}`)},showError(n){console.error(`[WalletConnect] Error: ${n}`)},showSuccess(n){console.log(`[WalletConnect] ${n}`)}}}var L=["eth_sendTransaction","eth_signTransaction","personal_sign","eth_sign","eth_signTypedData","eth_signTypedData_v4"],q=["chainChanged","accountsChanged"],_=["eip155:1"],P=W(R(),".walletconnect-cli"),p=class extends U{constructor(e){super();this.signClient=null;this.currentSession=null;this.browserUI=null;this.sessionManager=f();this.options=e}async tryRestore(){let e=await this.ensureClient(),t=this.sessionManager.getExistingSession(e);return t?(this.currentSession=t,this.buildConnectResult(t)):null}async connect(e){let t=await this.ensureClient();if(this.options.autoConnect!==!1){let d=this.sessionManager.getExistingSession(t);if(d){this.currentSession=d;let C=this.buildConnectResult(d);return this.emit("connect",C),C}}let o=this.options.chains||_,s=this.options.methods||L,r=this.options.events||q,a=e?.optionalNamespaces||{eip155:{chains:o,methods:s,events:r}},{uri:c,approval:l}=await t.connect({optionalNamespaces:a});if(!c)throw new Error("Failed to generate WalletConnect URI");this.options.ui==="browser"?await this.showBrowserUI(c):m().displayQR(c);let u=await l();this.currentSession=u,this.browserUI&&(this.browserUI.updateStatus("connected",`Connected to ${u.peer.metadata.name}`),setTimeout(()=>this.browserUI?.stop(),3e3));let h=this.buildConnectResult(u);return this.emit("connect",h),h}async request(e){let t=await this.ensureClient(),o=e.topic||this.currentSession?.topic;if(!o)throw new Error("No active session. Call connect() first.");this.logRequestDetails(e);try{return await t.request({topic:o,chainId:e.chainId,request:e.request})}catch(s){let r=this.extractErrorMessage(s);if(r.includes("rejected")||r.includes("denied")||r.includes("cancelled"))throw new Error("Request rejected by user");if(typeof s=="object"&&s!==null){let a=s;if(a.code===0&&!a.message)throw new Error("Request rejected or timed out in wallet")}throw s}}async disconnect(){if(this.currentSession){try{let e=await this.ensureClient(),t=()=>{};e.core.relayer.on("error",t);try{await e.disconnect({topic:this.currentSession.topic,reason:{code:6e3,message:"User disconnected"}})}finally{e.core.relayer.off("error",t)}}catch{}this.currentSession=null,this.emit("disconnect")}}isConnected(){return this.currentSession?this.sessionManager.isSessionValid(this.currentSession):!1}getAccounts(){return this.currentSession?Object.values(this.currentSession.namespaces).flatMap(e=>e.accounts||[]):[]}getSession(){return this.currentSession}async destroy(){if(this.browserUI&&(await this.browserUI.stop(),this.browserUI=null),this.removeAllListeners(),this.signClient)try{await this.signClient.core.relayer.transportClose()}catch{}this.signClient=null,this.currentSession=null}on(e,t){return super.on(e,t)}once(e,t){return super.once(e,t)}off(e,t){return super.off(e,t)}emit(e,...t){return super.emit(e,...t)}logRequestDetails(e){let t=this.currentSession?.peer.metadata.name;if(t&&console.log(`
99
+ Requesting approval on ${t}...`),e.request.method==="eth_sendTransaction"){let s=e.request.params[0]?.data;if(s&&s!=="0x")try{let r=O("cast",["4d",s],{encoding:"utf-8",timeout:5e3,stdio:["pipe","pipe","pipe"]}).trim();r&&console.log(`
100
+ Decoded calldata:
101
+ ${r.split(`
102
+ `).map(a=>` ${a}`).join(`
103
+ `)}
104
+ `)}catch{}}}async ensureClient(){if(this.signClient)return this.signClient;let e=this.options.storagePath||P,t=new j({database:e});return this.signClient=await k.init({projectId:this.options.projectId,metadata:this.options.metadata,storage:t,logger:this.options.logger||"silent"}),this.signClient.on("session_update",({topic:o})=>{let s=this.signClient?.session.get(o);s&&(this.currentSession=s,this.emit("session_update",s))}),this.signClient.on("session_delete",({topic:o})=>{this.currentSession?.topic===o&&(this.currentSession=null),this.emit("session_delete",{topic:o}),this.emit("disconnect")}),this.signClient}async showBrowserUI(e){this.browserUI=g(this.options.port);try{let{url:t}=await this.browserUI.start(e);console.log(`
105
+ Connect your wallet at: ${t}
106
+ `)}catch{console.log("Could not open browser, falling back to terminal QR code."),m().displayQR(e),this.browserUI=null}}buildConnectResult(e){let t=Object.values(e.namespaces).flatMap(o=>o.accounts||[]);return{session:e,accounts:t,topic:e.topic}}extractErrorMessage(e){if(e instanceof Error)return e.message;if(typeof e=="object"&&e!==null){let t=e;return t.message?t.message:JSON.stringify(e)}return String(e)}};import{homedir as M}from"os";import{join as w}from"path";import{readFileSync as N,writeFileSync as $,mkdirSync as A}from"fs";var S=w(M(),".walletconnect-cli"),v=w(S,"config.json");function b(){try{return JSON.parse(N(v,"utf-8"))}catch{return{}}}function D(n){A(S,{recursive:!0,mode:448}),$(v,JSON.stringify(n,null,2)+`
107
+ `,{mode:384})}function I(n){return b()[n]}function B(n,i){let e=b();e[n]=i,D(e)}function F(){return process.env.WALLETCONNECT_PROJECT_ID||I("projectId")}async function ue(n,i){let e=new p(n);try{let t=await e.connect(n.connectOptions);await i(e,t),n.disconnectAfter!==!1&&await e.disconnect()}finally{await e.destroy()}}export{p as WalletConnectCLI,g as createBrowserUI,f as createSessionManager,m as createTerminalUI,I as getConfigValue,F as resolveProjectId,B as setConfigValue,ue as withWallet};
108
+ //# sourceMappingURL=index.js.map