toncorp-wallet-connect-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/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # toncorp-wallet-connect-sdk
2
+
3
+ Connect TonPass, OneDollar and more wallets from any DApp or website.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install toncorp-wallet-connect-sdk
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Specific wallet
14
+
15
+ ```typescript
16
+ import { TonPassConnect } from 'toncorp-wallet-connect-sdk';
17
+
18
+ const wallet = new TonPassConnect({
19
+ appId: 'your_app_id',
20
+ registryUrl: 'https://api.example.com/connect/wallets',
21
+ });
22
+
23
+ const result = await wallet.connect();
24
+ console.log(result.wallets); // [{ address: '0x...', chain: 'TON' }]
25
+ console.log(result.user); // { username: 'john', avatar: '...' }
26
+ ```
27
+
28
+ ```typescript
29
+ import { OneDollarConnect } from 'toncorp-wallet-connect-sdk';
30
+
31
+ const wallet = new OneDollarConnect({
32
+ appId: 'your_app_id',
33
+ registryUrl: 'https://api.example.com/connect/wallets',
34
+ });
35
+
36
+ const result = await wallet.connect();
37
+ ```
38
+
39
+ ### All wallets (show picker)
40
+
41
+ ```typescript
42
+ import { BaseWalletConnect } from 'toncorp-wallet-connect-sdk';
43
+
44
+ const wallet = new BaseWalletConnect({
45
+ appId: 'your_app_id',
46
+ registryUrl: 'https://api.example.com/connect/wallets',
47
+ // walletId: ['tonpass', 'onedollar'], // optional filter
48
+ });
49
+
50
+ const result = await wallet.connect();
51
+ ```
52
+
53
+ ### Script tag (UMD)
54
+
55
+ ```html
56
+ <script src="https://unpkg.com/toncorp-wallet-connect-sdk/dist/index.umd.js"></script>
57
+ <script>
58
+ const wallet = new WalletConnectSDK.TonPassConnect({
59
+ appId: 'your_app_id',
60
+ registryUrl: 'https://api.example.com/connect/wallets',
61
+ });
62
+
63
+ document.getElementById('connect-btn').onclick = async () => {
64
+ const result = await wallet.connect();
65
+ console.log(result);
66
+ };
67
+ </script>
68
+ ```
69
+
70
+ ## API
71
+
72
+ ### Constructor options
73
+
74
+ | Option | Type | Required | Description |
75
+ |--------|------|----------|-------------|
76
+ | `appId` | `string` | Yes | Your registered app ID |
77
+ | `registryUrl` | `string` | Yes | URL to fetch available wallets |
78
+ | `walletId` | `string \| string[]` | No | Filter wallets (only for `BaseWalletConnect`) |
79
+ | `theme` | `'light' \| 'dark'` | No | Modal theme (default: `light`) |
80
+
81
+ ### Methods
82
+
83
+ | Method | Returns | Description |
84
+ |--------|---------|-------------|
85
+ | `connect()` | `Promise<ConnectResult>` | Open modal and wait for user to approve |
86
+ | `disconnect()` | `void` | Disconnect and clear session |
87
+ | `isConnected()` | `boolean` | Check connection status |
88
+ | `getWallet()` | `ConnectResult \| null` | Get current connection info |
89
+ | `on(event, cb)` | `void` | Listen to events |
90
+ | `off(event, cb)` | `void` | Remove listener |
91
+
92
+ ### Events
93
+
94
+ | Event | Data | Description |
95
+ |-------|------|-------------|
96
+ | `connect` | `ConnectResult` | Connected successfully |
97
+ | `disconnect` | — | Disconnected |
98
+ | `error` | `string` | Transport error |
99
+ | `session_expired` | — | Session timed out |
100
+
101
+ ## Publish to npm
102
+
103
+ ### Prerequisites
104
+
105
+ ```bash
106
+ # Login to npm (one-time)
107
+ npm login
108
+
109
+ # If using scoped package (@aspect-wallet), make sure the org exists on npmjs.com
110
+ # Or change the name in package.json to an unscoped name
111
+ ```
112
+
113
+ ### Build & Publish
114
+
115
+ ```bash
116
+ # Navigate to SDK folder
117
+ cd src/blockchain/walletconnect/sdk
118
+
119
+ # Install build dependencies
120
+ npm install
121
+
122
+ # Build (outputs to dist/)
123
+ npm run build
124
+
125
+ # Check what will be published
126
+ npm pack --dry-run
127
+
128
+ # Publish (first time — scoped packages default to private)
129
+ npm publish --access public
130
+
131
+ # Publish subsequent versions
132
+ # 1. Bump version first:
133
+ npm version patch # 0.1.0 → 0.1.1 (bug fixes)
134
+ npm version minor # 0.1.1 → 0.2.0 (new features)
135
+ npm version major # 0.2.0 → 1.0.0 (breaking changes)
136
+ # 2. Then publish:
137
+ npm publish --access public
138
+ ```
139
+
140
+ ### Verify
141
+
142
+ ```bash
143
+ # Check the published package
144
+ npm info toncorp-wallet-connect-sdk
145
+
146
+ # Install in another project to test
147
+ npm install toncorp-wallet-connect-sdk
148
+ ```
149
+
150
+ ### CDN (auto-available after publish)
151
+
152
+ ```
153
+ https://unpkg.com/toncorp-wallet-connect-sdk/dist/index.umd.js
154
+ https://cdn.jsdelivr.net/npm/toncorp-wallet-connect-sdk/dist/index.umd.js
155
+ ```
156
+
157
+ ## License
158
+
159
+ MIT
@@ -0,0 +1,27 @@
1
+ import type { WalletConnectConfig, ConnectResult, WalletConnectEventType, WalletConnectEventCallback } from './types';
2
+ export declare class BaseWalletConnect {
3
+ protected config: Required<Pick<WalletConnectConfig, 'appId' | 'registryUrl' | 'theme'>> & Pick<WalletConnectConfig, 'walletId'>;
4
+ private listeners;
5
+ private modal;
6
+ private wsTransport;
7
+ private pollingTransport;
8
+ private currentResult;
9
+ constructor(config: WalletConnectConfig);
10
+ connect(): Promise<ConnectResult>;
11
+ disconnect(): void;
12
+ isConnected(): boolean;
13
+ getWallet(): ConnectResult | null;
14
+ on(event: WalletConnectEventType, cb: WalletConnectEventCallback): void;
15
+ off(event: WalletConnectEventType, cb: WalletConnectEventCallback): void;
16
+ private get storageKey();
17
+ private fetchWallets;
18
+ private filterWallets;
19
+ private startConnect;
20
+ private initSession;
21
+ private listenForConfirmation;
22
+ private cleanup;
23
+ private emit;
24
+ private storeSession;
25
+ private restoreSession;
26
+ private removeStoredSession;
27
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";class e{constructor(e,t,n,s,i,o){this.apiUrl=e,this.sessionToken=t,this.onConfirmed=n,this.onRejected=s,this.onExpired=i,this.onError=o,this.ws=null,this.reconnectTimer=null,this.closed=!1}connect(){this.closed=!1;this.apiUrl.replace(/^http/,"ws").replace(/\/$/,"");this.sessionToken;try{this.connectSocketIO()}catch{this.onError("WebSocket connection failed")}}connectSocketIO(){const e=this.apiUrl.replace(/\/$/,"");fetch(`${e}/walletconnect/?EIO=4&transport=polling`).then(e=>e.text()).then(t=>{const n=t.replace(/^\d+/,""),s=JSON.parse(n).sid,i=`${e.replace(/^http/,"ws")}/walletconnect/?EIO=4&transport=websocket&sid=${s}`;this.ws=new WebSocket(i),this.ws.onopen=()=>{this.ws.send("2probe")},this.ws.onmessage=e=>{const t=e.data;if("3probe"!==t)if(t.startsWith("42"))try{const e=JSON.parse(t.slice(2)),[n,s]=e;this.handleEvent(n,s)}catch{}else"2"===t&&this.ws.send("3");else this.ws.send("5")},this.ws.onclose=()=>{this.closed||this.scheduleReconnect()},this.ws.onerror=()=>{this.closed||this.scheduleReconnect()}}).catch(()=>{this.closed||this.scheduleReconnect()})}handleEvent(e,t){switch(e){case"session_confirmed":this.onConfirmed(t),this.close();break;case"session_rejected":this.onRejected(),this.close();break;case"session_expired":this.onExpired(),this.close()}}scheduleReconnect(){this.closed||this.reconnectTimer||(this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.connectSocketIO()},3e3))}close(){this.closed=!0,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.ws&&(this.ws.close(),this.ws=null)}}class t{constructor(e,t,n,s,i,o){this.apiUrl=e,this.sessionToken=t,this.onConfirmed=n,this.onRejected=s,this.onExpired=i,this.onError=o,this.timer=null,this.stopped=!1}start(){this.stopped=!1,this.poll(),this.timer=setInterval(()=>this.poll(),2e3)}async poll(){if(!this.stopped)try{const e=this.apiUrl.replace(/\/$/,""),t=await fetch(`${e}/connect/status?token=${this.sessionToken}`);if(!t.ok)return;const n=await t.json();switch(n.status){case"CONFIRMED":this.onConfirmed({wallets:n.wallets,user:n.user}),this.stop();break;case"REJECTED":this.onRejected(),this.stop();break;case"EXPIRED":this.onExpired(),this.stop()}}catch{}}stop(){this.stopped=!0,this.timer&&(clearInterval(this.timer),this.timer=null)}}const n="__wc_modal__";class s{constructor(e,t){this.overlay=null,this.theme=e,this.onClose=t}showWalletPicker(e,t){const n=`\n <div class="wc-header">\n <h3 class="wc-title">Connect Wallet</h3>\n <button class="wc-close" data-action="close">&times;</button>\n </div>\n <div class="wc-body">\n <ul class="wc-wallet-list">${e.map(e=>`\n <li class="wc-wallet-item" data-wallet-id="${e.walletId}">\n ${e.icon?`<img class="wc-wallet-icon" src="${e.icon}" alt="${e.name}" />`:`<div class="wc-wallet-icon-placeholder">${e.name.charAt(0).toUpperCase()}</div>`}\n <div>\n <div class="wc-wallet-name">${e.name}</div>\n ${e.description?`<div class="wc-wallet-desc">${e.description}</div>`:""}\n </div>\n </li>`).join("")}</ul>\n </div>\n `;this.render(n),e.forEach(e=>{const n=this.overlay?.querySelector(`[data-wallet-id="${e.walletId}"]`);n?.addEventListener("click",()=>t(e))})}showConnect(e,t,n,s){const i=function(e,t=200){return`https://api.qrserver.com/v1/create-qr-code/?size=${t}x${t}&data=${encodeURIComponent(e)}`}(t),o=`\n <div class="wc-header">\n <div style="display:flex;align-items:center;gap:8px;">\n ${n?'<button class="wc-back" data-action="back">&#8592;</button>':""}\n <h3 class="wc-title">Connect ${e.name}</h3>\n </div>\n <button class="wc-close" data-action="close">&times;</button>\n </div>\n <div class="wc-body">\n <div class="wc-tabs">\n <button class="wc-tab active" data-tab="mobile">Mobile</button>\n <button class="wc-tab" data-tab="qr">QR Code</button>\n </div>\n <div data-panel="mobile">\n <a class="wc-deeplink-btn" href="${t}" target="_blank">\n Open in Telegram\n </a>\n </div>\n <div data-panel="qr" style="display:none;">\n <div class="wc-qr-container">\n <img class="wc-qr-canvas" src="${i}" width="200" height="200" alt="QR Code" />\n <div class="wc-qr-hint">Scan with your phone or from wallet app</div>\n </div>\n </div>\n <div class="wc-status">\n <div class="wc-spinner"></div>\n <span>Waiting for confirmation...</span>\n </div>\n </div>\n `;this.render(o);const r=this.overlay?.querySelectorAll(".wc-tab"),a=this.overlay?.querySelectorAll("[data-panel]");r?.forEach(e=>{e.addEventListener("click",()=>{const t=e.dataset.tab;r.forEach(e=>e.classList.remove("active")),e.classList.add("active"),a?.forEach(e=>{e.style.display=e.dataset.panel===t?"block":"none"})})}),n&&s&&this.overlay?.querySelector('[data-action="back"]')?.addEventListener("click",s)}updateStatus(e,t=!0){const n=this.overlay?.querySelector(".wc-status");n&&(n.innerHTML=`\n ${t?'<div class="wc-spinner"></div>':""}\n <span>${e}</span>\n `)}render(e){this.destroy();const t=document.createElement("div");t.id=n,t.innerHTML=`\n <style>${function(e){const t="dark"===e?"#16213e":"#f5f5f5",n="dark"===e?"#a0a0a0":"#666666",s="dark"===e?"#2a2a4a":"#e0e0e0",i="#3b82f6";return`\n .wc-overlay {\n position: fixed; inset: 0; z-index: 99999;\n background: rgba(0,0,0,0.5); display: flex;\n align-items: center; justify-content: center;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n .wc-modal {\n background: ${"dark"===e?"#1a1a2e":"#ffffff"}; border-radius: 16px; width: 380px;\n max-width: 90vw; box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n overflow: hidden; color: ${"dark"===e?"#e0e0e0":"#1a1a1a"};\n }\n .wc-header {\n display: flex; align-items: center; justify-content: space-between;\n padding: 20px 24px 16px; border-bottom: 1px solid ${s};\n }\n .wc-title { font-size: 18px; font-weight: 600; margin: 0; }\n .wc-close {\n background: none; border: none; cursor: pointer;\n font-size: 20px; color: ${n}; padding: 4px 8px;\n border-radius: 8px;\n }\n .wc-close:hover { background: ${t}; }\n .wc-body { padding: 16px 24px 24px; }\n .wc-wallet-list { list-style: none; margin: 0; padding: 0; }\n .wc-wallet-item {\n display: flex; align-items: center; gap: 12px;\n padding: 12px 16px; border-radius: 12px; cursor: pointer;\n border: 1px solid ${s}; margin-bottom: 8px;\n transition: background 0.15s;\n }\n .wc-wallet-item:hover { background: ${"dark"===e?"#0f3460":"#e8f0fe"}; }\n .wc-wallet-icon {\n width: 40px; height: 40px; border-radius: 10px;\n object-fit: cover; flex-shrink: 0;\n }\n .wc-wallet-icon-placeholder {\n width: 40px; height: 40px; border-radius: 10px;\n background: ${i}; display: flex; align-items: center;\n justify-content: center; color: #fff; font-weight: 700;\n font-size: 16px; flex-shrink: 0;\n }\n .wc-wallet-name { font-size: 15px; font-weight: 500; }\n .wc-wallet-desc { font-size: 12px; color: ${n}; margin-top: 2px; }\n\n /* Connect screen (after wallet selected) */\n .wc-tabs {\n display: flex; gap: 0; margin-bottom: 20px;\n border: 1px solid ${s}; border-radius: 10px; overflow: hidden;\n }\n .wc-tab {\n flex: 1; padding: 10px; text-align: center; cursor: pointer;\n font-size: 13px; font-weight: 500; background: ${t};\n border: none; color: ${n}; transition: all 0.15s;\n }\n .wc-tab.active { background: ${i}; color: #fff; }\n .wc-deeplink-btn {\n display: block; width: 100%; padding: 14px; border: none;\n border-radius: 12px; background: ${i}; color: #fff;\n font-size: 15px; font-weight: 600; cursor: pointer;\n text-align: center; text-decoration: none;\n }\n .wc-deeplink-btn:hover { opacity: 0.9; }\n .wc-qr-container {\n display: flex; flex-direction: column; align-items: center; gap: 12px;\n }\n .wc-qr-canvas {\n border-radius: 12px; padding: 16px; background: #fff;\n }\n .wc-qr-hint { font-size: 12px; color: ${n}; text-align: center; }\n .wc-status {\n display: flex; align-items: center; justify-content: center;\n gap: 8px; padding: 16px 0 0; font-size: 13px; color: ${n};\n }\n .wc-spinner {\n width: 16px; height: 16px; border: 2px solid ${s};\n border-top-color: ${i}; border-radius: 50%;\n animation: wc-spin 0.8s linear infinite;\n }\n @keyframes wc-spin { to { transform: rotate(360deg); } }\n .wc-back {\n background: none; border: none; cursor: pointer;\n font-size: 14px; color: ${i}; padding: 0;\n display: flex; align-items: center; gap: 4px;\n }\n .wc-back:hover { text-decoration: underline; }\n `}(this.theme)}</style>\n <div class="wc-overlay">\n <div class="wc-modal">${e}</div>\n </div>\n `,document.body.appendChild(t),this.overlay=t,this.overlay.querySelector('[data-action="close"]')?.addEventListener("click",()=>{this.onClose(),this.destroy()}),this.overlay.querySelector(".wc-overlay")?.addEventListener("click",e=>{e.target.classList.contains("wc-overlay")&&(this.onClose(),this.destroy())})}destroy(){const e=document.getElementById(n);e&&e.remove(),this.overlay=null}}class i{constructor(e){this.listeners=new Map,this.modal=null,this.wsTransport=null,this.pollingTransport=null,this.currentResult=null,this.config={appId:e.appId,registryUrl:e.registryUrl,walletId:e.walletId,theme:e.theme||"light"},this.restoreSession()}async connect(){if(this.currentResult)return this.currentResult;const e=await this.fetchWallets(),t=this.filterWallets(e);if(0===t.length)throw new Error("No supported wallets available");return new Promise((e,n)=>{this.modal=new s(this.config.theme,()=>{this.cleanup(),n(new Error("User closed modal"))}),1===t.length?this.startConnect(t[0],!1,e,n):this.modal.showWalletPicker(t,t=>{this.startConnect(t,!0,e,n)})})}disconnect(){this.currentResult=null,this.removeStoredSession(),this.cleanup(),this.emit("disconnect")}isConnected(){return null!==this.currentResult}getWallet(){return this.currentResult}on(e,t){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t)}off(e,t){this.listeners.get(e)?.delete(t)}get storageKey(){const e=this.config.walletId;return`__wc_session_${Array.isArray(e)?e.sort().join("_"):e||"all"}__`}async fetchWallets(){const e=this.config.registryUrl.replace(/\/$/,""),t=await fetch(e);if(!t.ok)throw new Error("Failed to fetch wallets");return t.json()}filterWallets(e){if(!this.config.walletId)return e;const t=Array.isArray(this.config.walletId)?this.config.walletId:[this.config.walletId];return e.filter(e=>t.includes(e.walletId))}async startConnect(e,t,n,s){try{const i=await this.initSession(e);this.modal?.showConnect(e,i.deeplink,t,()=>{this.cleanup(),this.connect().then(n).catch(s)}),this.listenForConfirmation(e.apiUrl,i.sessionToken,e=>{this.currentResult=e,this.storeSession(e),this.modal?.destroy(),this.modal=null,this.emit("connect",e),n(e)},()=>{this.modal?.updateStatus("Connection rejected",!1),setTimeout(()=>{this.modal?.destroy(),this.modal=null,s(new Error("Connection rejected by user"))},1500)},()=>{this.modal?.updateStatus("Session expired",!1),this.emit("session_expired"),setTimeout(()=>{this.modal?.destroy(),this.modal=null,s(new Error("Session expired"))},1500)})}catch(e){this.modal?.destroy(),this.modal=null,s(e instanceof Error?e:new Error(String(e)))}}async initSession(e){const t=e.apiUrl.replace(/\/$/,""),n=await fetch(`${t}/connect/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({appId:this.config.appId,walletId:e.walletId,origin:"undefined"!=typeof window?window.location.origin:""})});if(!n.ok)throw new Error("Failed to init session");return n.json()}listenForConfirmation(n,s,i,o,r){this.wsTransport=new e(n,s,i,o,r,()=>{this.pollingTransport=new t(n,s,i,o,r,e=>this.emit("error",e)),this.pollingTransport.start()}),this.wsTransport.connect()}cleanup(){this.wsTransport?.close(),this.wsTransport=null,this.pollingTransport?.stop(),this.pollingTransport=null,this.modal?.destroy(),this.modal=null}emit(e,t){this.listeners.get(e)?.forEach(e=>e(t))}storeSession(e){try{localStorage.setItem(this.storageKey,JSON.stringify(e))}catch{}}restoreSession(){try{const e=localStorage.getItem(this.storageKey);e&&(this.currentResult=JSON.parse(e))}catch{}}removeStoredSession(){try{localStorage.removeItem(this.storageKey)}catch{}}}exports.BaseWalletConnect=i,exports.OneDollarConnect=class extends i{constructor(e){super({...e,walletId:"onedollar"})}},exports.TonPassConnect=class extends i{constructor(e){super({...e,walletId:"tonpass"})}};
2
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","sources":["../../transport.ts","../../modal.ts","../../client.ts","../../onedollar.ts","../../tonpass.ts"],"sourcesContent":["import type { ConnectResult } from './types';\n\ntype TransportCallback = (data: ConnectResult) => void;\ntype TransportErrorCallback = (error: string) => void;\n\n// ── WebSocket Transport ──\n\nexport class WsTransport {\n private ws: WebSocket | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private closed = false;\n\n constructor(\n private apiUrl: string,\n private sessionToken: string,\n private onConfirmed: TransportCallback,\n private onRejected: () => void,\n private onExpired: () => void,\n private onError: TransportErrorCallback,\n ) {}\n\n connect(): void {\n this.closed = false;\n const wsUrl = this.apiUrl\n .replace(/^http/, 'ws')\n .replace(/\\/$/, '');\n const url = `${wsUrl}/walletconnect?sessionToken=${this.sessionToken}`;\n\n try {\n // Socket.IO uses polling upgrade — use native WS for simplicity in SDK\n // The BE gateway uses socket.io, so we connect via socket.io protocol\n this.connectSocketIO();\n } catch {\n this.onError('WebSocket connection failed');\n }\n }\n\n private connectSocketIO(): void {\n const baseUrl = this.apiUrl.replace(/\\/$/, '');\n\n // Socket.IO handshake: first GET for sid, then upgrade to WS\n const pollingUrl = `${baseUrl}/walletconnect/?EIO=4&transport=polling`;\n\n fetch(pollingUrl)\n .then((res) => res.text())\n .then((body) => {\n // Socket.IO response format: \"0{...json...}\"\n const jsonStr = body.replace(/^\\d+/, '');\n const handshake = JSON.parse(jsonStr);\n const sid = handshake.sid;\n\n const wsBase = baseUrl.replace(/^http/, 'ws');\n const wsUrl = `${wsBase}/walletconnect/?EIO=4&transport=websocket&sid=${sid}`;\n\n this.ws = new WebSocket(wsUrl);\n\n this.ws.onopen = () => {\n // Socket.IO upgrade probe\n this.ws!.send('2probe');\n };\n\n this.ws.onmessage = (event) => {\n const msg = event.data as string;\n\n if (msg === '3probe') {\n // Upgrade confirmed, send upgrade packet + join room\n this.ws!.send('5');\n // Emit connect event with sessionToken as query (already in URL)\n // Socket.IO auto-joins based on handshake query\n return;\n }\n\n // Handle Socket.IO event messages: 42[\"event_name\", {...data}]\n if (msg.startsWith('42')) {\n try {\n const payload = JSON.parse(msg.slice(2));\n const [eventName, data] = payload;\n this.handleEvent(eventName, data);\n } catch {\n // ignore malformed\n }\n return;\n }\n\n // Ping from server\n if (msg === '2') {\n this.ws!.send('3');\n }\n };\n\n this.ws.onclose = () => {\n if (!this.closed) {\n this.scheduleReconnect();\n }\n };\n\n this.ws.onerror = () => {\n if (!this.closed) {\n this.scheduleReconnect();\n }\n };\n })\n .catch(() => {\n if (!this.closed) {\n this.scheduleReconnect();\n }\n });\n }\n\n private handleEvent(eventName: string, data: any): void {\n switch (eventName) {\n case 'session_confirmed':\n this.onConfirmed(data);\n this.close();\n break;\n case 'session_rejected':\n this.onRejected();\n this.close();\n break;\n case 'session_expired':\n this.onExpired();\n this.close();\n break;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.closed || this.reconnectTimer) return;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connectSocketIO();\n }, 3000);\n }\n\n close(): void {\n this.closed = true;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n }\n}\n\n// ── Long-Poll Fallback ──\n\nexport class PollingTransport {\n private timer: ReturnType<typeof setInterval> | null = null;\n private stopped = false;\n\n constructor(\n private apiUrl: string,\n private sessionToken: string,\n private onConfirmed: TransportCallback,\n private onRejected: () => void,\n private onExpired: () => void,\n private onError: TransportErrorCallback,\n ) {}\n\n start(): void {\n this.stopped = false;\n this.poll();\n this.timer = setInterval(() => this.poll(), 2000);\n }\n\n private async poll(): Promise<void> {\n if (this.stopped) return;\n\n try {\n const baseUrl = this.apiUrl.replace(/\\/$/, '');\n const res = await fetch(\n `${baseUrl}/connect/status?token=${this.sessionToken}`,\n );\n if (!res.ok) return;\n\n const data = await res.json();\n\n switch (data.status) {\n case 'CONFIRMED':\n this.onConfirmed({ wallets: data.wallets, user: data.user });\n this.stop();\n break;\n case 'REJECTED':\n this.onRejected();\n this.stop();\n break;\n case 'EXPIRED':\n this.onExpired();\n this.stop();\n break;\n }\n } catch {\n // silently retry next interval\n }\n }\n\n stop(): void {\n this.stopped = true;\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n}\n","import type { WalletMeta } from './types';\n\nconst MODAL_ID = '__wc_modal__';\n\n// ── Styles (scoped, no conflict with host) ──\n\nfunction getStyles(theme: 'light' | 'dark'): string {\n const bg = theme === 'dark' ? '#1a1a2e' : '#ffffff';\n const bgSecondary = theme === 'dark' ? '#16213e' : '#f5f5f5';\n const text = theme === 'dark' ? '#e0e0e0' : '#1a1a1a';\n const textSecondary = theme === 'dark' ? '#a0a0a0' : '#666666';\n const border = theme === 'dark' ? '#2a2a4a' : '#e0e0e0';\n const primary = '#3b82f6';\n const hover = theme === 'dark' ? '#0f3460' : '#e8f0fe';\n\n return `\n .wc-overlay {\n position: fixed; inset: 0; z-index: 99999;\n background: rgba(0,0,0,0.5); display: flex;\n align-items: center; justify-content: center;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n .wc-modal {\n background: ${bg}; border-radius: 16px; width: 380px;\n max-width: 90vw; box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n overflow: hidden; color: ${text};\n }\n .wc-header {\n display: flex; align-items: center; justify-content: space-between;\n padding: 20px 24px 16px; border-bottom: 1px solid ${border};\n }\n .wc-title { font-size: 18px; font-weight: 600; margin: 0; }\n .wc-close {\n background: none; border: none; cursor: pointer;\n font-size: 20px; color: ${textSecondary}; padding: 4px 8px;\n border-radius: 8px;\n }\n .wc-close:hover { background: ${bgSecondary}; }\n .wc-body { padding: 16px 24px 24px; }\n .wc-wallet-list { list-style: none; margin: 0; padding: 0; }\n .wc-wallet-item {\n display: flex; align-items: center; gap: 12px;\n padding: 12px 16px; border-radius: 12px; cursor: pointer;\n border: 1px solid ${border}; margin-bottom: 8px;\n transition: background 0.15s;\n }\n .wc-wallet-item:hover { background: ${hover}; }\n .wc-wallet-icon {\n width: 40px; height: 40px; border-radius: 10px;\n object-fit: cover; flex-shrink: 0;\n }\n .wc-wallet-icon-placeholder {\n width: 40px; height: 40px; border-radius: 10px;\n background: ${primary}; display: flex; align-items: center;\n justify-content: center; color: #fff; font-weight: 700;\n font-size: 16px; flex-shrink: 0;\n }\n .wc-wallet-name { font-size: 15px; font-weight: 500; }\n .wc-wallet-desc { font-size: 12px; color: ${textSecondary}; margin-top: 2px; }\n\n /* Connect screen (after wallet selected) */\n .wc-tabs {\n display: flex; gap: 0; margin-bottom: 20px;\n border: 1px solid ${border}; border-radius: 10px; overflow: hidden;\n }\n .wc-tab {\n flex: 1; padding: 10px; text-align: center; cursor: pointer;\n font-size: 13px; font-weight: 500; background: ${bgSecondary};\n border: none; color: ${textSecondary}; transition: all 0.15s;\n }\n .wc-tab.active { background: ${primary}; color: #fff; }\n .wc-deeplink-btn {\n display: block; width: 100%; padding: 14px; border: none;\n border-radius: 12px; background: ${primary}; color: #fff;\n font-size: 15px; font-weight: 600; cursor: pointer;\n text-align: center; text-decoration: none;\n }\n .wc-deeplink-btn:hover { opacity: 0.9; }\n .wc-qr-container {\n display: flex; flex-direction: column; align-items: center; gap: 12px;\n }\n .wc-qr-canvas {\n border-radius: 12px; padding: 16px; background: #fff;\n }\n .wc-qr-hint { font-size: 12px; color: ${textSecondary}; text-align: center; }\n .wc-status {\n display: flex; align-items: center; justify-content: center;\n gap: 8px; padding: 16px 0 0; font-size: 13px; color: ${textSecondary};\n }\n .wc-spinner {\n width: 16px; height: 16px; border: 2px solid ${border};\n border-top-color: ${primary}; border-radius: 50%;\n animation: wc-spin 0.8s linear infinite;\n }\n @keyframes wc-spin { to { transform: rotate(360deg); } }\n .wc-back {\n background: none; border: none; cursor: pointer;\n font-size: 14px; color: ${primary}; padding: 0;\n display: flex; align-items: center; gap: 4px;\n }\n .wc-back:hover { text-decoration: underline; }\n `;\n}\n\n// ── QR Code (minimal inline generator, no external dep) ──\n\nfunction generateQRDataUrl(text: string, size = 200): string {\n // Encode as a simple QR placeholder using a public API\n // In production, replace with a bundled QR lib like 'qrcode'\n return `https://api.qrserver.com/v1/create-qr-code/?size=${size}x${size}&data=${encodeURIComponent(text)}`;\n}\n\n// ── Modal builder ──\n\nexport class Modal {\n private overlay: HTMLDivElement | null = null;\n private theme: 'light' | 'dark';\n private onClose: () => void;\n\n constructor(theme: 'light' | 'dark', onClose: () => void) {\n this.theme = theme;\n this.onClose = onClose;\n }\n\n // Show wallet picker (multiple wallets)\n showWalletPicker(\n wallets: WalletMeta[],\n onSelect: (wallet: WalletMeta) => void,\n ): void {\n const walletListHtml = wallets\n .map(\n (w) => `\n <li class=\"wc-wallet-item\" data-wallet-id=\"${w.walletId}\">\n ${\n w.icon\n ? `<img class=\"wc-wallet-icon\" src=\"${w.icon}\" alt=\"${w.name}\" />`\n : `<div class=\"wc-wallet-icon-placeholder\">${w.name.charAt(0).toUpperCase()}</div>`\n }\n <div>\n <div class=\"wc-wallet-name\">${w.name}</div>\n ${w.description ? `<div class=\"wc-wallet-desc\">${w.description}</div>` : ''}\n </div>\n </li>`,\n )\n .join('');\n\n const html = `\n <div class=\"wc-header\">\n <h3 class=\"wc-title\">Connect Wallet</h3>\n <button class=\"wc-close\" data-action=\"close\">&times;</button>\n </div>\n <div class=\"wc-body\">\n <ul class=\"wc-wallet-list\">${walletListHtml}</ul>\n </div>\n `;\n\n this.render(html);\n\n // Bind wallet click\n wallets.forEach((w) => {\n const el = this.overlay?.querySelector(\n `[data-wallet-id=\"${w.walletId}\"]`,\n );\n el?.addEventListener('click', () => onSelect(w));\n });\n }\n\n // Show connect screen (deeplink + QR)\n showConnect(\n wallet: WalletMeta,\n deeplink: string,\n showBack: boolean,\n onBack?: () => void,\n ): void {\n const qrUrl = generateQRDataUrl(deeplink);\n\n const html = `\n <div class=\"wc-header\">\n <div style=\"display:flex;align-items:center;gap:8px;\">\n ${\n showBack\n ? '<button class=\"wc-back\" data-action=\"back\">&#8592;</button>'\n : ''\n }\n <h3 class=\"wc-title\">Connect ${wallet.name}</h3>\n </div>\n <button class=\"wc-close\" data-action=\"close\">&times;</button>\n </div>\n <div class=\"wc-body\">\n <div class=\"wc-tabs\">\n <button class=\"wc-tab active\" data-tab=\"mobile\">Mobile</button>\n <button class=\"wc-tab\" data-tab=\"qr\">QR Code</button>\n </div>\n <div data-panel=\"mobile\">\n <a class=\"wc-deeplink-btn\" href=\"${deeplink}\" target=\"_blank\">\n Open in Telegram\n </a>\n </div>\n <div data-panel=\"qr\" style=\"display:none;\">\n <div class=\"wc-qr-container\">\n <img class=\"wc-qr-canvas\" src=\"${qrUrl}\" width=\"200\" height=\"200\" alt=\"QR Code\" />\n <div class=\"wc-qr-hint\">Scan with your phone or from wallet app</div>\n </div>\n </div>\n <div class=\"wc-status\">\n <div class=\"wc-spinner\"></div>\n <span>Waiting for confirmation...</span>\n </div>\n </div>\n `;\n\n this.render(html);\n\n // Tab switching\n const tabs = this.overlay?.querySelectorAll('.wc-tab');\n const panels = this.overlay?.querySelectorAll('[data-panel]');\n tabs?.forEach((tab) => {\n tab.addEventListener('click', () => {\n const target = (tab as HTMLElement).dataset.tab;\n tabs.forEach((t) => t.classList.remove('active'));\n tab.classList.add('active');\n panels?.forEach((p) => {\n (p as HTMLElement).style.display =\n (p as HTMLElement).dataset.panel === target ? 'block' : 'none';\n });\n });\n });\n\n // Back button\n if (showBack && onBack) {\n this.overlay\n ?.querySelector('[data-action=\"back\"]')\n ?.addEventListener('click', onBack);\n }\n }\n\n // Update status text\n updateStatus(text: string, showSpinner = true): void {\n const statusEl = this.overlay?.querySelector('.wc-status');\n if (statusEl) {\n statusEl.innerHTML = `\n ${showSpinner ? '<div class=\"wc-spinner\"></div>' : ''}\n <span>${text}</span>\n `;\n }\n }\n\n private render(innerHtml: string): void {\n this.destroy();\n\n const overlay = document.createElement('div');\n overlay.id = MODAL_ID;\n overlay.innerHTML = `\n <style>${getStyles(this.theme)}</style>\n <div class=\"wc-overlay\">\n <div class=\"wc-modal\">${innerHtml}</div>\n </div>\n `;\n\n document.body.appendChild(overlay);\n this.overlay = overlay;\n\n // Close button\n this.overlay\n .querySelector('[data-action=\"close\"]')\n ?.addEventListener('click', () => {\n this.onClose();\n this.destroy();\n });\n\n // Click overlay to close\n this.overlay\n .querySelector('.wc-overlay')\n ?.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).classList.contains('wc-overlay')) {\n this.onClose();\n this.destroy();\n }\n });\n }\n\n destroy(): void {\n const existing = document.getElementById(MODAL_ID);\n if (existing) {\n existing.remove();\n }\n this.overlay = null;\n }\n}\n","import type {\n WalletConnectConfig,\n WalletMeta,\n ConnectResult,\n InitSessionResponse,\n WalletConnectEventType,\n WalletConnectEventCallback,\n} from './types';\nimport { WsTransport, PollingTransport } from './transport';\nimport { Modal } from './modal';\n\nconst STORAGE_KEY_PREFIX = '__wc_session_';\n\nexport class BaseWalletConnect {\n protected config: Required<\n Pick<WalletConnectConfig, 'appId' | 'registryUrl' | 'theme'>\n > &\n Pick<WalletConnectConfig, 'walletId'>;\n\n private listeners: Map<WalletConnectEventType, Set<WalletConnectEventCallback>> = new Map();\n private modal: Modal | null = null;\n private wsTransport: WsTransport | null = null;\n private pollingTransport: PollingTransport | null = null;\n private currentResult: ConnectResult | null = null;\n\n constructor(config: WalletConnectConfig) {\n this.config = {\n appId: config.appId,\n registryUrl: config.registryUrl,\n walletId: config.walletId,\n theme: config.theme || 'light',\n };\n\n this.restoreSession();\n }\n\n // ── Public API ──\n\n async connect(): Promise<ConnectResult> {\n if (this.currentResult) {\n return this.currentResult;\n }\n\n const wallets = await this.fetchWallets();\n const filtered = this.filterWallets(wallets);\n\n if (filtered.length === 0) {\n throw new Error('No supported wallets available');\n }\n\n return new Promise<ConnectResult>((resolve, reject) => {\n const onClose = () => {\n this.cleanup();\n reject(new Error('User closed modal'));\n };\n\n this.modal = new Modal(this.config.theme, onClose);\n\n if (filtered.length === 1) {\n this.startConnect(filtered[0], false, resolve, reject);\n } else {\n this.modal.showWalletPicker(filtered, (wallet) => {\n this.startConnect(wallet, true, resolve, reject);\n });\n }\n });\n }\n\n disconnect(): void {\n this.currentResult = null;\n this.removeStoredSession();\n this.cleanup();\n this.emit('disconnect');\n }\n\n isConnected(): boolean {\n return this.currentResult !== null;\n }\n\n getWallet(): ConnectResult | null {\n return this.currentResult;\n }\n\n on(event: WalletConnectEventType, cb: WalletConnectEventCallback): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(cb);\n }\n\n off(event: WalletConnectEventType, cb: WalletConnectEventCallback): void {\n this.listeners.get(event)?.delete(cb);\n }\n\n // ── Internal ──\n\n private get storageKey(): string {\n const walletId = this.config.walletId;\n const suffix = Array.isArray(walletId)\n ? walletId.sort().join('_')\n : walletId || 'all';\n return `${STORAGE_KEY_PREFIX}${suffix}__`;\n }\n\n private async fetchWallets(): Promise<WalletMeta[]> {\n const url = this.config.registryUrl.replace(/\\/$/, '');\n const res = await fetch(url);\n if (!res.ok) throw new Error('Failed to fetch wallets');\n return res.json();\n }\n\n private filterWallets(wallets: WalletMeta[]): WalletMeta[] {\n if (!this.config.walletId) return wallets;\n\n const ids = Array.isArray(this.config.walletId)\n ? this.config.walletId\n : [this.config.walletId];\n\n return wallets.filter((w) => ids.includes(w.walletId));\n }\n\n private async startConnect(\n wallet: WalletMeta,\n showBack: boolean,\n resolve: (result: ConnectResult) => void,\n reject: (error: Error) => void,\n ): Promise<void> {\n try {\n const session = await this.initSession(wallet);\n\n this.modal?.showConnect(wallet, session.deeplink, showBack, () => {\n this.cleanup();\n this.connect().then(resolve).catch(reject);\n });\n\n this.listenForConfirmation(\n wallet.apiUrl,\n session.sessionToken,\n (result) => {\n this.currentResult = result;\n this.storeSession(result);\n this.modal?.destroy();\n this.modal = null;\n this.emit('connect', result);\n resolve(result);\n },\n () => {\n this.modal?.updateStatus('Connection rejected', false);\n setTimeout(() => {\n this.modal?.destroy();\n this.modal = null;\n reject(new Error('Connection rejected by user'));\n }, 1500);\n },\n () => {\n this.modal?.updateStatus('Session expired', false);\n this.emit('session_expired');\n setTimeout(() => {\n this.modal?.destroy();\n this.modal = null;\n reject(new Error('Session expired'));\n }, 1500);\n },\n );\n } catch (err) {\n this.modal?.destroy();\n this.modal = null;\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n }\n\n private async initSession(wallet: WalletMeta): Promise<InitSessionResponse> {\n const baseUrl = wallet.apiUrl.replace(/\\/$/, '');\n const res = await fetch(`${baseUrl}/connect/init`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n appId: this.config.appId,\n walletId: wallet.walletId,\n origin: typeof window !== 'undefined' ? window.location.origin : '',\n }),\n });\n if (!res.ok) throw new Error('Failed to init session');\n return res.json();\n }\n\n private listenForConfirmation(\n apiUrl: string,\n sessionToken: string,\n onConfirmed: (result: ConnectResult) => void,\n onRejected: () => void,\n onExpired: () => void,\n ): void {\n const onError = () => {\n this.pollingTransport = new PollingTransport(\n apiUrl,\n sessionToken,\n onConfirmed,\n onRejected,\n onExpired,\n (msg) => this.emit('error', msg),\n );\n this.pollingTransport.start();\n };\n\n this.wsTransport = new WsTransport(\n apiUrl,\n sessionToken,\n onConfirmed,\n onRejected,\n onExpired,\n onError,\n );\n this.wsTransport.connect();\n }\n\n private cleanup(): void {\n this.wsTransport?.close();\n this.wsTransport = null;\n this.pollingTransport?.stop();\n this.pollingTransport = null;\n this.modal?.destroy();\n this.modal = null;\n }\n\n private emit(event: WalletConnectEventType, data?: any): void {\n this.listeners.get(event)?.forEach((cb) => cb(data));\n }\n\n // ── Persistence ──\n\n private storeSession(result: ConnectResult): void {\n try {\n localStorage.setItem(this.storageKey, JSON.stringify(result));\n } catch {\n // localStorage unavailable\n }\n }\n\n private restoreSession(): void {\n try {\n const stored = localStorage.getItem(this.storageKey);\n if (stored) {\n this.currentResult = JSON.parse(stored);\n }\n } catch {\n // ignore\n }\n }\n\n private removeStoredSession(): void {\n try {\n localStorage.removeItem(this.storageKey);\n } catch {\n // ignore\n }\n }\n}\n","import { BaseWalletConnect } from './client';\nimport type { WalletConnectConfig } from './types';\n\nexport class OneDollarConnect extends BaseWalletConnect {\n constructor(config: Omit<WalletConnectConfig, 'walletId'>) {\n super({ ...config, walletId: 'onedollar' });\n }\n}\n","import { BaseWalletConnect } from './client';\nimport type { WalletConnectConfig } from './types';\n\nexport class TonPassConnect extends BaseWalletConnect {\n constructor(config: Omit<WalletConnectConfig, 'walletId'>) {\n super({ ...config, walletId: 'tonpass' });\n }\n}\n"],"names":["WsTransport","constructor","apiUrl","sessionToken","onConfirmed","onRejected","onExpired","onError","this","ws","reconnectTimer","closed","connect","replace","connectSocketIO","baseUrl","fetch","then","res","text","body","jsonStr","sid","JSON","parse","wsUrl","WebSocket","onopen","send","onmessage","event","msg","data","startsWith","payload","slice","eventName","handleEvent","onclose","scheduleReconnect","onerror","catch","close","setTimeout","clearTimeout","PollingTransport","timer","stopped","start","poll","setInterval","ok","json","status","wallets","user","stop","clearInterval","MODAL_ID","Modal","theme","onClose","overlay","showWalletPicker","onSelect","html","map","w","walletId","icon","name","charAt","toUpperCase","description","join","render","forEach","el","querySelector","addEventListener","showConnect","wallet","deeplink","showBack","onBack","qrUrl","size","encodeURIComponent","generateQRDataUrl","tabs","querySelectorAll","panels","tab","target","dataset","t","classList","remove","add","p","style","display","panel","updateStatus","showSpinner","statusEl","innerHTML","innerHtml","destroy","document","createElement","id","bgSecondary","textSecondary","border","primary","getStyles","appendChild","e","contains","existing","getElementById","BaseWalletConnect","config","listeners","Map","modal","wsTransport","pollingTransport","currentResult","appId","registryUrl","restoreSession","fetchWallets","filtered","filterWallets","length","Error","Promise","resolve","reject","cleanup","startConnect","disconnect","removeStoredSession","emit","isConnected","getWallet","on","cb","has","set","Set","get","off","delete","storageKey","Array","isArray","sort","url","ids","filter","includes","session","initSession","listenForConfirmation","result","storeSession","err","String","method","headers","stringify","origin","window","location","localStorage","setItem","stored","getItem","removeItem","super"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { BaseWalletConnect } from './client';
2
+ export { TonPassConnect } from './tonpass';
3
+ export { OneDollarConnect } from './onedollar';
4
+ export type { WalletConnectConfig, WalletMeta, WalletInfo, ConnectResult, WalletConnectEventType, WalletConnectEventCallback, } from './types';
@@ -0,0 +1,2 @@
1
+ class e{constructor(e,t,n,s,i,o){this.apiUrl=e,this.sessionToken=t,this.onConfirmed=n,this.onRejected=s,this.onExpired=i,this.onError=o,this.ws=null,this.reconnectTimer=null,this.closed=!1}connect(){this.closed=!1;this.apiUrl.replace(/^http/,"ws").replace(/\/$/,"");this.sessionToken;try{this.connectSocketIO()}catch{this.onError("WebSocket connection failed")}}connectSocketIO(){const e=this.apiUrl.replace(/\/$/,"");fetch(`${e}/walletconnect/?EIO=4&transport=polling`).then(e=>e.text()).then(t=>{const n=t.replace(/^\d+/,""),s=JSON.parse(n).sid,i=`${e.replace(/^http/,"ws")}/walletconnect/?EIO=4&transport=websocket&sid=${s}`;this.ws=new WebSocket(i),this.ws.onopen=()=>{this.ws.send("2probe")},this.ws.onmessage=e=>{const t=e.data;if("3probe"!==t)if(t.startsWith("42"))try{const e=JSON.parse(t.slice(2)),[n,s]=e;this.handleEvent(n,s)}catch{}else"2"===t&&this.ws.send("3");else this.ws.send("5")},this.ws.onclose=()=>{this.closed||this.scheduleReconnect()},this.ws.onerror=()=>{this.closed||this.scheduleReconnect()}}).catch(()=>{this.closed||this.scheduleReconnect()})}handleEvent(e,t){switch(e){case"session_confirmed":this.onConfirmed(t),this.close();break;case"session_rejected":this.onRejected(),this.close();break;case"session_expired":this.onExpired(),this.close()}}scheduleReconnect(){this.closed||this.reconnectTimer||(this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.connectSocketIO()},3e3))}close(){this.closed=!0,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.ws&&(this.ws.close(),this.ws=null)}}class t{constructor(e,t,n,s,i,o){this.apiUrl=e,this.sessionToken=t,this.onConfirmed=n,this.onRejected=s,this.onExpired=i,this.onError=o,this.timer=null,this.stopped=!1}start(){this.stopped=!1,this.poll(),this.timer=setInterval(()=>this.poll(),2e3)}async poll(){if(!this.stopped)try{const e=this.apiUrl.replace(/\/$/,""),t=await fetch(`${e}/connect/status?token=${this.sessionToken}`);if(!t.ok)return;const n=await t.json();switch(n.status){case"CONFIRMED":this.onConfirmed({wallets:n.wallets,user:n.user}),this.stop();break;case"REJECTED":this.onRejected(),this.stop();break;case"EXPIRED":this.onExpired(),this.stop()}}catch{}}stop(){this.stopped=!0,this.timer&&(clearInterval(this.timer),this.timer=null)}}const n="__wc_modal__";class s{constructor(e,t){this.overlay=null,this.theme=e,this.onClose=t}showWalletPicker(e,t){const n=`\n <div class="wc-header">\n <h3 class="wc-title">Connect Wallet</h3>\n <button class="wc-close" data-action="close">&times;</button>\n </div>\n <div class="wc-body">\n <ul class="wc-wallet-list">${e.map(e=>`\n <li class="wc-wallet-item" data-wallet-id="${e.walletId}">\n ${e.icon?`<img class="wc-wallet-icon" src="${e.icon}" alt="${e.name}" />`:`<div class="wc-wallet-icon-placeholder">${e.name.charAt(0).toUpperCase()}</div>`}\n <div>\n <div class="wc-wallet-name">${e.name}</div>\n ${e.description?`<div class="wc-wallet-desc">${e.description}</div>`:""}\n </div>\n </li>`).join("")}</ul>\n </div>\n `;this.render(n),e.forEach(e=>{const n=this.overlay?.querySelector(`[data-wallet-id="${e.walletId}"]`);n?.addEventListener("click",()=>t(e))})}showConnect(e,t,n,s){const i=function(e,t=200){return`https://api.qrserver.com/v1/create-qr-code/?size=${t}x${t}&data=${encodeURIComponent(e)}`}(t),o=`\n <div class="wc-header">\n <div style="display:flex;align-items:center;gap:8px;">\n ${n?'<button class="wc-back" data-action="back">&#8592;</button>':""}\n <h3 class="wc-title">Connect ${e.name}</h3>\n </div>\n <button class="wc-close" data-action="close">&times;</button>\n </div>\n <div class="wc-body">\n <div class="wc-tabs">\n <button class="wc-tab active" data-tab="mobile">Mobile</button>\n <button class="wc-tab" data-tab="qr">QR Code</button>\n </div>\n <div data-panel="mobile">\n <a class="wc-deeplink-btn" href="${t}" target="_blank">\n Open in Telegram\n </a>\n </div>\n <div data-panel="qr" style="display:none;">\n <div class="wc-qr-container">\n <img class="wc-qr-canvas" src="${i}" width="200" height="200" alt="QR Code" />\n <div class="wc-qr-hint">Scan with your phone or from wallet app</div>\n </div>\n </div>\n <div class="wc-status">\n <div class="wc-spinner"></div>\n <span>Waiting for confirmation...</span>\n </div>\n </div>\n `;this.render(o);const r=this.overlay?.querySelectorAll(".wc-tab"),a=this.overlay?.querySelectorAll("[data-panel]");r?.forEach(e=>{e.addEventListener("click",()=>{const t=e.dataset.tab;r.forEach(e=>e.classList.remove("active")),e.classList.add("active"),a?.forEach(e=>{e.style.display=e.dataset.panel===t?"block":"none"})})}),n&&s&&this.overlay?.querySelector('[data-action="back"]')?.addEventListener("click",s)}updateStatus(e,t=!0){const n=this.overlay?.querySelector(".wc-status");n&&(n.innerHTML=`\n ${t?'<div class="wc-spinner"></div>':""}\n <span>${e}</span>\n `)}render(e){this.destroy();const t=document.createElement("div");t.id=n,t.innerHTML=`\n <style>${function(e){const t="dark"===e?"#16213e":"#f5f5f5",n="dark"===e?"#a0a0a0":"#666666",s="dark"===e?"#2a2a4a":"#e0e0e0",i="#3b82f6";return`\n .wc-overlay {\n position: fixed; inset: 0; z-index: 99999;\n background: rgba(0,0,0,0.5); display: flex;\n align-items: center; justify-content: center;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n .wc-modal {\n background: ${"dark"===e?"#1a1a2e":"#ffffff"}; border-radius: 16px; width: 380px;\n max-width: 90vw; box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n overflow: hidden; color: ${"dark"===e?"#e0e0e0":"#1a1a1a"};\n }\n .wc-header {\n display: flex; align-items: center; justify-content: space-between;\n padding: 20px 24px 16px; border-bottom: 1px solid ${s};\n }\n .wc-title { font-size: 18px; font-weight: 600; margin: 0; }\n .wc-close {\n background: none; border: none; cursor: pointer;\n font-size: 20px; color: ${n}; padding: 4px 8px;\n border-radius: 8px;\n }\n .wc-close:hover { background: ${t}; }\n .wc-body { padding: 16px 24px 24px; }\n .wc-wallet-list { list-style: none; margin: 0; padding: 0; }\n .wc-wallet-item {\n display: flex; align-items: center; gap: 12px;\n padding: 12px 16px; border-radius: 12px; cursor: pointer;\n border: 1px solid ${s}; margin-bottom: 8px;\n transition: background 0.15s;\n }\n .wc-wallet-item:hover { background: ${"dark"===e?"#0f3460":"#e8f0fe"}; }\n .wc-wallet-icon {\n width: 40px; height: 40px; border-radius: 10px;\n object-fit: cover; flex-shrink: 0;\n }\n .wc-wallet-icon-placeholder {\n width: 40px; height: 40px; border-radius: 10px;\n background: ${i}; display: flex; align-items: center;\n justify-content: center; color: #fff; font-weight: 700;\n font-size: 16px; flex-shrink: 0;\n }\n .wc-wallet-name { font-size: 15px; font-weight: 500; }\n .wc-wallet-desc { font-size: 12px; color: ${n}; margin-top: 2px; }\n\n /* Connect screen (after wallet selected) */\n .wc-tabs {\n display: flex; gap: 0; margin-bottom: 20px;\n border: 1px solid ${s}; border-radius: 10px; overflow: hidden;\n }\n .wc-tab {\n flex: 1; padding: 10px; text-align: center; cursor: pointer;\n font-size: 13px; font-weight: 500; background: ${t};\n border: none; color: ${n}; transition: all 0.15s;\n }\n .wc-tab.active { background: ${i}; color: #fff; }\n .wc-deeplink-btn {\n display: block; width: 100%; padding: 14px; border: none;\n border-radius: 12px; background: ${i}; color: #fff;\n font-size: 15px; font-weight: 600; cursor: pointer;\n text-align: center; text-decoration: none;\n }\n .wc-deeplink-btn:hover { opacity: 0.9; }\n .wc-qr-container {\n display: flex; flex-direction: column; align-items: center; gap: 12px;\n }\n .wc-qr-canvas {\n border-radius: 12px; padding: 16px; background: #fff;\n }\n .wc-qr-hint { font-size: 12px; color: ${n}; text-align: center; }\n .wc-status {\n display: flex; align-items: center; justify-content: center;\n gap: 8px; padding: 16px 0 0; font-size: 13px; color: ${n};\n }\n .wc-spinner {\n width: 16px; height: 16px; border: 2px solid ${s};\n border-top-color: ${i}; border-radius: 50%;\n animation: wc-spin 0.8s linear infinite;\n }\n @keyframes wc-spin { to { transform: rotate(360deg); } }\n .wc-back {\n background: none; border: none; cursor: pointer;\n font-size: 14px; color: ${i}; padding: 0;\n display: flex; align-items: center; gap: 4px;\n }\n .wc-back:hover { text-decoration: underline; }\n `}(this.theme)}</style>\n <div class="wc-overlay">\n <div class="wc-modal">${e}</div>\n </div>\n `,document.body.appendChild(t),this.overlay=t,this.overlay.querySelector('[data-action="close"]')?.addEventListener("click",()=>{this.onClose(),this.destroy()}),this.overlay.querySelector(".wc-overlay")?.addEventListener("click",e=>{e.target.classList.contains("wc-overlay")&&(this.onClose(),this.destroy())})}destroy(){const e=document.getElementById(n);e&&e.remove(),this.overlay=null}}class i{constructor(e){this.listeners=new Map,this.modal=null,this.wsTransport=null,this.pollingTransport=null,this.currentResult=null,this.config={appId:e.appId,registryUrl:e.registryUrl,walletId:e.walletId,theme:e.theme||"light"},this.restoreSession()}async connect(){if(this.currentResult)return this.currentResult;const e=await this.fetchWallets(),t=this.filterWallets(e);if(0===t.length)throw new Error("No supported wallets available");return new Promise((e,n)=>{this.modal=new s(this.config.theme,()=>{this.cleanup(),n(new Error("User closed modal"))}),1===t.length?this.startConnect(t[0],!1,e,n):this.modal.showWalletPicker(t,t=>{this.startConnect(t,!0,e,n)})})}disconnect(){this.currentResult=null,this.removeStoredSession(),this.cleanup(),this.emit("disconnect")}isConnected(){return null!==this.currentResult}getWallet(){return this.currentResult}on(e,t){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t)}off(e,t){this.listeners.get(e)?.delete(t)}get storageKey(){const e=this.config.walletId;return`__wc_session_${Array.isArray(e)?e.sort().join("_"):e||"all"}__`}async fetchWallets(){const e=this.config.registryUrl.replace(/\/$/,""),t=await fetch(e);if(!t.ok)throw new Error("Failed to fetch wallets");return t.json()}filterWallets(e){if(!this.config.walletId)return e;const t=Array.isArray(this.config.walletId)?this.config.walletId:[this.config.walletId];return e.filter(e=>t.includes(e.walletId))}async startConnect(e,t,n,s){try{const i=await this.initSession(e);this.modal?.showConnect(e,i.deeplink,t,()=>{this.cleanup(),this.connect().then(n).catch(s)}),this.listenForConfirmation(e.apiUrl,i.sessionToken,e=>{this.currentResult=e,this.storeSession(e),this.modal?.destroy(),this.modal=null,this.emit("connect",e),n(e)},()=>{this.modal?.updateStatus("Connection rejected",!1),setTimeout(()=>{this.modal?.destroy(),this.modal=null,s(new Error("Connection rejected by user"))},1500)},()=>{this.modal?.updateStatus("Session expired",!1),this.emit("session_expired"),setTimeout(()=>{this.modal?.destroy(),this.modal=null,s(new Error("Session expired"))},1500)})}catch(e){this.modal?.destroy(),this.modal=null,s(e instanceof Error?e:new Error(String(e)))}}async initSession(e){const t=e.apiUrl.replace(/\/$/,""),n=await fetch(`${t}/connect/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({appId:this.config.appId,walletId:e.walletId,origin:"undefined"!=typeof window?window.location.origin:""})});if(!n.ok)throw new Error("Failed to init session");return n.json()}listenForConfirmation(n,s,i,o,r){this.wsTransport=new e(n,s,i,o,r,()=>{this.pollingTransport=new t(n,s,i,o,r,e=>this.emit("error",e)),this.pollingTransport.start()}),this.wsTransport.connect()}cleanup(){this.wsTransport?.close(),this.wsTransport=null,this.pollingTransport?.stop(),this.pollingTransport=null,this.modal?.destroy(),this.modal=null}emit(e,t){this.listeners.get(e)?.forEach(e=>e(t))}storeSession(e){try{localStorage.setItem(this.storageKey,JSON.stringify(e))}catch{}}restoreSession(){try{const e=localStorage.getItem(this.storageKey);e&&(this.currentResult=JSON.parse(e))}catch{}}removeStoredSession(){try{localStorage.removeItem(this.storageKey)}catch{}}}class o extends i{constructor(e){super({...e,walletId:"tonpass"})}}class r extends i{constructor(e){super({...e,walletId:"onedollar"})}}export{i as BaseWalletConnect,r as OneDollarConnect,o as TonPassConnect};
2
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../../transport.ts","../../modal.ts","../../client.ts","../../tonpass.ts","../../onedollar.ts"],"sourcesContent":["import type { ConnectResult } from './types';\n\ntype TransportCallback = (data: ConnectResult) => void;\ntype TransportErrorCallback = (error: string) => void;\n\n// ── WebSocket Transport ──\n\nexport class WsTransport {\n private ws: WebSocket | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private closed = false;\n\n constructor(\n private apiUrl: string,\n private sessionToken: string,\n private onConfirmed: TransportCallback,\n private onRejected: () => void,\n private onExpired: () => void,\n private onError: TransportErrorCallback,\n ) {}\n\n connect(): void {\n this.closed = false;\n const wsUrl = this.apiUrl\n .replace(/^http/, 'ws')\n .replace(/\\/$/, '');\n const url = `${wsUrl}/walletconnect?sessionToken=${this.sessionToken}`;\n\n try {\n // Socket.IO uses polling upgrade — use native WS for simplicity in SDK\n // The BE gateway uses socket.io, so we connect via socket.io protocol\n this.connectSocketIO();\n } catch {\n this.onError('WebSocket connection failed');\n }\n }\n\n private connectSocketIO(): void {\n const baseUrl = this.apiUrl.replace(/\\/$/, '');\n\n // Socket.IO handshake: first GET for sid, then upgrade to WS\n const pollingUrl = `${baseUrl}/walletconnect/?EIO=4&transport=polling`;\n\n fetch(pollingUrl)\n .then((res) => res.text())\n .then((body) => {\n // Socket.IO response format: \"0{...json...}\"\n const jsonStr = body.replace(/^\\d+/, '');\n const handshake = JSON.parse(jsonStr);\n const sid = handshake.sid;\n\n const wsBase = baseUrl.replace(/^http/, 'ws');\n const wsUrl = `${wsBase}/walletconnect/?EIO=4&transport=websocket&sid=${sid}`;\n\n this.ws = new WebSocket(wsUrl);\n\n this.ws.onopen = () => {\n // Socket.IO upgrade probe\n this.ws!.send('2probe');\n };\n\n this.ws.onmessage = (event) => {\n const msg = event.data as string;\n\n if (msg === '3probe') {\n // Upgrade confirmed, send upgrade packet + join room\n this.ws!.send('5');\n // Emit connect event with sessionToken as query (already in URL)\n // Socket.IO auto-joins based on handshake query\n return;\n }\n\n // Handle Socket.IO event messages: 42[\"event_name\", {...data}]\n if (msg.startsWith('42')) {\n try {\n const payload = JSON.parse(msg.slice(2));\n const [eventName, data] = payload;\n this.handleEvent(eventName, data);\n } catch {\n // ignore malformed\n }\n return;\n }\n\n // Ping from server\n if (msg === '2') {\n this.ws!.send('3');\n }\n };\n\n this.ws.onclose = () => {\n if (!this.closed) {\n this.scheduleReconnect();\n }\n };\n\n this.ws.onerror = () => {\n if (!this.closed) {\n this.scheduleReconnect();\n }\n };\n })\n .catch(() => {\n if (!this.closed) {\n this.scheduleReconnect();\n }\n });\n }\n\n private handleEvent(eventName: string, data: any): void {\n switch (eventName) {\n case 'session_confirmed':\n this.onConfirmed(data);\n this.close();\n break;\n case 'session_rejected':\n this.onRejected();\n this.close();\n break;\n case 'session_expired':\n this.onExpired();\n this.close();\n break;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.closed || this.reconnectTimer) return;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connectSocketIO();\n }, 3000);\n }\n\n close(): void {\n this.closed = true;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n }\n}\n\n// ── Long-Poll Fallback ──\n\nexport class PollingTransport {\n private timer: ReturnType<typeof setInterval> | null = null;\n private stopped = false;\n\n constructor(\n private apiUrl: string,\n private sessionToken: string,\n private onConfirmed: TransportCallback,\n private onRejected: () => void,\n private onExpired: () => void,\n private onError: TransportErrorCallback,\n ) {}\n\n start(): void {\n this.stopped = false;\n this.poll();\n this.timer = setInterval(() => this.poll(), 2000);\n }\n\n private async poll(): Promise<void> {\n if (this.stopped) return;\n\n try {\n const baseUrl = this.apiUrl.replace(/\\/$/, '');\n const res = await fetch(\n `${baseUrl}/connect/status?token=${this.sessionToken}`,\n );\n if (!res.ok) return;\n\n const data = await res.json();\n\n switch (data.status) {\n case 'CONFIRMED':\n this.onConfirmed({ wallets: data.wallets, user: data.user });\n this.stop();\n break;\n case 'REJECTED':\n this.onRejected();\n this.stop();\n break;\n case 'EXPIRED':\n this.onExpired();\n this.stop();\n break;\n }\n } catch {\n // silently retry next interval\n }\n }\n\n stop(): void {\n this.stopped = true;\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n}\n","import type { WalletMeta } from './types';\n\nconst MODAL_ID = '__wc_modal__';\n\n// ── Styles (scoped, no conflict with host) ──\n\nfunction getStyles(theme: 'light' | 'dark'): string {\n const bg = theme === 'dark' ? '#1a1a2e' : '#ffffff';\n const bgSecondary = theme === 'dark' ? '#16213e' : '#f5f5f5';\n const text = theme === 'dark' ? '#e0e0e0' : '#1a1a1a';\n const textSecondary = theme === 'dark' ? '#a0a0a0' : '#666666';\n const border = theme === 'dark' ? '#2a2a4a' : '#e0e0e0';\n const primary = '#3b82f6';\n const hover = theme === 'dark' ? '#0f3460' : '#e8f0fe';\n\n return `\n .wc-overlay {\n position: fixed; inset: 0; z-index: 99999;\n background: rgba(0,0,0,0.5); display: flex;\n align-items: center; justify-content: center;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n .wc-modal {\n background: ${bg}; border-radius: 16px; width: 380px;\n max-width: 90vw; box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n overflow: hidden; color: ${text};\n }\n .wc-header {\n display: flex; align-items: center; justify-content: space-between;\n padding: 20px 24px 16px; border-bottom: 1px solid ${border};\n }\n .wc-title { font-size: 18px; font-weight: 600; margin: 0; }\n .wc-close {\n background: none; border: none; cursor: pointer;\n font-size: 20px; color: ${textSecondary}; padding: 4px 8px;\n border-radius: 8px;\n }\n .wc-close:hover { background: ${bgSecondary}; }\n .wc-body { padding: 16px 24px 24px; }\n .wc-wallet-list { list-style: none; margin: 0; padding: 0; }\n .wc-wallet-item {\n display: flex; align-items: center; gap: 12px;\n padding: 12px 16px; border-radius: 12px; cursor: pointer;\n border: 1px solid ${border}; margin-bottom: 8px;\n transition: background 0.15s;\n }\n .wc-wallet-item:hover { background: ${hover}; }\n .wc-wallet-icon {\n width: 40px; height: 40px; border-radius: 10px;\n object-fit: cover; flex-shrink: 0;\n }\n .wc-wallet-icon-placeholder {\n width: 40px; height: 40px; border-radius: 10px;\n background: ${primary}; display: flex; align-items: center;\n justify-content: center; color: #fff; font-weight: 700;\n font-size: 16px; flex-shrink: 0;\n }\n .wc-wallet-name { font-size: 15px; font-weight: 500; }\n .wc-wallet-desc { font-size: 12px; color: ${textSecondary}; margin-top: 2px; }\n\n /* Connect screen (after wallet selected) */\n .wc-tabs {\n display: flex; gap: 0; margin-bottom: 20px;\n border: 1px solid ${border}; border-radius: 10px; overflow: hidden;\n }\n .wc-tab {\n flex: 1; padding: 10px; text-align: center; cursor: pointer;\n font-size: 13px; font-weight: 500; background: ${bgSecondary};\n border: none; color: ${textSecondary}; transition: all 0.15s;\n }\n .wc-tab.active { background: ${primary}; color: #fff; }\n .wc-deeplink-btn {\n display: block; width: 100%; padding: 14px; border: none;\n border-radius: 12px; background: ${primary}; color: #fff;\n font-size: 15px; font-weight: 600; cursor: pointer;\n text-align: center; text-decoration: none;\n }\n .wc-deeplink-btn:hover { opacity: 0.9; }\n .wc-qr-container {\n display: flex; flex-direction: column; align-items: center; gap: 12px;\n }\n .wc-qr-canvas {\n border-radius: 12px; padding: 16px; background: #fff;\n }\n .wc-qr-hint { font-size: 12px; color: ${textSecondary}; text-align: center; }\n .wc-status {\n display: flex; align-items: center; justify-content: center;\n gap: 8px; padding: 16px 0 0; font-size: 13px; color: ${textSecondary};\n }\n .wc-spinner {\n width: 16px; height: 16px; border: 2px solid ${border};\n border-top-color: ${primary}; border-radius: 50%;\n animation: wc-spin 0.8s linear infinite;\n }\n @keyframes wc-spin { to { transform: rotate(360deg); } }\n .wc-back {\n background: none; border: none; cursor: pointer;\n font-size: 14px; color: ${primary}; padding: 0;\n display: flex; align-items: center; gap: 4px;\n }\n .wc-back:hover { text-decoration: underline; }\n `;\n}\n\n// ── QR Code (minimal inline generator, no external dep) ──\n\nfunction generateQRDataUrl(text: string, size = 200): string {\n // Encode as a simple QR placeholder using a public API\n // In production, replace with a bundled QR lib like 'qrcode'\n return `https://api.qrserver.com/v1/create-qr-code/?size=${size}x${size}&data=${encodeURIComponent(text)}`;\n}\n\n// ── Modal builder ──\n\nexport class Modal {\n private overlay: HTMLDivElement | null = null;\n private theme: 'light' | 'dark';\n private onClose: () => void;\n\n constructor(theme: 'light' | 'dark', onClose: () => void) {\n this.theme = theme;\n this.onClose = onClose;\n }\n\n // Show wallet picker (multiple wallets)\n showWalletPicker(\n wallets: WalletMeta[],\n onSelect: (wallet: WalletMeta) => void,\n ): void {\n const walletListHtml = wallets\n .map(\n (w) => `\n <li class=\"wc-wallet-item\" data-wallet-id=\"${w.walletId}\">\n ${\n w.icon\n ? `<img class=\"wc-wallet-icon\" src=\"${w.icon}\" alt=\"${w.name}\" />`\n : `<div class=\"wc-wallet-icon-placeholder\">${w.name.charAt(0).toUpperCase()}</div>`\n }\n <div>\n <div class=\"wc-wallet-name\">${w.name}</div>\n ${w.description ? `<div class=\"wc-wallet-desc\">${w.description}</div>` : ''}\n </div>\n </li>`,\n )\n .join('');\n\n const html = `\n <div class=\"wc-header\">\n <h3 class=\"wc-title\">Connect Wallet</h3>\n <button class=\"wc-close\" data-action=\"close\">&times;</button>\n </div>\n <div class=\"wc-body\">\n <ul class=\"wc-wallet-list\">${walletListHtml}</ul>\n </div>\n `;\n\n this.render(html);\n\n // Bind wallet click\n wallets.forEach((w) => {\n const el = this.overlay?.querySelector(\n `[data-wallet-id=\"${w.walletId}\"]`,\n );\n el?.addEventListener('click', () => onSelect(w));\n });\n }\n\n // Show connect screen (deeplink + QR)\n showConnect(\n wallet: WalletMeta,\n deeplink: string,\n showBack: boolean,\n onBack?: () => void,\n ): void {\n const qrUrl = generateQRDataUrl(deeplink);\n\n const html = `\n <div class=\"wc-header\">\n <div style=\"display:flex;align-items:center;gap:8px;\">\n ${\n showBack\n ? '<button class=\"wc-back\" data-action=\"back\">&#8592;</button>'\n : ''\n }\n <h3 class=\"wc-title\">Connect ${wallet.name}</h3>\n </div>\n <button class=\"wc-close\" data-action=\"close\">&times;</button>\n </div>\n <div class=\"wc-body\">\n <div class=\"wc-tabs\">\n <button class=\"wc-tab active\" data-tab=\"mobile\">Mobile</button>\n <button class=\"wc-tab\" data-tab=\"qr\">QR Code</button>\n </div>\n <div data-panel=\"mobile\">\n <a class=\"wc-deeplink-btn\" href=\"${deeplink}\" target=\"_blank\">\n Open in Telegram\n </a>\n </div>\n <div data-panel=\"qr\" style=\"display:none;\">\n <div class=\"wc-qr-container\">\n <img class=\"wc-qr-canvas\" src=\"${qrUrl}\" width=\"200\" height=\"200\" alt=\"QR Code\" />\n <div class=\"wc-qr-hint\">Scan with your phone or from wallet app</div>\n </div>\n </div>\n <div class=\"wc-status\">\n <div class=\"wc-spinner\"></div>\n <span>Waiting for confirmation...</span>\n </div>\n </div>\n `;\n\n this.render(html);\n\n // Tab switching\n const tabs = this.overlay?.querySelectorAll('.wc-tab');\n const panels = this.overlay?.querySelectorAll('[data-panel]');\n tabs?.forEach((tab) => {\n tab.addEventListener('click', () => {\n const target = (tab as HTMLElement).dataset.tab;\n tabs.forEach((t) => t.classList.remove('active'));\n tab.classList.add('active');\n panels?.forEach((p) => {\n (p as HTMLElement).style.display =\n (p as HTMLElement).dataset.panel === target ? 'block' : 'none';\n });\n });\n });\n\n // Back button\n if (showBack && onBack) {\n this.overlay\n ?.querySelector('[data-action=\"back\"]')\n ?.addEventListener('click', onBack);\n }\n }\n\n // Update status text\n updateStatus(text: string, showSpinner = true): void {\n const statusEl = this.overlay?.querySelector('.wc-status');\n if (statusEl) {\n statusEl.innerHTML = `\n ${showSpinner ? '<div class=\"wc-spinner\"></div>' : ''}\n <span>${text}</span>\n `;\n }\n }\n\n private render(innerHtml: string): void {\n this.destroy();\n\n const overlay = document.createElement('div');\n overlay.id = MODAL_ID;\n overlay.innerHTML = `\n <style>${getStyles(this.theme)}</style>\n <div class=\"wc-overlay\">\n <div class=\"wc-modal\">${innerHtml}</div>\n </div>\n `;\n\n document.body.appendChild(overlay);\n this.overlay = overlay;\n\n // Close button\n this.overlay\n .querySelector('[data-action=\"close\"]')\n ?.addEventListener('click', () => {\n this.onClose();\n this.destroy();\n });\n\n // Click overlay to close\n this.overlay\n .querySelector('.wc-overlay')\n ?.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).classList.contains('wc-overlay')) {\n this.onClose();\n this.destroy();\n }\n });\n }\n\n destroy(): void {\n const existing = document.getElementById(MODAL_ID);\n if (existing) {\n existing.remove();\n }\n this.overlay = null;\n }\n}\n","import type {\n WalletConnectConfig,\n WalletMeta,\n ConnectResult,\n InitSessionResponse,\n WalletConnectEventType,\n WalletConnectEventCallback,\n} from './types';\nimport { WsTransport, PollingTransport } from './transport';\nimport { Modal } from './modal';\n\nconst STORAGE_KEY_PREFIX = '__wc_session_';\n\nexport class BaseWalletConnect {\n protected config: Required<\n Pick<WalletConnectConfig, 'appId' | 'registryUrl' | 'theme'>\n > &\n Pick<WalletConnectConfig, 'walletId'>;\n\n private listeners: Map<WalletConnectEventType, Set<WalletConnectEventCallback>> = new Map();\n private modal: Modal | null = null;\n private wsTransport: WsTransport | null = null;\n private pollingTransport: PollingTransport | null = null;\n private currentResult: ConnectResult | null = null;\n\n constructor(config: WalletConnectConfig) {\n this.config = {\n appId: config.appId,\n registryUrl: config.registryUrl,\n walletId: config.walletId,\n theme: config.theme || 'light',\n };\n\n this.restoreSession();\n }\n\n // ── Public API ──\n\n async connect(): Promise<ConnectResult> {\n if (this.currentResult) {\n return this.currentResult;\n }\n\n const wallets = await this.fetchWallets();\n const filtered = this.filterWallets(wallets);\n\n if (filtered.length === 0) {\n throw new Error('No supported wallets available');\n }\n\n return new Promise<ConnectResult>((resolve, reject) => {\n const onClose = () => {\n this.cleanup();\n reject(new Error('User closed modal'));\n };\n\n this.modal = new Modal(this.config.theme, onClose);\n\n if (filtered.length === 1) {\n this.startConnect(filtered[0], false, resolve, reject);\n } else {\n this.modal.showWalletPicker(filtered, (wallet) => {\n this.startConnect(wallet, true, resolve, reject);\n });\n }\n });\n }\n\n disconnect(): void {\n this.currentResult = null;\n this.removeStoredSession();\n this.cleanup();\n this.emit('disconnect');\n }\n\n isConnected(): boolean {\n return this.currentResult !== null;\n }\n\n getWallet(): ConnectResult | null {\n return this.currentResult;\n }\n\n on(event: WalletConnectEventType, cb: WalletConnectEventCallback): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(cb);\n }\n\n off(event: WalletConnectEventType, cb: WalletConnectEventCallback): void {\n this.listeners.get(event)?.delete(cb);\n }\n\n // ── Internal ──\n\n private get storageKey(): string {\n const walletId = this.config.walletId;\n const suffix = Array.isArray(walletId)\n ? walletId.sort().join('_')\n : walletId || 'all';\n return `${STORAGE_KEY_PREFIX}${suffix}__`;\n }\n\n private async fetchWallets(): Promise<WalletMeta[]> {\n const url = this.config.registryUrl.replace(/\\/$/, '');\n const res = await fetch(url);\n if (!res.ok) throw new Error('Failed to fetch wallets');\n return res.json();\n }\n\n private filterWallets(wallets: WalletMeta[]): WalletMeta[] {\n if (!this.config.walletId) return wallets;\n\n const ids = Array.isArray(this.config.walletId)\n ? this.config.walletId\n : [this.config.walletId];\n\n return wallets.filter((w) => ids.includes(w.walletId));\n }\n\n private async startConnect(\n wallet: WalletMeta,\n showBack: boolean,\n resolve: (result: ConnectResult) => void,\n reject: (error: Error) => void,\n ): Promise<void> {\n try {\n const session = await this.initSession(wallet);\n\n this.modal?.showConnect(wallet, session.deeplink, showBack, () => {\n this.cleanup();\n this.connect().then(resolve).catch(reject);\n });\n\n this.listenForConfirmation(\n wallet.apiUrl,\n session.sessionToken,\n (result) => {\n this.currentResult = result;\n this.storeSession(result);\n this.modal?.destroy();\n this.modal = null;\n this.emit('connect', result);\n resolve(result);\n },\n () => {\n this.modal?.updateStatus('Connection rejected', false);\n setTimeout(() => {\n this.modal?.destroy();\n this.modal = null;\n reject(new Error('Connection rejected by user'));\n }, 1500);\n },\n () => {\n this.modal?.updateStatus('Session expired', false);\n this.emit('session_expired');\n setTimeout(() => {\n this.modal?.destroy();\n this.modal = null;\n reject(new Error('Session expired'));\n }, 1500);\n },\n );\n } catch (err) {\n this.modal?.destroy();\n this.modal = null;\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n }\n\n private async initSession(wallet: WalletMeta): Promise<InitSessionResponse> {\n const baseUrl = wallet.apiUrl.replace(/\\/$/, '');\n const res = await fetch(`${baseUrl}/connect/init`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n appId: this.config.appId,\n walletId: wallet.walletId,\n origin: typeof window !== 'undefined' ? window.location.origin : '',\n }),\n });\n if (!res.ok) throw new Error('Failed to init session');\n return res.json();\n }\n\n private listenForConfirmation(\n apiUrl: string,\n sessionToken: string,\n onConfirmed: (result: ConnectResult) => void,\n onRejected: () => void,\n onExpired: () => void,\n ): void {\n const onError = () => {\n this.pollingTransport = new PollingTransport(\n apiUrl,\n sessionToken,\n onConfirmed,\n onRejected,\n onExpired,\n (msg) => this.emit('error', msg),\n );\n this.pollingTransport.start();\n };\n\n this.wsTransport = new WsTransport(\n apiUrl,\n sessionToken,\n onConfirmed,\n onRejected,\n onExpired,\n onError,\n );\n this.wsTransport.connect();\n }\n\n private cleanup(): void {\n this.wsTransport?.close();\n this.wsTransport = null;\n this.pollingTransport?.stop();\n this.pollingTransport = null;\n this.modal?.destroy();\n this.modal = null;\n }\n\n private emit(event: WalletConnectEventType, data?: any): void {\n this.listeners.get(event)?.forEach((cb) => cb(data));\n }\n\n // ── Persistence ──\n\n private storeSession(result: ConnectResult): void {\n try {\n localStorage.setItem(this.storageKey, JSON.stringify(result));\n } catch {\n // localStorage unavailable\n }\n }\n\n private restoreSession(): void {\n try {\n const stored = localStorage.getItem(this.storageKey);\n if (stored) {\n this.currentResult = JSON.parse(stored);\n }\n } catch {\n // ignore\n }\n }\n\n private removeStoredSession(): void {\n try {\n localStorage.removeItem(this.storageKey);\n } catch {\n // ignore\n }\n }\n}\n","import { BaseWalletConnect } from './client';\nimport type { WalletConnectConfig } from './types';\n\nexport class TonPassConnect extends BaseWalletConnect {\n constructor(config: Omit<WalletConnectConfig, 'walletId'>) {\n super({ ...config, walletId: 'tonpass' });\n }\n}\n","import { BaseWalletConnect } from './client';\nimport type { WalletConnectConfig } from './types';\n\nexport class OneDollarConnect extends BaseWalletConnect {\n constructor(config: Omit<WalletConnectConfig, 'walletId'>) {\n super({ ...config, walletId: 'onedollar' });\n }\n}\n"],"names":["WsTransport","constructor","apiUrl","sessionToken","onConfirmed","onRejected","onExpired","onError","this","ws","reconnectTimer","closed","connect","replace","connectSocketIO","baseUrl","fetch","then","res","text","body","jsonStr","sid","JSON","parse","wsUrl","WebSocket","onopen","send","onmessage","event","msg","data","startsWith","payload","slice","eventName","handleEvent","onclose","scheduleReconnect","onerror","catch","close","setTimeout","clearTimeout","PollingTransport","timer","stopped","start","poll","setInterval","ok","json","status","wallets","user","stop","clearInterval","MODAL_ID","Modal","theme","onClose","overlay","showWalletPicker","onSelect","html","map","w","walletId","icon","name","charAt","toUpperCase","description","join","render","forEach","el","querySelector","addEventListener","showConnect","wallet","deeplink","showBack","onBack","qrUrl","size","encodeURIComponent","generateQRDataUrl","tabs","querySelectorAll","panels","tab","target","dataset","t","classList","remove","add","p","style","display","panel","updateStatus","showSpinner","statusEl","innerHTML","innerHtml","destroy","document","createElement","id","bgSecondary","textSecondary","border","primary","getStyles","appendChild","e","contains","existing","getElementById","BaseWalletConnect","config","listeners","Map","modal","wsTransport","pollingTransport","currentResult","appId","registryUrl","restoreSession","fetchWallets","filtered","filterWallets","length","Error","Promise","resolve","reject","cleanup","startConnect","disconnect","removeStoredSession","emit","isConnected","getWallet","on","cb","has","set","Set","get","off","delete","storageKey","Array","isArray","sort","url","ids","filter","includes","session","initSession","listenForConfirmation","result","storeSession","err","String","method","headers","stringify","origin","window","location","localStorage","setItem","stored","getItem","removeItem","TonPassConnect","super","OneDollarConnect"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).WalletConnectSDK={})}(this,function(e){"use strict";class t{constructor(e,t,n,s,i,o){this.apiUrl=e,this.sessionToken=t,this.onConfirmed=n,this.onRejected=s,this.onExpired=i,this.onError=o,this.ws=null,this.reconnectTimer=null,this.closed=!1}connect(){this.closed=!1;this.apiUrl.replace(/^http/,"ws").replace(/\/$/,"");this.sessionToken;try{this.connectSocketIO()}catch{this.onError("WebSocket connection failed")}}connectSocketIO(){const e=this.apiUrl.replace(/\/$/,"");fetch(`${e}/walletconnect/?EIO=4&transport=polling`).then(e=>e.text()).then(t=>{const n=t.replace(/^\d+/,""),s=JSON.parse(n).sid,i=`${e.replace(/^http/,"ws")}/walletconnect/?EIO=4&transport=websocket&sid=${s}`;this.ws=new WebSocket(i),this.ws.onopen=()=>{this.ws.send("2probe")},this.ws.onmessage=e=>{const t=e.data;if("3probe"!==t)if(t.startsWith("42"))try{const e=JSON.parse(t.slice(2)),[n,s]=e;this.handleEvent(n,s)}catch{}else"2"===t&&this.ws.send("3");else this.ws.send("5")},this.ws.onclose=()=>{this.closed||this.scheduleReconnect()},this.ws.onerror=()=>{this.closed||this.scheduleReconnect()}}).catch(()=>{this.closed||this.scheduleReconnect()})}handleEvent(e,t){switch(e){case"session_confirmed":this.onConfirmed(t),this.close();break;case"session_rejected":this.onRejected(),this.close();break;case"session_expired":this.onExpired(),this.close()}}scheduleReconnect(){this.closed||this.reconnectTimer||(this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.connectSocketIO()},3e3))}close(){this.closed=!0,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.ws&&(this.ws.close(),this.ws=null)}}class n{constructor(e,t,n,s,i,o){this.apiUrl=e,this.sessionToken=t,this.onConfirmed=n,this.onRejected=s,this.onExpired=i,this.onError=o,this.timer=null,this.stopped=!1}start(){this.stopped=!1,this.poll(),this.timer=setInterval(()=>this.poll(),2e3)}async poll(){if(!this.stopped)try{const e=this.apiUrl.replace(/\/$/,""),t=await fetch(`${e}/connect/status?token=${this.sessionToken}`);if(!t.ok)return;const n=await t.json();switch(n.status){case"CONFIRMED":this.onConfirmed({wallets:n.wallets,user:n.user}),this.stop();break;case"REJECTED":this.onRejected(),this.stop();break;case"EXPIRED":this.onExpired(),this.stop()}}catch{}}stop(){this.stopped=!0,this.timer&&(clearInterval(this.timer),this.timer=null)}}const s="__wc_modal__";class i{constructor(e,t){this.overlay=null,this.theme=e,this.onClose=t}showWalletPicker(e,t){const n=`\n <div class="wc-header">\n <h3 class="wc-title">Connect Wallet</h3>\n <button class="wc-close" data-action="close">&times;</button>\n </div>\n <div class="wc-body">\n <ul class="wc-wallet-list">${e.map(e=>`\n <li class="wc-wallet-item" data-wallet-id="${e.walletId}">\n ${e.icon?`<img class="wc-wallet-icon" src="${e.icon}" alt="${e.name}" />`:`<div class="wc-wallet-icon-placeholder">${e.name.charAt(0).toUpperCase()}</div>`}\n <div>\n <div class="wc-wallet-name">${e.name}</div>\n ${e.description?`<div class="wc-wallet-desc">${e.description}</div>`:""}\n </div>\n </li>`).join("")}</ul>\n </div>\n `;this.render(n),e.forEach(e=>{const n=this.overlay?.querySelector(`[data-wallet-id="${e.walletId}"]`);n?.addEventListener("click",()=>t(e))})}showConnect(e,t,n,s){const i=function(e,t=200){return`https://api.qrserver.com/v1/create-qr-code/?size=${t}x${t}&data=${encodeURIComponent(e)}`}(t),o=`\n <div class="wc-header">\n <div style="display:flex;align-items:center;gap:8px;">\n ${n?'<button class="wc-back" data-action="back">&#8592;</button>':""}\n <h3 class="wc-title">Connect ${e.name}</h3>\n </div>\n <button class="wc-close" data-action="close">&times;</button>\n </div>\n <div class="wc-body">\n <div class="wc-tabs">\n <button class="wc-tab active" data-tab="mobile">Mobile</button>\n <button class="wc-tab" data-tab="qr">QR Code</button>\n </div>\n <div data-panel="mobile">\n <a class="wc-deeplink-btn" href="${t}" target="_blank">\n Open in Telegram\n </a>\n </div>\n <div data-panel="qr" style="display:none;">\n <div class="wc-qr-container">\n <img class="wc-qr-canvas" src="${i}" width="200" height="200" alt="QR Code" />\n <div class="wc-qr-hint">Scan with your phone or from wallet app</div>\n </div>\n </div>\n <div class="wc-status">\n <div class="wc-spinner"></div>\n <span>Waiting for confirmation...</span>\n </div>\n </div>\n `;this.render(o);const r=this.overlay?.querySelectorAll(".wc-tab"),a=this.overlay?.querySelectorAll("[data-panel]");r?.forEach(e=>{e.addEventListener("click",()=>{const t=e.dataset.tab;r.forEach(e=>e.classList.remove("active")),e.classList.add("active"),a?.forEach(e=>{e.style.display=e.dataset.panel===t?"block":"none"})})}),n&&s&&this.overlay?.querySelector('[data-action="back"]')?.addEventListener("click",s)}updateStatus(e,t=!0){const n=this.overlay?.querySelector(".wc-status");n&&(n.innerHTML=`\n ${t?'<div class="wc-spinner"></div>':""}\n <span>${e}</span>\n `)}render(e){this.destroy();const t=document.createElement("div");t.id=s,t.innerHTML=`\n <style>${function(e){const t="dark"===e?"#16213e":"#f5f5f5",n="dark"===e?"#a0a0a0":"#666666",s="dark"===e?"#2a2a4a":"#e0e0e0",i="#3b82f6";return`\n .wc-overlay {\n position: fixed; inset: 0; z-index: 99999;\n background: rgba(0,0,0,0.5); display: flex;\n align-items: center; justify-content: center;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n .wc-modal {\n background: ${"dark"===e?"#1a1a2e":"#ffffff"}; border-radius: 16px; width: 380px;\n max-width: 90vw; box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n overflow: hidden; color: ${"dark"===e?"#e0e0e0":"#1a1a1a"};\n }\n .wc-header {\n display: flex; align-items: center; justify-content: space-between;\n padding: 20px 24px 16px; border-bottom: 1px solid ${s};\n }\n .wc-title { font-size: 18px; font-weight: 600; margin: 0; }\n .wc-close {\n background: none; border: none; cursor: pointer;\n font-size: 20px; color: ${n}; padding: 4px 8px;\n border-radius: 8px;\n }\n .wc-close:hover { background: ${t}; }\n .wc-body { padding: 16px 24px 24px; }\n .wc-wallet-list { list-style: none; margin: 0; padding: 0; }\n .wc-wallet-item {\n display: flex; align-items: center; gap: 12px;\n padding: 12px 16px; border-radius: 12px; cursor: pointer;\n border: 1px solid ${s}; margin-bottom: 8px;\n transition: background 0.15s;\n }\n .wc-wallet-item:hover { background: ${"dark"===e?"#0f3460":"#e8f0fe"}; }\n .wc-wallet-icon {\n width: 40px; height: 40px; border-radius: 10px;\n object-fit: cover; flex-shrink: 0;\n }\n .wc-wallet-icon-placeholder {\n width: 40px; height: 40px; border-radius: 10px;\n background: ${i}; display: flex; align-items: center;\n justify-content: center; color: #fff; font-weight: 700;\n font-size: 16px; flex-shrink: 0;\n }\n .wc-wallet-name { font-size: 15px; font-weight: 500; }\n .wc-wallet-desc { font-size: 12px; color: ${n}; margin-top: 2px; }\n\n /* Connect screen (after wallet selected) */\n .wc-tabs {\n display: flex; gap: 0; margin-bottom: 20px;\n border: 1px solid ${s}; border-radius: 10px; overflow: hidden;\n }\n .wc-tab {\n flex: 1; padding: 10px; text-align: center; cursor: pointer;\n font-size: 13px; font-weight: 500; background: ${t};\n border: none; color: ${n}; transition: all 0.15s;\n }\n .wc-tab.active { background: ${i}; color: #fff; }\n .wc-deeplink-btn {\n display: block; width: 100%; padding: 14px; border: none;\n border-radius: 12px; background: ${i}; color: #fff;\n font-size: 15px; font-weight: 600; cursor: pointer;\n text-align: center; text-decoration: none;\n }\n .wc-deeplink-btn:hover { opacity: 0.9; }\n .wc-qr-container {\n display: flex; flex-direction: column; align-items: center; gap: 12px;\n }\n .wc-qr-canvas {\n border-radius: 12px; padding: 16px; background: #fff;\n }\n .wc-qr-hint { font-size: 12px; color: ${n}; text-align: center; }\n .wc-status {\n display: flex; align-items: center; justify-content: center;\n gap: 8px; padding: 16px 0 0; font-size: 13px; color: ${n};\n }\n .wc-spinner {\n width: 16px; height: 16px; border: 2px solid ${s};\n border-top-color: ${i}; border-radius: 50%;\n animation: wc-spin 0.8s linear infinite;\n }\n @keyframes wc-spin { to { transform: rotate(360deg); } }\n .wc-back {\n background: none; border: none; cursor: pointer;\n font-size: 14px; color: ${i}; padding: 0;\n display: flex; align-items: center; gap: 4px;\n }\n .wc-back:hover { text-decoration: underline; }\n `}(this.theme)}</style>\n <div class="wc-overlay">\n <div class="wc-modal">${e}</div>\n </div>\n `,document.body.appendChild(t),this.overlay=t,this.overlay.querySelector('[data-action="close"]')?.addEventListener("click",()=>{this.onClose(),this.destroy()}),this.overlay.querySelector(".wc-overlay")?.addEventListener("click",e=>{e.target.classList.contains("wc-overlay")&&(this.onClose(),this.destroy())})}destroy(){const e=document.getElementById(s);e&&e.remove(),this.overlay=null}}class o{constructor(e){this.listeners=new Map,this.modal=null,this.wsTransport=null,this.pollingTransport=null,this.currentResult=null,this.config={appId:e.appId,registryUrl:e.registryUrl,walletId:e.walletId,theme:e.theme||"light"},this.restoreSession()}async connect(){if(this.currentResult)return this.currentResult;const e=await this.fetchWallets(),t=this.filterWallets(e);if(0===t.length)throw new Error("No supported wallets available");return new Promise((e,n)=>{this.modal=new i(this.config.theme,()=>{this.cleanup(),n(new Error("User closed modal"))}),1===t.length?this.startConnect(t[0],!1,e,n):this.modal.showWalletPicker(t,t=>{this.startConnect(t,!0,e,n)})})}disconnect(){this.currentResult=null,this.removeStoredSession(),this.cleanup(),this.emit("disconnect")}isConnected(){return null!==this.currentResult}getWallet(){return this.currentResult}on(e,t){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t)}off(e,t){this.listeners.get(e)?.delete(t)}get storageKey(){const e=this.config.walletId;return`__wc_session_${Array.isArray(e)?e.sort().join("_"):e||"all"}__`}async fetchWallets(){const e=this.config.registryUrl.replace(/\/$/,""),t=await fetch(e);if(!t.ok)throw new Error("Failed to fetch wallets");return t.json()}filterWallets(e){if(!this.config.walletId)return e;const t=Array.isArray(this.config.walletId)?this.config.walletId:[this.config.walletId];return e.filter(e=>t.includes(e.walletId))}async startConnect(e,t,n,s){try{const i=await this.initSession(e);this.modal?.showConnect(e,i.deeplink,t,()=>{this.cleanup(),this.connect().then(n).catch(s)}),this.listenForConfirmation(e.apiUrl,i.sessionToken,e=>{this.currentResult=e,this.storeSession(e),this.modal?.destroy(),this.modal=null,this.emit("connect",e),n(e)},()=>{this.modal?.updateStatus("Connection rejected",!1),setTimeout(()=>{this.modal?.destroy(),this.modal=null,s(new Error("Connection rejected by user"))},1500)},()=>{this.modal?.updateStatus("Session expired",!1),this.emit("session_expired"),setTimeout(()=>{this.modal?.destroy(),this.modal=null,s(new Error("Session expired"))},1500)})}catch(e){this.modal?.destroy(),this.modal=null,s(e instanceof Error?e:new Error(String(e)))}}async initSession(e){const t=e.apiUrl.replace(/\/$/,""),n=await fetch(`${t}/connect/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({appId:this.config.appId,walletId:e.walletId,origin:"undefined"!=typeof window?window.location.origin:""})});if(!n.ok)throw new Error("Failed to init session");return n.json()}listenForConfirmation(e,s,i,o,r){this.wsTransport=new t(e,s,i,o,r,()=>{this.pollingTransport=new n(e,s,i,o,r,e=>this.emit("error",e)),this.pollingTransport.start()}),this.wsTransport.connect()}cleanup(){this.wsTransport?.close(),this.wsTransport=null,this.pollingTransport?.stop(),this.pollingTransport=null,this.modal?.destroy(),this.modal=null}emit(e,t){this.listeners.get(e)?.forEach(e=>e(t))}storeSession(e){try{localStorage.setItem(this.storageKey,JSON.stringify(e))}catch{}}restoreSession(){try{const e=localStorage.getItem(this.storageKey);e&&(this.currentResult=JSON.parse(e))}catch{}}removeStoredSession(){try{localStorage.removeItem(this.storageKey)}catch{}}}e.BaseWalletConnect=o,e.OneDollarConnect=class extends o{constructor(e){super({...e,walletId:"onedollar"})}},e.TonPassConnect=class extends o{constructor(e){super({...e,walletId:"tonpass"})}}});
2
+ //# sourceMappingURL=index.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.umd.js","sources":["../../transport.ts","../../modal.ts","../../client.ts","../../onedollar.ts","../../tonpass.ts"],"sourcesContent":["import type { ConnectResult } from './types';\n\ntype TransportCallback = (data: ConnectResult) => void;\ntype TransportErrorCallback = (error: string) => void;\n\n// ── WebSocket Transport ──\n\nexport class WsTransport {\n private ws: WebSocket | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private closed = false;\n\n constructor(\n private apiUrl: string,\n private sessionToken: string,\n private onConfirmed: TransportCallback,\n private onRejected: () => void,\n private onExpired: () => void,\n private onError: TransportErrorCallback,\n ) {}\n\n connect(): void {\n this.closed = false;\n const wsUrl = this.apiUrl\n .replace(/^http/, 'ws')\n .replace(/\\/$/, '');\n const url = `${wsUrl}/walletconnect?sessionToken=${this.sessionToken}`;\n\n try {\n // Socket.IO uses polling upgrade — use native WS for simplicity in SDK\n // The BE gateway uses socket.io, so we connect via socket.io protocol\n this.connectSocketIO();\n } catch {\n this.onError('WebSocket connection failed');\n }\n }\n\n private connectSocketIO(): void {\n const baseUrl = this.apiUrl.replace(/\\/$/, '');\n\n // Socket.IO handshake: first GET for sid, then upgrade to WS\n const pollingUrl = `${baseUrl}/walletconnect/?EIO=4&transport=polling`;\n\n fetch(pollingUrl)\n .then((res) => res.text())\n .then((body) => {\n // Socket.IO response format: \"0{...json...}\"\n const jsonStr = body.replace(/^\\d+/, '');\n const handshake = JSON.parse(jsonStr);\n const sid = handshake.sid;\n\n const wsBase = baseUrl.replace(/^http/, 'ws');\n const wsUrl = `${wsBase}/walletconnect/?EIO=4&transport=websocket&sid=${sid}`;\n\n this.ws = new WebSocket(wsUrl);\n\n this.ws.onopen = () => {\n // Socket.IO upgrade probe\n this.ws!.send('2probe');\n };\n\n this.ws.onmessage = (event) => {\n const msg = event.data as string;\n\n if (msg === '3probe') {\n // Upgrade confirmed, send upgrade packet + join room\n this.ws!.send('5');\n // Emit connect event with sessionToken as query (already in URL)\n // Socket.IO auto-joins based on handshake query\n return;\n }\n\n // Handle Socket.IO event messages: 42[\"event_name\", {...data}]\n if (msg.startsWith('42')) {\n try {\n const payload = JSON.parse(msg.slice(2));\n const [eventName, data] = payload;\n this.handleEvent(eventName, data);\n } catch {\n // ignore malformed\n }\n return;\n }\n\n // Ping from server\n if (msg === '2') {\n this.ws!.send('3');\n }\n };\n\n this.ws.onclose = () => {\n if (!this.closed) {\n this.scheduleReconnect();\n }\n };\n\n this.ws.onerror = () => {\n if (!this.closed) {\n this.scheduleReconnect();\n }\n };\n })\n .catch(() => {\n if (!this.closed) {\n this.scheduleReconnect();\n }\n });\n }\n\n private handleEvent(eventName: string, data: any): void {\n switch (eventName) {\n case 'session_confirmed':\n this.onConfirmed(data);\n this.close();\n break;\n case 'session_rejected':\n this.onRejected();\n this.close();\n break;\n case 'session_expired':\n this.onExpired();\n this.close();\n break;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.closed || this.reconnectTimer) return;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connectSocketIO();\n }, 3000);\n }\n\n close(): void {\n this.closed = true;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n }\n}\n\n// ── Long-Poll Fallback ──\n\nexport class PollingTransport {\n private timer: ReturnType<typeof setInterval> | null = null;\n private stopped = false;\n\n constructor(\n private apiUrl: string,\n private sessionToken: string,\n private onConfirmed: TransportCallback,\n private onRejected: () => void,\n private onExpired: () => void,\n private onError: TransportErrorCallback,\n ) {}\n\n start(): void {\n this.stopped = false;\n this.poll();\n this.timer = setInterval(() => this.poll(), 2000);\n }\n\n private async poll(): Promise<void> {\n if (this.stopped) return;\n\n try {\n const baseUrl = this.apiUrl.replace(/\\/$/, '');\n const res = await fetch(\n `${baseUrl}/connect/status?token=${this.sessionToken}`,\n );\n if (!res.ok) return;\n\n const data = await res.json();\n\n switch (data.status) {\n case 'CONFIRMED':\n this.onConfirmed({ wallets: data.wallets, user: data.user });\n this.stop();\n break;\n case 'REJECTED':\n this.onRejected();\n this.stop();\n break;\n case 'EXPIRED':\n this.onExpired();\n this.stop();\n break;\n }\n } catch {\n // silently retry next interval\n }\n }\n\n stop(): void {\n this.stopped = true;\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n}\n","import type { WalletMeta } from './types';\n\nconst MODAL_ID = '__wc_modal__';\n\n// ── Styles (scoped, no conflict with host) ──\n\nfunction getStyles(theme: 'light' | 'dark'): string {\n const bg = theme === 'dark' ? '#1a1a2e' : '#ffffff';\n const bgSecondary = theme === 'dark' ? '#16213e' : '#f5f5f5';\n const text = theme === 'dark' ? '#e0e0e0' : '#1a1a1a';\n const textSecondary = theme === 'dark' ? '#a0a0a0' : '#666666';\n const border = theme === 'dark' ? '#2a2a4a' : '#e0e0e0';\n const primary = '#3b82f6';\n const hover = theme === 'dark' ? '#0f3460' : '#e8f0fe';\n\n return `\n .wc-overlay {\n position: fixed; inset: 0; z-index: 99999;\n background: rgba(0,0,0,0.5); display: flex;\n align-items: center; justify-content: center;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n .wc-modal {\n background: ${bg}; border-radius: 16px; width: 380px;\n max-width: 90vw; box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n overflow: hidden; color: ${text};\n }\n .wc-header {\n display: flex; align-items: center; justify-content: space-between;\n padding: 20px 24px 16px; border-bottom: 1px solid ${border};\n }\n .wc-title { font-size: 18px; font-weight: 600; margin: 0; }\n .wc-close {\n background: none; border: none; cursor: pointer;\n font-size: 20px; color: ${textSecondary}; padding: 4px 8px;\n border-radius: 8px;\n }\n .wc-close:hover { background: ${bgSecondary}; }\n .wc-body { padding: 16px 24px 24px; }\n .wc-wallet-list { list-style: none; margin: 0; padding: 0; }\n .wc-wallet-item {\n display: flex; align-items: center; gap: 12px;\n padding: 12px 16px; border-radius: 12px; cursor: pointer;\n border: 1px solid ${border}; margin-bottom: 8px;\n transition: background 0.15s;\n }\n .wc-wallet-item:hover { background: ${hover}; }\n .wc-wallet-icon {\n width: 40px; height: 40px; border-radius: 10px;\n object-fit: cover; flex-shrink: 0;\n }\n .wc-wallet-icon-placeholder {\n width: 40px; height: 40px; border-radius: 10px;\n background: ${primary}; display: flex; align-items: center;\n justify-content: center; color: #fff; font-weight: 700;\n font-size: 16px; flex-shrink: 0;\n }\n .wc-wallet-name { font-size: 15px; font-weight: 500; }\n .wc-wallet-desc { font-size: 12px; color: ${textSecondary}; margin-top: 2px; }\n\n /* Connect screen (after wallet selected) */\n .wc-tabs {\n display: flex; gap: 0; margin-bottom: 20px;\n border: 1px solid ${border}; border-radius: 10px; overflow: hidden;\n }\n .wc-tab {\n flex: 1; padding: 10px; text-align: center; cursor: pointer;\n font-size: 13px; font-weight: 500; background: ${bgSecondary};\n border: none; color: ${textSecondary}; transition: all 0.15s;\n }\n .wc-tab.active { background: ${primary}; color: #fff; }\n .wc-deeplink-btn {\n display: block; width: 100%; padding: 14px; border: none;\n border-radius: 12px; background: ${primary}; color: #fff;\n font-size: 15px; font-weight: 600; cursor: pointer;\n text-align: center; text-decoration: none;\n }\n .wc-deeplink-btn:hover { opacity: 0.9; }\n .wc-qr-container {\n display: flex; flex-direction: column; align-items: center; gap: 12px;\n }\n .wc-qr-canvas {\n border-radius: 12px; padding: 16px; background: #fff;\n }\n .wc-qr-hint { font-size: 12px; color: ${textSecondary}; text-align: center; }\n .wc-status {\n display: flex; align-items: center; justify-content: center;\n gap: 8px; padding: 16px 0 0; font-size: 13px; color: ${textSecondary};\n }\n .wc-spinner {\n width: 16px; height: 16px; border: 2px solid ${border};\n border-top-color: ${primary}; border-radius: 50%;\n animation: wc-spin 0.8s linear infinite;\n }\n @keyframes wc-spin { to { transform: rotate(360deg); } }\n .wc-back {\n background: none; border: none; cursor: pointer;\n font-size: 14px; color: ${primary}; padding: 0;\n display: flex; align-items: center; gap: 4px;\n }\n .wc-back:hover { text-decoration: underline; }\n `;\n}\n\n// ── QR Code (minimal inline generator, no external dep) ──\n\nfunction generateQRDataUrl(text: string, size = 200): string {\n // Encode as a simple QR placeholder using a public API\n // In production, replace with a bundled QR lib like 'qrcode'\n return `https://api.qrserver.com/v1/create-qr-code/?size=${size}x${size}&data=${encodeURIComponent(text)}`;\n}\n\n// ── Modal builder ──\n\nexport class Modal {\n private overlay: HTMLDivElement | null = null;\n private theme: 'light' | 'dark';\n private onClose: () => void;\n\n constructor(theme: 'light' | 'dark', onClose: () => void) {\n this.theme = theme;\n this.onClose = onClose;\n }\n\n // Show wallet picker (multiple wallets)\n showWalletPicker(\n wallets: WalletMeta[],\n onSelect: (wallet: WalletMeta) => void,\n ): void {\n const walletListHtml = wallets\n .map(\n (w) => `\n <li class=\"wc-wallet-item\" data-wallet-id=\"${w.walletId}\">\n ${\n w.icon\n ? `<img class=\"wc-wallet-icon\" src=\"${w.icon}\" alt=\"${w.name}\" />`\n : `<div class=\"wc-wallet-icon-placeholder\">${w.name.charAt(0).toUpperCase()}</div>`\n }\n <div>\n <div class=\"wc-wallet-name\">${w.name}</div>\n ${w.description ? `<div class=\"wc-wallet-desc\">${w.description}</div>` : ''}\n </div>\n </li>`,\n )\n .join('');\n\n const html = `\n <div class=\"wc-header\">\n <h3 class=\"wc-title\">Connect Wallet</h3>\n <button class=\"wc-close\" data-action=\"close\">&times;</button>\n </div>\n <div class=\"wc-body\">\n <ul class=\"wc-wallet-list\">${walletListHtml}</ul>\n </div>\n `;\n\n this.render(html);\n\n // Bind wallet click\n wallets.forEach((w) => {\n const el = this.overlay?.querySelector(\n `[data-wallet-id=\"${w.walletId}\"]`,\n );\n el?.addEventListener('click', () => onSelect(w));\n });\n }\n\n // Show connect screen (deeplink + QR)\n showConnect(\n wallet: WalletMeta,\n deeplink: string,\n showBack: boolean,\n onBack?: () => void,\n ): void {\n const qrUrl = generateQRDataUrl(deeplink);\n\n const html = `\n <div class=\"wc-header\">\n <div style=\"display:flex;align-items:center;gap:8px;\">\n ${\n showBack\n ? '<button class=\"wc-back\" data-action=\"back\">&#8592;</button>'\n : ''\n }\n <h3 class=\"wc-title\">Connect ${wallet.name}</h3>\n </div>\n <button class=\"wc-close\" data-action=\"close\">&times;</button>\n </div>\n <div class=\"wc-body\">\n <div class=\"wc-tabs\">\n <button class=\"wc-tab active\" data-tab=\"mobile\">Mobile</button>\n <button class=\"wc-tab\" data-tab=\"qr\">QR Code</button>\n </div>\n <div data-panel=\"mobile\">\n <a class=\"wc-deeplink-btn\" href=\"${deeplink}\" target=\"_blank\">\n Open in Telegram\n </a>\n </div>\n <div data-panel=\"qr\" style=\"display:none;\">\n <div class=\"wc-qr-container\">\n <img class=\"wc-qr-canvas\" src=\"${qrUrl}\" width=\"200\" height=\"200\" alt=\"QR Code\" />\n <div class=\"wc-qr-hint\">Scan with your phone or from wallet app</div>\n </div>\n </div>\n <div class=\"wc-status\">\n <div class=\"wc-spinner\"></div>\n <span>Waiting for confirmation...</span>\n </div>\n </div>\n `;\n\n this.render(html);\n\n // Tab switching\n const tabs = this.overlay?.querySelectorAll('.wc-tab');\n const panels = this.overlay?.querySelectorAll('[data-panel]');\n tabs?.forEach((tab) => {\n tab.addEventListener('click', () => {\n const target = (tab as HTMLElement).dataset.tab;\n tabs.forEach((t) => t.classList.remove('active'));\n tab.classList.add('active');\n panels?.forEach((p) => {\n (p as HTMLElement).style.display =\n (p as HTMLElement).dataset.panel === target ? 'block' : 'none';\n });\n });\n });\n\n // Back button\n if (showBack && onBack) {\n this.overlay\n ?.querySelector('[data-action=\"back\"]')\n ?.addEventListener('click', onBack);\n }\n }\n\n // Update status text\n updateStatus(text: string, showSpinner = true): void {\n const statusEl = this.overlay?.querySelector('.wc-status');\n if (statusEl) {\n statusEl.innerHTML = `\n ${showSpinner ? '<div class=\"wc-spinner\"></div>' : ''}\n <span>${text}</span>\n `;\n }\n }\n\n private render(innerHtml: string): void {\n this.destroy();\n\n const overlay = document.createElement('div');\n overlay.id = MODAL_ID;\n overlay.innerHTML = `\n <style>${getStyles(this.theme)}</style>\n <div class=\"wc-overlay\">\n <div class=\"wc-modal\">${innerHtml}</div>\n </div>\n `;\n\n document.body.appendChild(overlay);\n this.overlay = overlay;\n\n // Close button\n this.overlay\n .querySelector('[data-action=\"close\"]')\n ?.addEventListener('click', () => {\n this.onClose();\n this.destroy();\n });\n\n // Click overlay to close\n this.overlay\n .querySelector('.wc-overlay')\n ?.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).classList.contains('wc-overlay')) {\n this.onClose();\n this.destroy();\n }\n });\n }\n\n destroy(): void {\n const existing = document.getElementById(MODAL_ID);\n if (existing) {\n existing.remove();\n }\n this.overlay = null;\n }\n}\n","import type {\n WalletConnectConfig,\n WalletMeta,\n ConnectResult,\n InitSessionResponse,\n WalletConnectEventType,\n WalletConnectEventCallback,\n} from './types';\nimport { WsTransport, PollingTransport } from './transport';\nimport { Modal } from './modal';\n\nconst STORAGE_KEY_PREFIX = '__wc_session_';\n\nexport class BaseWalletConnect {\n protected config: Required<\n Pick<WalletConnectConfig, 'appId' | 'registryUrl' | 'theme'>\n > &\n Pick<WalletConnectConfig, 'walletId'>;\n\n private listeners: Map<WalletConnectEventType, Set<WalletConnectEventCallback>> = new Map();\n private modal: Modal | null = null;\n private wsTransport: WsTransport | null = null;\n private pollingTransport: PollingTransport | null = null;\n private currentResult: ConnectResult | null = null;\n\n constructor(config: WalletConnectConfig) {\n this.config = {\n appId: config.appId,\n registryUrl: config.registryUrl,\n walletId: config.walletId,\n theme: config.theme || 'light',\n };\n\n this.restoreSession();\n }\n\n // ── Public API ──\n\n async connect(): Promise<ConnectResult> {\n if (this.currentResult) {\n return this.currentResult;\n }\n\n const wallets = await this.fetchWallets();\n const filtered = this.filterWallets(wallets);\n\n if (filtered.length === 0) {\n throw new Error('No supported wallets available');\n }\n\n return new Promise<ConnectResult>((resolve, reject) => {\n const onClose = () => {\n this.cleanup();\n reject(new Error('User closed modal'));\n };\n\n this.modal = new Modal(this.config.theme, onClose);\n\n if (filtered.length === 1) {\n this.startConnect(filtered[0], false, resolve, reject);\n } else {\n this.modal.showWalletPicker(filtered, (wallet) => {\n this.startConnect(wallet, true, resolve, reject);\n });\n }\n });\n }\n\n disconnect(): void {\n this.currentResult = null;\n this.removeStoredSession();\n this.cleanup();\n this.emit('disconnect');\n }\n\n isConnected(): boolean {\n return this.currentResult !== null;\n }\n\n getWallet(): ConnectResult | null {\n return this.currentResult;\n }\n\n on(event: WalletConnectEventType, cb: WalletConnectEventCallback): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(cb);\n }\n\n off(event: WalletConnectEventType, cb: WalletConnectEventCallback): void {\n this.listeners.get(event)?.delete(cb);\n }\n\n // ── Internal ──\n\n private get storageKey(): string {\n const walletId = this.config.walletId;\n const suffix = Array.isArray(walletId)\n ? walletId.sort().join('_')\n : walletId || 'all';\n return `${STORAGE_KEY_PREFIX}${suffix}__`;\n }\n\n private async fetchWallets(): Promise<WalletMeta[]> {\n const url = this.config.registryUrl.replace(/\\/$/, '');\n const res = await fetch(url);\n if (!res.ok) throw new Error('Failed to fetch wallets');\n return res.json();\n }\n\n private filterWallets(wallets: WalletMeta[]): WalletMeta[] {\n if (!this.config.walletId) return wallets;\n\n const ids = Array.isArray(this.config.walletId)\n ? this.config.walletId\n : [this.config.walletId];\n\n return wallets.filter((w) => ids.includes(w.walletId));\n }\n\n private async startConnect(\n wallet: WalletMeta,\n showBack: boolean,\n resolve: (result: ConnectResult) => void,\n reject: (error: Error) => void,\n ): Promise<void> {\n try {\n const session = await this.initSession(wallet);\n\n this.modal?.showConnect(wallet, session.deeplink, showBack, () => {\n this.cleanup();\n this.connect().then(resolve).catch(reject);\n });\n\n this.listenForConfirmation(\n wallet.apiUrl,\n session.sessionToken,\n (result) => {\n this.currentResult = result;\n this.storeSession(result);\n this.modal?.destroy();\n this.modal = null;\n this.emit('connect', result);\n resolve(result);\n },\n () => {\n this.modal?.updateStatus('Connection rejected', false);\n setTimeout(() => {\n this.modal?.destroy();\n this.modal = null;\n reject(new Error('Connection rejected by user'));\n }, 1500);\n },\n () => {\n this.modal?.updateStatus('Session expired', false);\n this.emit('session_expired');\n setTimeout(() => {\n this.modal?.destroy();\n this.modal = null;\n reject(new Error('Session expired'));\n }, 1500);\n },\n );\n } catch (err) {\n this.modal?.destroy();\n this.modal = null;\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n }\n\n private async initSession(wallet: WalletMeta): Promise<InitSessionResponse> {\n const baseUrl = wallet.apiUrl.replace(/\\/$/, '');\n const res = await fetch(`${baseUrl}/connect/init`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n appId: this.config.appId,\n walletId: wallet.walletId,\n origin: typeof window !== 'undefined' ? window.location.origin : '',\n }),\n });\n if (!res.ok) throw new Error('Failed to init session');\n return res.json();\n }\n\n private listenForConfirmation(\n apiUrl: string,\n sessionToken: string,\n onConfirmed: (result: ConnectResult) => void,\n onRejected: () => void,\n onExpired: () => void,\n ): void {\n const onError = () => {\n this.pollingTransport = new PollingTransport(\n apiUrl,\n sessionToken,\n onConfirmed,\n onRejected,\n onExpired,\n (msg) => this.emit('error', msg),\n );\n this.pollingTransport.start();\n };\n\n this.wsTransport = new WsTransport(\n apiUrl,\n sessionToken,\n onConfirmed,\n onRejected,\n onExpired,\n onError,\n );\n this.wsTransport.connect();\n }\n\n private cleanup(): void {\n this.wsTransport?.close();\n this.wsTransport = null;\n this.pollingTransport?.stop();\n this.pollingTransport = null;\n this.modal?.destroy();\n this.modal = null;\n }\n\n private emit(event: WalletConnectEventType, data?: any): void {\n this.listeners.get(event)?.forEach((cb) => cb(data));\n }\n\n // ── Persistence ──\n\n private storeSession(result: ConnectResult): void {\n try {\n localStorage.setItem(this.storageKey, JSON.stringify(result));\n } catch {\n // localStorage unavailable\n }\n }\n\n private restoreSession(): void {\n try {\n const stored = localStorage.getItem(this.storageKey);\n if (stored) {\n this.currentResult = JSON.parse(stored);\n }\n } catch {\n // ignore\n }\n }\n\n private removeStoredSession(): void {\n try {\n localStorage.removeItem(this.storageKey);\n } catch {\n // ignore\n }\n }\n}\n","import { BaseWalletConnect } from './client';\nimport type { WalletConnectConfig } from './types';\n\nexport class OneDollarConnect extends BaseWalletConnect {\n constructor(config: Omit<WalletConnectConfig, 'walletId'>) {\n super({ ...config, walletId: 'onedollar' });\n }\n}\n","import { BaseWalletConnect } from './client';\nimport type { WalletConnectConfig } from './types';\n\nexport class TonPassConnect extends BaseWalletConnect {\n constructor(config: Omit<WalletConnectConfig, 'walletId'>) {\n super({ ...config, walletId: 'tonpass' });\n }\n}\n"],"names":["WsTransport","constructor","apiUrl","sessionToken","onConfirmed","onRejected","onExpired","onError","this","ws","reconnectTimer","closed","connect","replace","connectSocketIO","baseUrl","fetch","then","res","text","body","jsonStr","sid","JSON","parse","wsUrl","WebSocket","onopen","send","onmessage","event","msg","data","startsWith","payload","slice","eventName","handleEvent","onclose","scheduleReconnect","onerror","catch","close","setTimeout","clearTimeout","PollingTransport","timer","stopped","start","poll","setInterval","ok","json","status","wallets","user","stop","clearInterval","MODAL_ID","Modal","theme","onClose","overlay","showWalletPicker","onSelect","html","map","w","walletId","icon","name","charAt","toUpperCase","description","join","render","forEach","el","querySelector","addEventListener","showConnect","wallet","deeplink","showBack","onBack","qrUrl","size","encodeURIComponent","generateQRDataUrl","tabs","querySelectorAll","panels","tab","target","dataset","t","classList","remove","add","p","style","display","panel","updateStatus","showSpinner","statusEl","innerHTML","innerHtml","destroy","document","createElement","id","bgSecondary","textSecondary","border","primary","getStyles","appendChild","e","contains","existing","getElementById","BaseWalletConnect","config","listeners","Map","modal","wsTransport","pollingTransport","currentResult","appId","registryUrl","restoreSession","fetchWallets","filtered","filterWallets","length","Error","Promise","resolve","reject","cleanup","startConnect","disconnect","removeStoredSession","emit","isConnected","getWallet","on","cb","has","set","Set","get","off","delete","storageKey","Array","isArray","sort","url","ids","filter","includes","session","initSession","listenForConfirmation","result","storeSession","err","String","method","headers","stringify","origin","window","location","localStorage","setItem","stored","getItem","removeItem","super"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { WalletMeta } from './types';
2
+ export declare class Modal {
3
+ private overlay;
4
+ private theme;
5
+ private onClose;
6
+ constructor(theme: 'light' | 'dark', onClose: () => void);
7
+ showWalletPicker(wallets: WalletMeta[], onSelect: (wallet: WalletMeta) => void): void;
8
+ showConnect(wallet: WalletMeta, deeplink: string, showBack: boolean, onBack?: () => void): void;
9
+ updateStatus(text: string, showSpinner?: boolean): void;
10
+ private render;
11
+ destroy(): void;
12
+ }
@@ -0,0 +1,5 @@
1
+ import { BaseWalletConnect } from './client';
2
+ import type { WalletConnectConfig } from './types';
3
+ export declare class OneDollarConnect extends BaseWalletConnect {
4
+ constructor(config: Omit<WalletConnectConfig, 'walletId'>);
5
+ }
@@ -0,0 +1,5 @@
1
+ import { BaseWalletConnect } from './client';
2
+ import type { WalletConnectConfig } from './types';
3
+ export declare class TonPassConnect extends BaseWalletConnect {
4
+ constructor(config: Omit<WalletConnectConfig, 'walletId'>);
5
+ }
@@ -0,0 +1,35 @@
1
+ import type { ConnectResult } from './types';
2
+ type TransportCallback = (data: ConnectResult) => void;
3
+ type TransportErrorCallback = (error: string) => void;
4
+ export declare class WsTransport {
5
+ private apiUrl;
6
+ private sessionToken;
7
+ private onConfirmed;
8
+ private onRejected;
9
+ private onExpired;
10
+ private onError;
11
+ private ws;
12
+ private reconnectTimer;
13
+ private closed;
14
+ constructor(apiUrl: string, sessionToken: string, onConfirmed: TransportCallback, onRejected: () => void, onExpired: () => void, onError: TransportErrorCallback);
15
+ connect(): void;
16
+ private connectSocketIO;
17
+ private handleEvent;
18
+ private scheduleReconnect;
19
+ close(): void;
20
+ }
21
+ export declare class PollingTransport {
22
+ private apiUrl;
23
+ private sessionToken;
24
+ private onConfirmed;
25
+ private onRejected;
26
+ private onExpired;
27
+ private onError;
28
+ private timer;
29
+ private stopped;
30
+ constructor(apiUrl: string, sessionToken: string, onConfirmed: TransportCallback, onRejected: () => void, onExpired: () => void, onError: TransportErrorCallback);
31
+ start(): void;
32
+ private poll;
33
+ stop(): void;
34
+ }
35
+ export {};
@@ -0,0 +1,46 @@
1
+ export interface WalletConnectConfig {
2
+ /** Registered app ID from dashboard */
3
+ appId: string;
4
+ /** Filter to specific wallet(s). Omit to show all available */
5
+ walletId?: string | string[];
6
+ /** URL to fetch wallet registry (GET /connect/wallets) */
7
+ registryUrl: string;
8
+ /** Theme */
9
+ theme?: 'light' | 'dark';
10
+ }
11
+ export interface WalletMeta {
12
+ walletId: string;
13
+ name: string;
14
+ icon: string;
15
+ botUsername: string;
16
+ appName: string;
17
+ apiUrl: string;
18
+ description?: string;
19
+ order: number;
20
+ }
21
+ export interface WalletInfo {
22
+ address: string;
23
+ chain: string;
24
+ }
25
+ export interface ConnectResult {
26
+ wallets: WalletInfo[];
27
+ user: {
28
+ username?: string;
29
+ avatar?: string;
30
+ };
31
+ }
32
+ export interface InitSessionResponse {
33
+ sessionToken: string;
34
+ deeplink: string;
35
+ expiresAt: string;
36
+ }
37
+ export interface SessionStatusResponse {
38
+ status: 'PENDING' | 'CONFIRMED' | 'REJECTED' | 'EXPIRED';
39
+ wallets?: WalletInfo[];
40
+ user?: {
41
+ username?: string;
42
+ avatar?: string;
43
+ };
44
+ }
45
+ export type WalletConnectEventType = 'connect' | 'disconnect' | 'error' | 'session_expired';
46
+ export type WalletConnectEventCallback = (data?: any) => void;
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "toncorp-wallet-connect-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Wallet Connect SDK — connect TonPass, OneDollar and more wallets from any DApp",
5
+ "author": "PlaygroundVina",
6
+ "license": "MIT",
7
+ "main": "dist/index.cjs.js",
8
+ "module": "dist/index.esm.js",
9
+ "types": "dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.esm.js",
13
+ "require": "./dist/index.cjs.js",
14
+ "types": "./dist/index.d.ts"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md"
20
+ ],
21
+ "scripts": {
22
+ "build": "rollup -c rollup.config.mjs",
23
+ "prepublishOnly": "npm run build",
24
+ "clean": "rm -rf dist"
25
+ },
26
+ "devDependencies": {
27
+ "rollup": "^4.0.0",
28
+ "@rollup/plugin-typescript": "^12.0.0",
29
+ "tslib": "^2.7.0",
30
+ "@rollup/plugin-terser": "^0.4.0",
31
+ "typescript": "^5.0.0"
32
+ },
33
+ "keywords": [
34
+ "wallet",
35
+ "connect",
36
+ "tonpass",
37
+ "onedollar",
38
+ "telegram",
39
+ "dapp",
40
+ "web3"
41
+ ],
42
+ "repository": {
43
+ "type": "git",
44
+ "url": ""
45
+ },
46
+ "sideEffects": false
47
+ }