windkit 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,7 @@
1
1
  # WindKit
2
+
3
+ [![npm version](https://img.shields.io/npm/v/windkit.svg)](https://www.npmjs.com/package/windkit)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
2
5
  A protocol to connect Vexanium DApps to the Wind wallet.
3
6
 
4
7
  ## Features
@@ -77,4 +80,4 @@ console.log(result.transaction_id ?? result.id);
77
80
  > Notes
78
81
  > - Class names: `WindConnector` (connector) and `WalletSession` (active session).
79
82
  > - Chain ID is handled internally by `WalletSession.ChainID` (Vexanium mainnet).
80
- > - For re-login, the `session` event may be called without `proof` (use `session.permissionLevel`).
83
+ > - For re-login, the `session` event may be called without `proof` (use `session.permissionLevel`).
package/dist/index.cjs ADDED
@@ -0,0 +1,316 @@
1
+ 'use strict';
2
+
3
+ var signingRequest = require('@wharfkit/signing-request');
4
+ var antelope = require('@wharfkit/antelope');
5
+ var peerjs = require('peerjs');
6
+ var pako = require('pako');
7
+
8
+ function _interopNamespace(e) {
9
+ if (e && e.__esModule) return e;
10
+ var n = Object.create(null);
11
+ if (e) {
12
+ Object.keys(e).forEach(function (k) {
13
+ if (k !== 'default') {
14
+ var d = Object.getOwnPropertyDescriptor(e, k);
15
+ Object.defineProperty(n, k, d.get ? d : {
16
+ enumerable: true,
17
+ get: function () { return e[k]; }
18
+ });
19
+ }
20
+ });
21
+ }
22
+ n.default = e;
23
+ return Object.freeze(n);
24
+ }
25
+
26
+ var pako__namespace = /*#__PURE__*/_interopNamespace(pako);
27
+
28
+ // src/WindConnector.ts
29
+ var zlib = {
30
+ deflateRaw: (data) => pako__namespace.deflateRaw(data),
31
+ inflateRaw: (data) => pako__namespace.inflateRaw(data)
32
+ };
33
+
34
+ // src/WalletSession.ts
35
+ function assertBrowser() {
36
+ if (typeof window === "undefined" || typeof crypto === "undefined") {
37
+ throw new Error("WalletSession requires browser environment (window/crypto).");
38
+ }
39
+ }
40
+ var WalletSession = class _WalletSession {
41
+ static ChainID = "f9f432b1851b5c179d2091a96f593aaed50ec7466b74f89301f957a83e56ce1f";
42
+ #connection;
43
+ #callbacks;
44
+ #encodingOptions;
45
+ #permissionLevel;
46
+ #closeListener;
47
+ #errorListener;
48
+ constructor(connection) {
49
+ this.#connection = connection;
50
+ this.#callbacks = /* @__PURE__ */ new Map();
51
+ connection.on("data", (data) => this.#onDataReceived(data));
52
+ connection.on("close", () => this.#closeListener?.());
53
+ connection.on("error", (error) => this.#errorListener?.(error));
54
+ }
55
+ setABICache(cache) {
56
+ this.#encodingOptions = { zlib, abiProvider: cache };
57
+ }
58
+ onClose(listener) {
59
+ this.#closeListener = listener;
60
+ }
61
+ onError(listener) {
62
+ this.#errorListener = listener;
63
+ }
64
+ isOpen() {
65
+ return Boolean(this.#connection.open);
66
+ }
67
+ close() {
68
+ this.#connection.close();
69
+ }
70
+ get permissionLevel() {
71
+ return this.#permissionLevel;
72
+ }
73
+ set permissionLevel(value) {
74
+ this.#permissionLevel = value;
75
+ }
76
+ get actor() {
77
+ return this.#permissionLevel?.actor;
78
+ }
79
+ get permission() {
80
+ return this.#permissionLevel?.permission;
81
+ }
82
+ async transact(args, options) {
83
+ assertBrowser();
84
+ args.chainId = _WalletSession.ChainID;
85
+ const willBroadcast = options?.broadcast ?? true;
86
+ const request = await signingRequest.SigningRequest.create(
87
+ args,
88
+ this.#encodingOptions ?? { zlib }
89
+ );
90
+ request.setBroadcast(willBroadcast);
91
+ const vsr = request.encode(true, false, "vsr:");
92
+ return this.signingRequest(vsr);
93
+ }
94
+ signingRequest(vsr) {
95
+ assertBrowser();
96
+ const callback = crypto.randomUUID();
97
+ const data = { method: "signingRequest", id: callback, params: { vsr } };
98
+ return new Promise((resolve, reject) => {
99
+ const func = (reply) => {
100
+ const r = reply;
101
+ if (r.code === "SENT") {
102
+ resolve(r.result);
103
+ } else if (r.code === "SIGNED") {
104
+ resolve(antelope.SignedTransaction.from(r.result));
105
+ } else {
106
+ const err = typeof r.error === "string" ? new Error(r.error) : r.error ?? new Error("Unknown error");
107
+ reject(err);
108
+ }
109
+ };
110
+ this.#callbacks.set(callback, func);
111
+ this.#connection.send(data);
112
+ });
113
+ }
114
+ signMessage(message) {
115
+ assertBrowser();
116
+ const callback = crypto.randomUUID();
117
+ const data = { method: "signMessage", id: callback, params: { message } };
118
+ return new Promise((resolve, reject) => {
119
+ const func = (reply) => {
120
+ const r = reply;
121
+ if (r.code === "SIGNED" && r.result?.signature) {
122
+ resolve(antelope.Signature.from(r.result.signature));
123
+ } else {
124
+ reject(new Error(r.error?.message ?? "Sign message failed"));
125
+ }
126
+ };
127
+ this.#callbacks.set(callback, func);
128
+ this.#connection.send(data);
129
+ });
130
+ }
131
+ sharedSecret(publicKey) {
132
+ assertBrowser();
133
+ const callback = crypto.randomUUID();
134
+ const data = {
135
+ method: "sharedSecret",
136
+ id: callback,
137
+ params: { key: publicKey.toString() }
138
+ };
139
+ return new Promise((resolve, reject) => {
140
+ const func = (reply) => {
141
+ const r = reply;
142
+ if (r.code === "CREATED" && r.result?.secret) {
143
+ resolve(antelope.Checksum512.from(r.result.secret));
144
+ } else {
145
+ reject(new Error(String(r.error ?? "ECDH failed")));
146
+ }
147
+ };
148
+ this.#callbacks.set(callback, func);
149
+ this.#connection.send(data);
150
+ });
151
+ }
152
+ // menerima unknown, lakukan narrowing di dalam
153
+ #onDataReceived(data) {
154
+ if (!data || typeof data !== "object") return;
155
+ const maybe = data;
156
+ if (!maybe.id || typeof maybe.id !== "string") return;
157
+ const callback = this.#callbacks.get(maybe.id);
158
+ if (callback) {
159
+ callback(data);
160
+ this.#callbacks.delete(maybe.id);
161
+ }
162
+ }
163
+ };
164
+
165
+ // src/WindConnector.ts
166
+ function assertBrowser2() {
167
+ if (typeof window === "undefined" || typeof crypto === "undefined") {
168
+ throw new Error("WindConnector requires browser environment (window/crypto).");
169
+ }
170
+ }
171
+ var WindConnector = class {
172
+ #peer;
173
+ #peerOptions = {};
174
+ #peerId;
175
+ #listeners = /* @__PURE__ */ new Map();
176
+ #session = /* @__PURE__ */ new Map();
177
+ /** Argumen identity yang sesuai typing @wharfkit */
178
+ #identityArgs = {
179
+ chainId: WalletSession.ChainID,
180
+ scope: "vexanium",
181
+ // beberapa versi typing menandai callback required; berikan placeholder
182
+ callback: { url: "", background: false }
183
+ };
184
+ constructor() {
185
+ this.#peerOptions.config = {
186
+ iceServers: [
187
+ { urls: "stun:stun.l.google.com:19302" },
188
+ { urls: "stun:stun1.l.google.com:3478" },
189
+ { urls: "stun:stun.relay.metered.ca:80" },
190
+ {
191
+ urls: "turn:asia.relay.metered.ca:80",
192
+ username: "b66cd40a117bddb5cde924ab",
193
+ credential: "4jRmuTehVCZ2a/S+"
194
+ }
195
+ ],
196
+ sdpSemantics: "unified-plan"
197
+ };
198
+ this.#loadSession();
199
+ }
200
+ addIceServer(server) {
201
+ if (!this.#peerOptions.config) this.#peerOptions.config = { iceServers: [] };
202
+ this.#peerOptions.config.iceServers.push(server);
203
+ }
204
+ setServer(host, port) {
205
+ this.#peerOptions.host = host;
206
+ if (typeof port === "number") this.#peerOptions.port = port;
207
+ }
208
+ /** Events: `open`, `close`, `disconnected`, `error`, `session` */
209
+ on(event, func) {
210
+ this.#listeners.set(event, func);
211
+ }
212
+ async connect() {
213
+ assertBrowser2();
214
+ if (!this.#peerId) throw new Error("Peer ID is not set");
215
+ this.#peer = new peerjs.Peer(this.#peerId, this.#peerOptions);
216
+ this.#peer.on("connection", this.#onConnection.bind(this));
217
+ this.#listeners.forEach((func, key) => this.#peer.on(key, func));
218
+ }
219
+ disconnect() {
220
+ this.#peer?.disconnect();
221
+ }
222
+ destroy() {
223
+ this.#peer?.destroy();
224
+ }
225
+ reconnect() {
226
+ this.#peer?.reconnect();
227
+ }
228
+ isDisconnected() {
229
+ return Boolean(this.#peer?.disconnected);
230
+ }
231
+ isDestroyed() {
232
+ return Boolean(this.#peer?.destroyed);
233
+ }
234
+ /**
235
+ * Membuat VSR login untuk QR/URL.
236
+ * @param name - App name
237
+ * @param icon - Icon URL
238
+ */
239
+ createLoginRequest(name, icon) {
240
+ assertBrowser2();
241
+ const session = this.#getLastSession();
242
+ if (session) {
243
+ const [actor, perm] = session.permission.split("@");
244
+ this.#identityArgs.account = actor;
245
+ this.#identityArgs.permission = perm;
246
+ this.#peerId = session.peerId;
247
+ } else {
248
+ this.#peerId = `VEX-${crypto.randomUUID()}`;
249
+ delete this.#identityArgs.account;
250
+ delete this.#identityArgs.permission;
251
+ }
252
+ const req = signingRequest.SigningRequest.identity(this.#identityArgs, { zlib });
253
+ req.setInfoKey("pi", this.#peerId);
254
+ req.setInfoKey("na", name);
255
+ req.setInfoKey("ic", icon);
256
+ req.setInfoKey("do", window.location.origin);
257
+ if (session) {
258
+ req.setInfoKey("exp", antelope.Int64.from(session.exp));
259
+ if (session.signature) req.setInfoKey("sig", session.signature);
260
+ }
261
+ return req.encode(true, false, "vsr:");
262
+ }
263
+ /** ===== internal helpers ===== */
264
+ #getLastSession() {
265
+ const domain = typeof window !== "undefined" ? window.location.origin : "";
266
+ if (!domain) return null;
267
+ const current = this.#session.get(domain);
268
+ if (current && current.exp >= Date.now()) return current;
269
+ if (current) this.#session.delete(domain);
270
+ return null;
271
+ }
272
+ #addSession(permission, exp, signature) {
273
+ const domain = window.location.origin;
274
+ const peerId = this.#peerId ?? `VEX-${crypto.randomUUID()}`;
275
+ const current = { permission, exp, signature, domain, peerId };
276
+ this.#session.set(domain, current);
277
+ }
278
+ #saveSession() {
279
+ const data = Array.from(this.#session.values());
280
+ sessionStorage.setItem("session", JSON.stringify(data));
281
+ }
282
+ #loadSession() {
283
+ if (typeof window === "undefined") return;
284
+ const raw = sessionStorage.getItem("session");
285
+ if (!raw) return;
286
+ try {
287
+ const data = JSON.parse(raw);
288
+ for (const it of data) this.#session.set(it.domain, it);
289
+ } catch {
290
+ sessionStorage.removeItem("session");
291
+ }
292
+ }
293
+ #onConnection(conn) {
294
+ conn.once("data", (payload) => {
295
+ const p = payload;
296
+ if (p.code === "LOGIN_OK") {
297
+ const auth = signingRequest.Base64u.decode(p.result.auth);
298
+ const proof = antelope.Serializer.decode({ data: auth, type: signingRequest.IdentityProof });
299
+ const session = new WalletSession(conn);
300
+ session.permissionLevel = proof.signer;
301
+ this.#addSession(proof.signer.toString(), p.result.exp, p.result.signature);
302
+ this.#saveSession();
303
+ this.#listeners.get("session")?.(session, proof);
304
+ } else if (p.code === "RE_LOGIN_OK") {
305
+ const session = new WalletSession(conn);
306
+ session.permissionLevel = antelope.PermissionLevel.from(p.result.permission);
307
+ this.#listeners.get("session")?.(session);
308
+ }
309
+ });
310
+ }
311
+ };
312
+
313
+ exports.WalletSession = WalletSession;
314
+ exports.WindConnector = WindConnector;
315
+ //# sourceMappingURL=index.cjs.map
316
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/zlib.ts","../src/WalletSession.ts","../src/WindConnector.ts"],"names":["pako","SigningRequest","SignedTransaction","Signature","Checksum512","assertBrowser","Peer","Int64","Base64u","Serializer","IdentityProof","PermissionLevel"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as pako from 'pako'\n\nexport interface ZlibProvider {\n deflateRaw: (data: Uint8Array) => Uint8Array\n inflateRaw: (data: Uint8Array) => Uint8Array\n}\n\nexport const zlib: ZlibProvider = {\n deflateRaw: (data) => pako.deflateRaw(data),\n inflateRaw: (data) => pako.inflateRaw(data)\n}\n","import { SigningRequest } from '@wharfkit/signing-request'\nimport {\n Action,\n Checksum512,\n Name,\n PermissionLevel,\n PublicKey,\n Signature,\n SignedTransaction,\n Transaction,\n type SignedTransactionType\n} from '@wharfkit/antelope'\nimport { ABICache } from '@wharfkit/abicache'\nimport type { DataConnection } from 'peerjs'\nimport { zlib, type ZlibProvider } from './zlib'\n\ntype SendTxResponse = unknown\n\nexport interface TransactArguments {\n action?: Action\n actions?: Action[]\n transaction?: Transaction\n chainId?: string\n}\n\nexport interface TransactOptions {\n broadcast?: boolean\n}\n\ntype PendingCallback = (reply: unknown) => void\n\nfunction assertBrowser(): void {\n if (typeof window === 'undefined' || typeof crypto === 'undefined') {\n throw new Error('WalletSession requires browser environment (window/crypto).')\n }\n}\n\nexport class WalletSession {\n static readonly ChainID =\n 'f9f432b1851b5c179d2091a96f593aaed50ec7466b74f89301f957a83e56ce1f'\n\n #connection: DataConnection\n #callbacks: Map<string, PendingCallback>\n #encodingOptions?: { zlib: ZlibProvider; abiProvider?: ABICache }\n #permissionLevel?: PermissionLevel\n #closeListener?: () => void\n #errorListener?: (err: unknown) => void\n\n constructor(connection: DataConnection) {\n this.#connection = connection\n this.#callbacks = new Map()\n\n // peerjs types: (data: unknown) => void\n connection.on('data', (data: unknown) => this.#onDataReceived(data))\n connection.on('close', () => this.#closeListener?.())\n connection.on('error', (error) => this.#errorListener?.(error))\n }\n\n setABICache(cache: ABICache) {\n this.#encodingOptions = { zlib, abiProvider: cache }\n }\n\n onClose(listener: () => void) {\n this.#closeListener = listener\n }\n\n onError(listener: (err: unknown) => void) {\n this.#errorListener = listener\n }\n\n isOpen(): boolean {\n return Boolean(this.#connection.open)\n }\n\n close(): void {\n this.#connection.close()\n }\n\n get permissionLevel(): PermissionLevel | undefined {\n return this.#permissionLevel\n }\n set permissionLevel(value: PermissionLevel | undefined) {\n this.#permissionLevel = value\n }\n\n get actor(): Name | undefined {\n return this.#permissionLevel?.actor\n }\n\n get permission(): Name | undefined {\n return this.#permissionLevel?.permission\n }\n\n async transact(\n args: TransactArguments,\n options?: TransactOptions\n ): Promise<SignedTransaction | SendTxResponse> {\n assertBrowser()\n args.chainId = WalletSession.ChainID\n const willBroadcast = options?.broadcast ?? true\n\n const request = await SigningRequest.create(\n args,\n this.#encodingOptions ?? { zlib }\n )\n request.setBroadcast(willBroadcast)\n\n const vsr = request.encode(true, false, 'vsr:')\n return this.signingRequest(vsr)\n }\n\n signingRequest(vsr: string): Promise<SignedTransaction | SendTxResponse> {\n assertBrowser()\n const callback = crypto.randomUUID()\n const data = { method: 'signingRequest', id: callback, params: { vsr } }\n\n return new Promise((resolve, reject) => {\n const func: PendingCallback = (reply: unknown) => {\n const r = reply as { code: string; result?: unknown; error?: unknown }\n if (r.code === 'SENT') {\n resolve(r.result as SendTxResponse)\n } else if (r.code === 'SIGNED') {\n resolve(SignedTransaction.from(r.result as SignedTransactionType))\n } else {\n const err =\n typeof r.error === 'string'\n ? new Error(r.error)\n : (r.error as Error) ?? new Error('Unknown error')\n reject(err)\n }\n }\n this.#callbacks.set(callback, func)\n this.#connection.send(data)\n })\n }\n\n signMessage(message: string): Promise<Signature> {\n assertBrowser()\n const callback = crypto.randomUUID()\n const data = { method: 'signMessage', id: callback, params: { message } }\n\n return new Promise((resolve, reject) => {\n const func: PendingCallback = (reply: unknown) => {\n const r = reply as { code: string; result?: { signature: string }; error?: { message?: string } }\n if (r.code === 'SIGNED' && r.result?.signature) {\n resolve(Signature.from(r.result.signature))\n } else {\n reject(new Error(r.error?.message ?? 'Sign message failed'))\n }\n }\n this.#callbacks.set(callback, func)\n this.#connection.send(data)\n })\n }\n\n sharedSecret(publicKey: PublicKey): Promise<Checksum512> {\n assertBrowser()\n const callback = crypto.randomUUID()\n const data = {\n method: 'sharedSecret',\n id: callback,\n params: { key: publicKey.toString() }\n }\n\n return new Promise((resolve, reject) => {\n const func: PendingCallback = (reply: unknown) => {\n const r = reply as { code: string; result?: { secret: string }; error?: unknown }\n if (r.code === 'CREATED' && r.result?.secret) {\n resolve(Checksum512.from(r.result.secret))\n } else {\n reject(new Error(String(r.error ?? 'ECDH failed')))\n }\n }\n this.#callbacks.set(callback, func)\n this.#connection.send(data)\n })\n }\n\n // menerima unknown, lakukan narrowing di dalam\n #onDataReceived(data: unknown) {\n if (!data || typeof data !== 'object') return\n const maybe = data as { id?: string }\n if (!maybe.id || typeof maybe.id !== 'string') return\n const callback = this.#callbacks.get(maybe.id)\n if (callback) {\n callback(data)\n this.#callbacks.delete(maybe.id)\n }\n }\n}\n","import {\n Base64u,\n IdentityProof,\n SigningRequest,\n type SigningRequestCreateIdentityArguments\n} from '@wharfkit/signing-request'\nimport { Int64, PermissionLevel, Serializer } from '@wharfkit/antelope'\nimport { Peer, type DataConnection, type PeerOptions } from 'peerjs'\nimport { WalletSession } from './WalletSession'\nimport { zlib } from './zlib'\n\n/** Event yang didukung */\ntype WindConnectorEvent = 'open' | 'close' | 'disconnected' | 'error' | 'session'\n\ntype ListenerMap = Map<WindConnectorEvent | string, (...args: unknown[]) => void>\n\ninterface StoredSession {\n permission: string\n exp: number\n signature?: string\n domain: string\n peerId: string\n}\n\n/** Payload dari wallet saat koneksi pertama */\ninterface LoginOkPayload {\n code: 'LOGIN_OK'\n result: { auth: string; exp: number; signature?: string }\n}\n/** Payload dari wallet saat re-login (tanpa proof) */\ninterface ReLoginOkPayload {\n code: 'RE_LOGIN_OK'\n result: { permission: string }\n}\n\ntype IncomingPayload = LoginOkPayload | ReLoginOkPayload\n\nfunction assertBrowser(): void {\n if (typeof window === 'undefined' || typeof crypto === 'undefined') {\n throw new Error('WindConnector requires browser environment (window/crypto).')\n }\n}\n\nexport class WindConnector {\n #peer?: Peer\n #peerOptions: PeerOptions = {}\n #peerId?: string\n #listeners: ListenerMap = new Map()\n #session: Map<string, StoredSession> = new Map()\n\n /** Argumen identity yang sesuai typing @wharfkit */\n #identityArgs: SigningRequestCreateIdentityArguments = {\n chainId: WalletSession.ChainID,\n scope: 'vexanium',\n // beberapa versi typing menandai callback required; berikan placeholder\n callback: { url: '', background: false }\n }\n\n constructor() {\n this.#peerOptions.config = {\n iceServers: [\n { urls: 'stun:stun.l.google.com:19302' },\n { urls: 'stun:stun1.l.google.com:3478' },\n { urls: 'stun:stun.relay.metered.ca:80' },\n {\n urls: 'turn:asia.relay.metered.ca:80',\n username: 'b66cd40a117bddb5cde924ab',\n credential: '4jRmuTehVCZ2a/S+'\n }\n ],\n sdpSemantics: 'unified-plan'\n }\n this.#loadSession()\n }\n\n addIceServer(server: RTCIceServer) {\n if (!this.#peerOptions.config) this.#peerOptions.config = { iceServers: [] }\n ;(this.#peerOptions.config.iceServers as RTCIceServer[]).push(server)\n }\n\n setServer(host: string, port?: number) {\n this.#peerOptions.host = host\n if (typeof port === 'number') this.#peerOptions.port = port\n }\n\n /** Events: `open`, `close`, `disconnected`, `error`, `session` */\n on(event: WindConnectorEvent | string, func: (...args: unknown[]) => void) {\n this.#listeners.set(event, func)\n }\n\n async connect() {\n assertBrowser()\n if (!this.#peerId) throw new Error('Peer ID is not set')\n this.#peer = new Peer(this.#peerId, this.#peerOptions)\n this.#peer.on('connection', this.#onConnection.bind(this))\n this.#listeners.forEach((func, key) => this.#peer!.on(key as any, func))\n }\n\n disconnect() { this.#peer?.disconnect() }\n destroy() { this.#peer?.destroy() }\n reconnect() { this.#peer?.reconnect() }\n\n isDisconnected(): boolean { return Boolean(this.#peer?.disconnected) }\n isDestroyed(): boolean { return Boolean(this.#peer?.destroyed) }\n\n /**\n * Membuat VSR login untuk QR/URL.\n * @param name - App name\n * @param icon - Icon URL\n */\n createLoginRequest(name: string, icon: string): string {\n assertBrowser()\n const session = this.#getLastSession()\n if (session) {\n const [actor, perm] = session.permission.split('@')\n this.#identityArgs.account = actor\n this.#identityArgs.permission = perm\n this.#peerId = session.peerId\n } else {\n this.#peerId = `VEX-${crypto.randomUUID()}`\n // bersihkan akun/permission lama kalau ada\n delete this.#identityArgs.account\n delete this.#identityArgs.permission\n }\n\n const req = SigningRequest.identity(this.#identityArgs, { zlib })\n req.setInfoKey('pi', this.#peerId) // peer id\n req.setInfoKey('na', name) // app name\n req.setInfoKey('ic', icon) // icon url\n req.setInfoKey('do', window.location.origin) // domain origin\n\n if (session) {\n req.setInfoKey('exp', Int64.from(session.exp))\n if (session.signature) req.setInfoKey('sig', session.signature)\n }\n return req.encode(true, false, 'vsr:')\n }\n\n /** ===== internal helpers ===== */\n #getLastSession(): StoredSession | null {\n const domain = typeof window !== 'undefined' ? window.location.origin : ''\n if (!domain) return null\n const current = this.#session.get(domain)\n if (current && current.exp >= Date.now()) return current\n if (current) this.#session.delete(domain)\n return null\n }\n\n #addSession(permission: string, exp: number, signature?: string) {\n const domain = window.location.origin\n const peerId = this.#peerId ?? `VEX-${crypto.randomUUID()}`\n const current: StoredSession = { permission, exp, signature, domain, peerId }\n this.#session.set(domain, current)\n }\n\n #saveSession() {\n const data = Array.from(this.#session.values())\n sessionStorage.setItem('session', JSON.stringify(data))\n }\n\n #loadSession() {\n if (typeof window === 'undefined') return\n const raw = sessionStorage.getItem('session')\n if (!raw) return\n try {\n const data = JSON.parse(raw) as StoredSession[]\n for (const it of data) this.#session.set(it.domain, it)\n } catch {\n // corrupted storage → reset\n sessionStorage.removeItem('session')\n }\n }\n\n #onConnection(conn: DataConnection) {\n conn.once('data', (payload: unknown) => {\n const p = payload as IncomingPayload\n if (p.code === 'LOGIN_OK') {\n const auth = Base64u.decode(p.result.auth)\n const proof = Serializer.decode({ data: auth, type: IdentityProof })\n const session = new WalletSession(conn)\n session.permissionLevel = proof.signer\n\n this.#addSession(proof.signer.toString(), p.result.exp, p.result.signature)\n this.#saveSession()\n\n this.#listeners.get('session')?.(session, proof)\n } else if (p.code === 'RE_LOGIN_OK') {\n const session = new WalletSession(conn)\n session.permissionLevel = PermissionLevel.from(p.result.permission)\n this.#listeners.get('session')?.(session)\n }\n })\n }\n}\n"]}
@@ -0,0 +1,62 @@
1
+ import { PermissionLevel, Name, Action, Transaction, SignedTransaction, Signature, PublicKey, Checksum512 } from '@wharfkit/antelope';
2
+ import { ABICache } from '@wharfkit/abicache';
3
+ import { DataConnection } from 'peerjs';
4
+
5
+ /** Event yang didukung */
6
+ type WindConnectorEvent = 'open' | 'close' | 'disconnected' | 'error' | 'session';
7
+ declare class WindConnector {
8
+ #private;
9
+ constructor();
10
+ addIceServer(server: RTCIceServer): void;
11
+ setServer(host: string, port?: number): void;
12
+ /** Events: `open`, `close`, `disconnected`, `error`, `session` */
13
+ on(event: WindConnectorEvent | string, func: (...args: unknown[]) => void): void;
14
+ connect(): Promise<void>;
15
+ disconnect(): void;
16
+ destroy(): void;
17
+ reconnect(): void;
18
+ isDisconnected(): boolean;
19
+ isDestroyed(): boolean;
20
+ /**
21
+ * Membuat VSR login untuk QR/URL.
22
+ * @param name - App name
23
+ * @param icon - Icon URL
24
+ */
25
+ createLoginRequest(name: string, icon: string): string;
26
+ }
27
+
28
+ type SendTxResponse = unknown;
29
+ interface TransactArguments {
30
+ action?: Action;
31
+ actions?: Action[];
32
+ transaction?: Transaction;
33
+ chainId?: string;
34
+ }
35
+ interface TransactOptions {
36
+ broadcast?: boolean;
37
+ }
38
+ declare class WalletSession {
39
+ #private;
40
+ static readonly ChainID = "f9f432b1851b5c179d2091a96f593aaed50ec7466b74f89301f957a83e56ce1f";
41
+ constructor(connection: DataConnection);
42
+ setABICache(cache: ABICache): void;
43
+ onClose(listener: () => void): void;
44
+ onError(listener: (err: unknown) => void): void;
45
+ isOpen(): boolean;
46
+ close(): void;
47
+ get permissionLevel(): PermissionLevel | undefined;
48
+ set permissionLevel(value: PermissionLevel | undefined);
49
+ get actor(): Name | undefined;
50
+ get permission(): Name | undefined;
51
+ transact(args: TransactArguments, options?: TransactOptions): Promise<SignedTransaction | SendTxResponse>;
52
+ signingRequest(vsr: string): Promise<SignedTransaction | SendTxResponse>;
53
+ signMessage(message: string): Promise<Signature>;
54
+ sharedSecret(publicKey: PublicKey): Promise<Checksum512>;
55
+ }
56
+
57
+ interface ZlibProvider {
58
+ deflateRaw: (data: Uint8Array) => Uint8Array;
59
+ inflateRaw: (data: Uint8Array) => Uint8Array;
60
+ }
61
+
62
+ export { WalletSession, WindConnector, type ZlibProvider };
@@ -0,0 +1,62 @@
1
+ import { PermissionLevel, Name, Action, Transaction, SignedTransaction, Signature, PublicKey, Checksum512 } from '@wharfkit/antelope';
2
+ import { ABICache } from '@wharfkit/abicache';
3
+ import { DataConnection } from 'peerjs';
4
+
5
+ /** Event yang didukung */
6
+ type WindConnectorEvent = 'open' | 'close' | 'disconnected' | 'error' | 'session';
7
+ declare class WindConnector {
8
+ #private;
9
+ constructor();
10
+ addIceServer(server: RTCIceServer): void;
11
+ setServer(host: string, port?: number): void;
12
+ /** Events: `open`, `close`, `disconnected`, `error`, `session` */
13
+ on(event: WindConnectorEvent | string, func: (...args: unknown[]) => void): void;
14
+ connect(): Promise<void>;
15
+ disconnect(): void;
16
+ destroy(): void;
17
+ reconnect(): void;
18
+ isDisconnected(): boolean;
19
+ isDestroyed(): boolean;
20
+ /**
21
+ * Membuat VSR login untuk QR/URL.
22
+ * @param name - App name
23
+ * @param icon - Icon URL
24
+ */
25
+ createLoginRequest(name: string, icon: string): string;
26
+ }
27
+
28
+ type SendTxResponse = unknown;
29
+ interface TransactArguments {
30
+ action?: Action;
31
+ actions?: Action[];
32
+ transaction?: Transaction;
33
+ chainId?: string;
34
+ }
35
+ interface TransactOptions {
36
+ broadcast?: boolean;
37
+ }
38
+ declare class WalletSession {
39
+ #private;
40
+ static readonly ChainID = "f9f432b1851b5c179d2091a96f593aaed50ec7466b74f89301f957a83e56ce1f";
41
+ constructor(connection: DataConnection);
42
+ setABICache(cache: ABICache): void;
43
+ onClose(listener: () => void): void;
44
+ onError(listener: (err: unknown) => void): void;
45
+ isOpen(): boolean;
46
+ close(): void;
47
+ get permissionLevel(): PermissionLevel | undefined;
48
+ set permissionLevel(value: PermissionLevel | undefined);
49
+ get actor(): Name | undefined;
50
+ get permission(): Name | undefined;
51
+ transact(args: TransactArguments, options?: TransactOptions): Promise<SignedTransaction | SendTxResponse>;
52
+ signingRequest(vsr: string): Promise<SignedTransaction | SendTxResponse>;
53
+ signMessage(message: string): Promise<Signature>;
54
+ sharedSecret(publicKey: PublicKey): Promise<Checksum512>;
55
+ }
56
+
57
+ interface ZlibProvider {
58
+ deflateRaw: (data: Uint8Array) => Uint8Array;
59
+ inflateRaw: (data: Uint8Array) => Uint8Array;
60
+ }
61
+
62
+ export { WalletSession, WindConnector, type ZlibProvider };
package/dist/index.js ADDED
@@ -0,0 +1,293 @@
1
+ import { SigningRequest, Base64u, IdentityProof } from '@wharfkit/signing-request';
2
+ import { Int64, Serializer, PermissionLevel, SignedTransaction, Signature, Checksum512 } from '@wharfkit/antelope';
3
+ import { Peer } from 'peerjs';
4
+ import * as pako from 'pako';
5
+
6
+ // src/WindConnector.ts
7
+ var zlib = {
8
+ deflateRaw: (data) => pako.deflateRaw(data),
9
+ inflateRaw: (data) => pako.inflateRaw(data)
10
+ };
11
+
12
+ // src/WalletSession.ts
13
+ function assertBrowser() {
14
+ if (typeof window === "undefined" || typeof crypto === "undefined") {
15
+ throw new Error("WalletSession requires browser environment (window/crypto).");
16
+ }
17
+ }
18
+ var WalletSession = class _WalletSession {
19
+ static ChainID = "f9f432b1851b5c179d2091a96f593aaed50ec7466b74f89301f957a83e56ce1f";
20
+ #connection;
21
+ #callbacks;
22
+ #encodingOptions;
23
+ #permissionLevel;
24
+ #closeListener;
25
+ #errorListener;
26
+ constructor(connection) {
27
+ this.#connection = connection;
28
+ this.#callbacks = /* @__PURE__ */ new Map();
29
+ connection.on("data", (data) => this.#onDataReceived(data));
30
+ connection.on("close", () => this.#closeListener?.());
31
+ connection.on("error", (error) => this.#errorListener?.(error));
32
+ }
33
+ setABICache(cache) {
34
+ this.#encodingOptions = { zlib, abiProvider: cache };
35
+ }
36
+ onClose(listener) {
37
+ this.#closeListener = listener;
38
+ }
39
+ onError(listener) {
40
+ this.#errorListener = listener;
41
+ }
42
+ isOpen() {
43
+ return Boolean(this.#connection.open);
44
+ }
45
+ close() {
46
+ this.#connection.close();
47
+ }
48
+ get permissionLevel() {
49
+ return this.#permissionLevel;
50
+ }
51
+ set permissionLevel(value) {
52
+ this.#permissionLevel = value;
53
+ }
54
+ get actor() {
55
+ return this.#permissionLevel?.actor;
56
+ }
57
+ get permission() {
58
+ return this.#permissionLevel?.permission;
59
+ }
60
+ async transact(args, options) {
61
+ assertBrowser();
62
+ args.chainId = _WalletSession.ChainID;
63
+ const willBroadcast = options?.broadcast ?? true;
64
+ const request = await SigningRequest.create(
65
+ args,
66
+ this.#encodingOptions ?? { zlib }
67
+ );
68
+ request.setBroadcast(willBroadcast);
69
+ const vsr = request.encode(true, false, "vsr:");
70
+ return this.signingRequest(vsr);
71
+ }
72
+ signingRequest(vsr) {
73
+ assertBrowser();
74
+ const callback = crypto.randomUUID();
75
+ const data = { method: "signingRequest", id: callback, params: { vsr } };
76
+ return new Promise((resolve, reject) => {
77
+ const func = (reply) => {
78
+ const r = reply;
79
+ if (r.code === "SENT") {
80
+ resolve(r.result);
81
+ } else if (r.code === "SIGNED") {
82
+ resolve(SignedTransaction.from(r.result));
83
+ } else {
84
+ const err = typeof r.error === "string" ? new Error(r.error) : r.error ?? new Error("Unknown error");
85
+ reject(err);
86
+ }
87
+ };
88
+ this.#callbacks.set(callback, func);
89
+ this.#connection.send(data);
90
+ });
91
+ }
92
+ signMessage(message) {
93
+ assertBrowser();
94
+ const callback = crypto.randomUUID();
95
+ const data = { method: "signMessage", id: callback, params: { message } };
96
+ return new Promise((resolve, reject) => {
97
+ const func = (reply) => {
98
+ const r = reply;
99
+ if (r.code === "SIGNED" && r.result?.signature) {
100
+ resolve(Signature.from(r.result.signature));
101
+ } else {
102
+ reject(new Error(r.error?.message ?? "Sign message failed"));
103
+ }
104
+ };
105
+ this.#callbacks.set(callback, func);
106
+ this.#connection.send(data);
107
+ });
108
+ }
109
+ sharedSecret(publicKey) {
110
+ assertBrowser();
111
+ const callback = crypto.randomUUID();
112
+ const data = {
113
+ method: "sharedSecret",
114
+ id: callback,
115
+ params: { key: publicKey.toString() }
116
+ };
117
+ return new Promise((resolve, reject) => {
118
+ const func = (reply) => {
119
+ const r = reply;
120
+ if (r.code === "CREATED" && r.result?.secret) {
121
+ resolve(Checksum512.from(r.result.secret));
122
+ } else {
123
+ reject(new Error(String(r.error ?? "ECDH failed")));
124
+ }
125
+ };
126
+ this.#callbacks.set(callback, func);
127
+ this.#connection.send(data);
128
+ });
129
+ }
130
+ // menerima unknown, lakukan narrowing di dalam
131
+ #onDataReceived(data) {
132
+ if (!data || typeof data !== "object") return;
133
+ const maybe = data;
134
+ if (!maybe.id || typeof maybe.id !== "string") return;
135
+ const callback = this.#callbacks.get(maybe.id);
136
+ if (callback) {
137
+ callback(data);
138
+ this.#callbacks.delete(maybe.id);
139
+ }
140
+ }
141
+ };
142
+
143
+ // src/WindConnector.ts
144
+ function assertBrowser2() {
145
+ if (typeof window === "undefined" || typeof crypto === "undefined") {
146
+ throw new Error("WindConnector requires browser environment (window/crypto).");
147
+ }
148
+ }
149
+ var WindConnector = class {
150
+ #peer;
151
+ #peerOptions = {};
152
+ #peerId;
153
+ #listeners = /* @__PURE__ */ new Map();
154
+ #session = /* @__PURE__ */ new Map();
155
+ /** Argumen identity yang sesuai typing @wharfkit */
156
+ #identityArgs = {
157
+ chainId: WalletSession.ChainID,
158
+ scope: "vexanium",
159
+ // beberapa versi typing menandai callback required; berikan placeholder
160
+ callback: { url: "", background: false }
161
+ };
162
+ constructor() {
163
+ this.#peerOptions.config = {
164
+ iceServers: [
165
+ { urls: "stun:stun.l.google.com:19302" },
166
+ { urls: "stun:stun1.l.google.com:3478" },
167
+ { urls: "stun:stun.relay.metered.ca:80" },
168
+ {
169
+ urls: "turn:asia.relay.metered.ca:80",
170
+ username: "b66cd40a117bddb5cde924ab",
171
+ credential: "4jRmuTehVCZ2a/S+"
172
+ }
173
+ ],
174
+ sdpSemantics: "unified-plan"
175
+ };
176
+ this.#loadSession();
177
+ }
178
+ addIceServer(server) {
179
+ if (!this.#peerOptions.config) this.#peerOptions.config = { iceServers: [] };
180
+ this.#peerOptions.config.iceServers.push(server);
181
+ }
182
+ setServer(host, port) {
183
+ this.#peerOptions.host = host;
184
+ if (typeof port === "number") this.#peerOptions.port = port;
185
+ }
186
+ /** Events: `open`, `close`, `disconnected`, `error`, `session` */
187
+ on(event, func) {
188
+ this.#listeners.set(event, func);
189
+ }
190
+ async connect() {
191
+ assertBrowser2();
192
+ if (!this.#peerId) throw new Error("Peer ID is not set");
193
+ this.#peer = new Peer(this.#peerId, this.#peerOptions);
194
+ this.#peer.on("connection", this.#onConnection.bind(this));
195
+ this.#listeners.forEach((func, key) => this.#peer.on(key, func));
196
+ }
197
+ disconnect() {
198
+ this.#peer?.disconnect();
199
+ }
200
+ destroy() {
201
+ this.#peer?.destroy();
202
+ }
203
+ reconnect() {
204
+ this.#peer?.reconnect();
205
+ }
206
+ isDisconnected() {
207
+ return Boolean(this.#peer?.disconnected);
208
+ }
209
+ isDestroyed() {
210
+ return Boolean(this.#peer?.destroyed);
211
+ }
212
+ /**
213
+ * Membuat VSR login untuk QR/URL.
214
+ * @param name - App name
215
+ * @param icon - Icon URL
216
+ */
217
+ createLoginRequest(name, icon) {
218
+ assertBrowser2();
219
+ const session = this.#getLastSession();
220
+ if (session) {
221
+ const [actor, perm] = session.permission.split("@");
222
+ this.#identityArgs.account = actor;
223
+ this.#identityArgs.permission = perm;
224
+ this.#peerId = session.peerId;
225
+ } else {
226
+ this.#peerId = `VEX-${crypto.randomUUID()}`;
227
+ delete this.#identityArgs.account;
228
+ delete this.#identityArgs.permission;
229
+ }
230
+ const req = SigningRequest.identity(this.#identityArgs, { zlib });
231
+ req.setInfoKey("pi", this.#peerId);
232
+ req.setInfoKey("na", name);
233
+ req.setInfoKey("ic", icon);
234
+ req.setInfoKey("do", window.location.origin);
235
+ if (session) {
236
+ req.setInfoKey("exp", Int64.from(session.exp));
237
+ if (session.signature) req.setInfoKey("sig", session.signature);
238
+ }
239
+ return req.encode(true, false, "vsr:");
240
+ }
241
+ /** ===== internal helpers ===== */
242
+ #getLastSession() {
243
+ const domain = typeof window !== "undefined" ? window.location.origin : "";
244
+ if (!domain) return null;
245
+ const current = this.#session.get(domain);
246
+ if (current && current.exp >= Date.now()) return current;
247
+ if (current) this.#session.delete(domain);
248
+ return null;
249
+ }
250
+ #addSession(permission, exp, signature) {
251
+ const domain = window.location.origin;
252
+ const peerId = this.#peerId ?? `VEX-${crypto.randomUUID()}`;
253
+ const current = { permission, exp, signature, domain, peerId };
254
+ this.#session.set(domain, current);
255
+ }
256
+ #saveSession() {
257
+ const data = Array.from(this.#session.values());
258
+ sessionStorage.setItem("session", JSON.stringify(data));
259
+ }
260
+ #loadSession() {
261
+ if (typeof window === "undefined") return;
262
+ const raw = sessionStorage.getItem("session");
263
+ if (!raw) return;
264
+ try {
265
+ const data = JSON.parse(raw);
266
+ for (const it of data) this.#session.set(it.domain, it);
267
+ } catch {
268
+ sessionStorage.removeItem("session");
269
+ }
270
+ }
271
+ #onConnection(conn) {
272
+ conn.once("data", (payload) => {
273
+ const p = payload;
274
+ if (p.code === "LOGIN_OK") {
275
+ const auth = Base64u.decode(p.result.auth);
276
+ const proof = Serializer.decode({ data: auth, type: IdentityProof });
277
+ const session = new WalletSession(conn);
278
+ session.permissionLevel = proof.signer;
279
+ this.#addSession(proof.signer.toString(), p.result.exp, p.result.signature);
280
+ this.#saveSession();
281
+ this.#listeners.get("session")?.(session, proof);
282
+ } else if (p.code === "RE_LOGIN_OK") {
283
+ const session = new WalletSession(conn);
284
+ session.permissionLevel = PermissionLevel.from(p.result.permission);
285
+ this.#listeners.get("session")?.(session);
286
+ }
287
+ });
288
+ }
289
+ };
290
+
291
+ export { WalletSession, WindConnector };
292
+ //# sourceMappingURL=index.js.map
293
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/zlib.ts","../src/WalletSession.ts","../src/WindConnector.ts"],"names":["assertBrowser","SigningRequest","PermissionLevel"],"mappings":"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","file":"index.js","sourcesContent":["import * as pako from 'pako'\n\nexport interface ZlibProvider {\n deflateRaw: (data: Uint8Array) => Uint8Array\n inflateRaw: (data: Uint8Array) => Uint8Array\n}\n\nexport const zlib: ZlibProvider = {\n deflateRaw: (data) => pako.deflateRaw(data),\n inflateRaw: (data) => pako.inflateRaw(data)\n}\n","import { SigningRequest } from '@wharfkit/signing-request'\nimport {\n Action,\n Checksum512,\n Name,\n PermissionLevel,\n PublicKey,\n Signature,\n SignedTransaction,\n Transaction,\n type SignedTransactionType\n} from '@wharfkit/antelope'\nimport { ABICache } from '@wharfkit/abicache'\nimport type { DataConnection } from 'peerjs'\nimport { zlib, type ZlibProvider } from './zlib'\n\ntype SendTxResponse = unknown\n\nexport interface TransactArguments {\n action?: Action\n actions?: Action[]\n transaction?: Transaction\n chainId?: string\n}\n\nexport interface TransactOptions {\n broadcast?: boolean\n}\n\ntype PendingCallback = (reply: unknown) => void\n\nfunction assertBrowser(): void {\n if (typeof window === 'undefined' || typeof crypto === 'undefined') {\n throw new Error('WalletSession requires browser environment (window/crypto).')\n }\n}\n\nexport class WalletSession {\n static readonly ChainID =\n 'f9f432b1851b5c179d2091a96f593aaed50ec7466b74f89301f957a83e56ce1f'\n\n #connection: DataConnection\n #callbacks: Map<string, PendingCallback>\n #encodingOptions?: { zlib: ZlibProvider; abiProvider?: ABICache }\n #permissionLevel?: PermissionLevel\n #closeListener?: () => void\n #errorListener?: (err: unknown) => void\n\n constructor(connection: DataConnection) {\n this.#connection = connection\n this.#callbacks = new Map()\n\n // peerjs types: (data: unknown) => void\n connection.on('data', (data: unknown) => this.#onDataReceived(data))\n connection.on('close', () => this.#closeListener?.())\n connection.on('error', (error) => this.#errorListener?.(error))\n }\n\n setABICache(cache: ABICache) {\n this.#encodingOptions = { zlib, abiProvider: cache }\n }\n\n onClose(listener: () => void) {\n this.#closeListener = listener\n }\n\n onError(listener: (err: unknown) => void) {\n this.#errorListener = listener\n }\n\n isOpen(): boolean {\n return Boolean(this.#connection.open)\n }\n\n close(): void {\n this.#connection.close()\n }\n\n get permissionLevel(): PermissionLevel | undefined {\n return this.#permissionLevel\n }\n set permissionLevel(value: PermissionLevel | undefined) {\n this.#permissionLevel = value\n }\n\n get actor(): Name | undefined {\n return this.#permissionLevel?.actor\n }\n\n get permission(): Name | undefined {\n return this.#permissionLevel?.permission\n }\n\n async transact(\n args: TransactArguments,\n options?: TransactOptions\n ): Promise<SignedTransaction | SendTxResponse> {\n assertBrowser()\n args.chainId = WalletSession.ChainID\n const willBroadcast = options?.broadcast ?? true\n\n const request = await SigningRequest.create(\n args,\n this.#encodingOptions ?? { zlib }\n )\n request.setBroadcast(willBroadcast)\n\n const vsr = request.encode(true, false, 'vsr:')\n return this.signingRequest(vsr)\n }\n\n signingRequest(vsr: string): Promise<SignedTransaction | SendTxResponse> {\n assertBrowser()\n const callback = crypto.randomUUID()\n const data = { method: 'signingRequest', id: callback, params: { vsr } }\n\n return new Promise((resolve, reject) => {\n const func: PendingCallback = (reply: unknown) => {\n const r = reply as { code: string; result?: unknown; error?: unknown }\n if (r.code === 'SENT') {\n resolve(r.result as SendTxResponse)\n } else if (r.code === 'SIGNED') {\n resolve(SignedTransaction.from(r.result as SignedTransactionType))\n } else {\n const err =\n typeof r.error === 'string'\n ? new Error(r.error)\n : (r.error as Error) ?? new Error('Unknown error')\n reject(err)\n }\n }\n this.#callbacks.set(callback, func)\n this.#connection.send(data)\n })\n }\n\n signMessage(message: string): Promise<Signature> {\n assertBrowser()\n const callback = crypto.randomUUID()\n const data = { method: 'signMessage', id: callback, params: { message } }\n\n return new Promise((resolve, reject) => {\n const func: PendingCallback = (reply: unknown) => {\n const r = reply as { code: string; result?: { signature: string }; error?: { message?: string } }\n if (r.code === 'SIGNED' && r.result?.signature) {\n resolve(Signature.from(r.result.signature))\n } else {\n reject(new Error(r.error?.message ?? 'Sign message failed'))\n }\n }\n this.#callbacks.set(callback, func)\n this.#connection.send(data)\n })\n }\n\n sharedSecret(publicKey: PublicKey): Promise<Checksum512> {\n assertBrowser()\n const callback = crypto.randomUUID()\n const data = {\n method: 'sharedSecret',\n id: callback,\n params: { key: publicKey.toString() }\n }\n\n return new Promise((resolve, reject) => {\n const func: PendingCallback = (reply: unknown) => {\n const r = reply as { code: string; result?: { secret: string }; error?: unknown }\n if (r.code === 'CREATED' && r.result?.secret) {\n resolve(Checksum512.from(r.result.secret))\n } else {\n reject(new Error(String(r.error ?? 'ECDH failed')))\n }\n }\n this.#callbacks.set(callback, func)\n this.#connection.send(data)\n })\n }\n\n // menerima unknown, lakukan narrowing di dalam\n #onDataReceived(data: unknown) {\n if (!data || typeof data !== 'object') return\n const maybe = data as { id?: string }\n if (!maybe.id || typeof maybe.id !== 'string') return\n const callback = this.#callbacks.get(maybe.id)\n if (callback) {\n callback(data)\n this.#callbacks.delete(maybe.id)\n }\n }\n}\n","import {\n Base64u,\n IdentityProof,\n SigningRequest,\n type SigningRequestCreateIdentityArguments\n} from '@wharfkit/signing-request'\nimport { Int64, PermissionLevel, Serializer } from '@wharfkit/antelope'\nimport { Peer, type DataConnection, type PeerOptions } from 'peerjs'\nimport { WalletSession } from './WalletSession'\nimport { zlib } from './zlib'\n\n/** Event yang didukung */\ntype WindConnectorEvent = 'open' | 'close' | 'disconnected' | 'error' | 'session'\n\ntype ListenerMap = Map<WindConnectorEvent | string, (...args: unknown[]) => void>\n\ninterface StoredSession {\n permission: string\n exp: number\n signature?: string\n domain: string\n peerId: string\n}\n\n/** Payload dari wallet saat koneksi pertama */\ninterface LoginOkPayload {\n code: 'LOGIN_OK'\n result: { auth: string; exp: number; signature?: string }\n}\n/** Payload dari wallet saat re-login (tanpa proof) */\ninterface ReLoginOkPayload {\n code: 'RE_LOGIN_OK'\n result: { permission: string }\n}\n\ntype IncomingPayload = LoginOkPayload | ReLoginOkPayload\n\nfunction assertBrowser(): void {\n if (typeof window === 'undefined' || typeof crypto === 'undefined') {\n throw new Error('WindConnector requires browser environment (window/crypto).')\n }\n}\n\nexport class WindConnector {\n #peer?: Peer\n #peerOptions: PeerOptions = {}\n #peerId?: string\n #listeners: ListenerMap = new Map()\n #session: Map<string, StoredSession> = new Map()\n\n /** Argumen identity yang sesuai typing @wharfkit */\n #identityArgs: SigningRequestCreateIdentityArguments = {\n chainId: WalletSession.ChainID,\n scope: 'vexanium',\n // beberapa versi typing menandai callback required; berikan placeholder\n callback: { url: '', background: false }\n }\n\n constructor() {\n this.#peerOptions.config = {\n iceServers: [\n { urls: 'stun:stun.l.google.com:19302' },\n { urls: 'stun:stun1.l.google.com:3478' },\n { urls: 'stun:stun.relay.metered.ca:80' },\n {\n urls: 'turn:asia.relay.metered.ca:80',\n username: 'b66cd40a117bddb5cde924ab',\n credential: '4jRmuTehVCZ2a/S+'\n }\n ],\n sdpSemantics: 'unified-plan'\n }\n this.#loadSession()\n }\n\n addIceServer(server: RTCIceServer) {\n if (!this.#peerOptions.config) this.#peerOptions.config = { iceServers: [] }\n ;(this.#peerOptions.config.iceServers as RTCIceServer[]).push(server)\n }\n\n setServer(host: string, port?: number) {\n this.#peerOptions.host = host\n if (typeof port === 'number') this.#peerOptions.port = port\n }\n\n /** Events: `open`, `close`, `disconnected`, `error`, `session` */\n on(event: WindConnectorEvent | string, func: (...args: unknown[]) => void) {\n this.#listeners.set(event, func)\n }\n\n async connect() {\n assertBrowser()\n if (!this.#peerId) throw new Error('Peer ID is not set')\n this.#peer = new Peer(this.#peerId, this.#peerOptions)\n this.#peer.on('connection', this.#onConnection.bind(this))\n this.#listeners.forEach((func, key) => this.#peer!.on(key as any, func))\n }\n\n disconnect() { this.#peer?.disconnect() }\n destroy() { this.#peer?.destroy() }\n reconnect() { this.#peer?.reconnect() }\n\n isDisconnected(): boolean { return Boolean(this.#peer?.disconnected) }\n isDestroyed(): boolean { return Boolean(this.#peer?.destroyed) }\n\n /**\n * Membuat VSR login untuk QR/URL.\n * @param name - App name\n * @param icon - Icon URL\n */\n createLoginRequest(name: string, icon: string): string {\n assertBrowser()\n const session = this.#getLastSession()\n if (session) {\n const [actor, perm] = session.permission.split('@')\n this.#identityArgs.account = actor\n this.#identityArgs.permission = perm\n this.#peerId = session.peerId\n } else {\n this.#peerId = `VEX-${crypto.randomUUID()}`\n // bersihkan akun/permission lama kalau ada\n delete this.#identityArgs.account\n delete this.#identityArgs.permission\n }\n\n const req = SigningRequest.identity(this.#identityArgs, { zlib })\n req.setInfoKey('pi', this.#peerId) // peer id\n req.setInfoKey('na', name) // app name\n req.setInfoKey('ic', icon) // icon url\n req.setInfoKey('do', window.location.origin) // domain origin\n\n if (session) {\n req.setInfoKey('exp', Int64.from(session.exp))\n if (session.signature) req.setInfoKey('sig', session.signature)\n }\n return req.encode(true, false, 'vsr:')\n }\n\n /** ===== internal helpers ===== */\n #getLastSession(): StoredSession | null {\n const domain = typeof window !== 'undefined' ? window.location.origin : ''\n if (!domain) return null\n const current = this.#session.get(domain)\n if (current && current.exp >= Date.now()) return current\n if (current) this.#session.delete(domain)\n return null\n }\n\n #addSession(permission: string, exp: number, signature?: string) {\n const domain = window.location.origin\n const peerId = this.#peerId ?? `VEX-${crypto.randomUUID()}`\n const current: StoredSession = { permission, exp, signature, domain, peerId }\n this.#session.set(domain, current)\n }\n\n #saveSession() {\n const data = Array.from(this.#session.values())\n sessionStorage.setItem('session', JSON.stringify(data))\n }\n\n #loadSession() {\n if (typeof window === 'undefined') return\n const raw = sessionStorage.getItem('session')\n if (!raw) return\n try {\n const data = JSON.parse(raw) as StoredSession[]\n for (const it of data) this.#session.set(it.domain, it)\n } catch {\n // corrupted storage → reset\n sessionStorage.removeItem('session')\n }\n }\n\n #onConnection(conn: DataConnection) {\n conn.once('data', (payload: unknown) => {\n const p = payload as IncomingPayload\n if (p.code === 'LOGIN_OK') {\n const auth = Base64u.decode(p.result.auth)\n const proof = Serializer.decode({ data: auth, type: IdentityProof })\n const session = new WalletSession(conn)\n session.permissionLevel = proof.signer\n\n this.#addSession(proof.signer.toString(), p.result.exp, p.result.signature)\n this.#saveSession()\n\n this.#listeners.get('session')?.(session, proof)\n } else if (p.code === 'RE_LOGIN_OK') {\n const session = new WalletSession(conn)\n session.permissionLevel = PermissionLevel.from(p.result.permission)\n this.#listeners.get('session')?.(session)\n }\n })\n }\n}\n"]}
package/package.json CHANGED
@@ -1,15 +1,11 @@
1
1
  {
2
2
  "name": "windkit",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "A protocol for connecting Vexanium DApps to the Wind wallet, enabling secure communication and transaction signing.",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/windvex/windkit.git"
8
8
  },
9
- "main": "index.js",
10
- "scripts": {
11
- "test": "echo \"Error: no test specified\" && exit 1"
12
- },
13
9
  "keywords": [
14
10
  "cryptocurrency",
15
11
  "web3",
@@ -24,11 +20,42 @@
24
20
  ],
25
21
  "license": "MIT",
26
22
  "type": "module",
23
+ "main": "dist/index.cjs",
24
+ "module": "dist/index.js",
25
+ "types": "dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "import": {
29
+ "types": "./dist/index.d.ts",
30
+ "default": "./dist/index.js"
31
+ },
32
+ "require": {
33
+ "types": "./dist/index.d.ts",
34
+ "default": "./dist/index.cjs"
35
+ }
36
+ }
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "README.md",
41
+ "LICENSE"
42
+ ],
43
+ "scripts": {
44
+ "build": "tsup",
45
+ "clean": "rm -rf dist",
46
+ "prepublishOnly": "npm run clean && npm run build",
47
+ "test": "echo \"(no tests yet)\""
48
+ },
27
49
  "dependencies": {
28
50
  "@wharfkit/abicache": "^1.2.2",
29
51
  "@wharfkit/antelope": "^1.0.13",
30
52
  "@wharfkit/signing-request": "^3.2.0",
31
53
  "pako": "^2.1.0",
32
54
  "peerjs": "^1.5.4"
55
+ },
56
+ "devDependencies": {
57
+ "@types/pako": "^2.0.4",
58
+ "tsup": "^8.5.0",
59
+ "typescript": "^5.9.3"
33
60
  }
34
- }
61
+ }
package/index.js DELETED
@@ -1,4 +0,0 @@
1
- import { WindConnector } from "./src/WindConnector.js";
2
- import { WalletSession } from "./src/WalletSession.js";
3
-
4
- export { WindConnector, WalletSession };
@@ -1,246 +0,0 @@
1
- import { SigningRequest } from "@wharfkit/signing-request";
2
- import {
3
- Action,
4
- Checksum512,
5
- Name,
6
- PermissionLevel,
7
- PublicKey,
8
- Signature,
9
- SignedTransaction,
10
- Transaction
11
- } from "@wharfkit/antelope";
12
- import { ABICache } from "@wharfkit/abicache";
13
- import zlib from "pako";
14
-
15
- export class WalletSession {
16
- // Vexanium mainnet Chain ID (constant)
17
- static ChainID = "f9f432b1851b5c179d2091a96f593aaed50ec7466b74f89301f957a83e56ce1f";
18
-
19
- #connection;
20
- #callbacks;
21
- #encodingOptions;
22
- /**
23
- * @type {PermissionLevel}
24
- */
25
- #permissionLevel;
26
- #closeListener;
27
- #errorListener;
28
-
29
- /**
30
- * Wraps a DataConnection to communicate with the wallet.
31
- * @param {import('peerjs').DataConnection} connection
32
- */
33
- constructor(connection) {
34
- this.#connection = connection;
35
- this.#callbacks = new Map();
36
-
37
- connection.on("data", this.#onDataReceived.bind(this));
38
- connection.on("close", () => {
39
- if (this.#closeListener) this.#closeListener();
40
- });
41
- connection.on("error", (error) => {
42
- if (this.#errorListener) this.#errorListener(error);
43
- });
44
- }
45
-
46
- /**
47
- * Sets the ABI cache to use for request (de)serialization.
48
- * @param {ABICache} cache
49
- */
50
- setABICache(cache) {
51
- this.#encodingOptions = { zlib, abiProvider: cache };
52
- }
53
-
54
- /**
55
- * Registers a listener invoked when the wallet connection closes.
56
- * @param {() => void} listener
57
- */
58
- onClose(listener) {
59
- this.#closeListener = listener;
60
- }
61
-
62
- /**
63
- * Registers a listener invoked when a connection error occurs.
64
- * @param {(err: unknown) => void} listener
65
- */
66
- onError(listener) {
67
- this.#errorListener = listener;
68
- }
69
-
70
- /**
71
- * Indicates whether the wallet connection is still open.
72
- * @return {boolean}
73
- */
74
- isOpen() {
75
- return this.#connection.open;
76
- }
77
-
78
- /**
79
- * Closes the connection to the wallet.
80
- */
81
- close() {
82
- this.#connection.close();
83
- }
84
-
85
- /**
86
- * The active permission level granted by the wallet.
87
- * @return {PermissionLevel}
88
- */
89
- get permissionLevel() {
90
- return this.#permissionLevel;
91
- }
92
-
93
- /**
94
- * @param {PermissionLevel} value
95
- */
96
- set permissionLevel(value) {
97
- this.#permissionLevel = value;
98
- }
99
-
100
- /**
101
- * Convenience accessor for the actor name.
102
- * @return {Name}
103
- */
104
- get actor() {
105
- return this.#permissionLevel.actor;
106
- }
107
-
108
- /**
109
- * Convenience accessor for the permission name.
110
- * @return {Name}
111
- */
112
- get permission() {
113
- return this.#permissionLevel.permission;
114
- }
115
-
116
- /**
117
- * @typedef TransactArguments
118
- * @property {Action} [action] Single-action transaction
119
- * @property {Action[]} [actions] Multi-action transaction
120
- * @property {Transaction} [transaction] Fully-formed transaction
121
- */
122
-
123
- /**
124
- * @typedef TransactOptions
125
- * @property {boolean} [broadcast=true] If true, broadcast on-chain; otherwise sign only.
126
- */
127
-
128
- /**
129
- * Builds and sends a transaction request to the wallet.
130
- * @param {TransactArguments} args
131
- * @param {TransactOptions} [options]
132
- * @return {Promise<SignedTransaction|import('@wharfkit/antelope').SendTransactionResponse>}
133
- */
134
- async transact(args, options) {
135
- args.chainId = WalletSession.ChainID;
136
- const willBroadcast =
137
- options && typeof options.broadcast !== "undefined"
138
- ? options.broadcast
139
- : true;
140
-
141
- const request = await SigningRequest.create(args, this.#encodingOptions);
142
- request.setBroadcast(willBroadcast);
143
-
144
- const vsr = request.encode(true, false, "vsr:");
145
- return this.signingRequest(vsr);
146
- }
147
-
148
- /**
149
- * Sends a VSR (Vexanium Signing Request) to the wallet.
150
- * The wallet may broadcast the transaction immediately or return a signature only.
151
- * @param {string} vsr
152
- * @return {Promise<import('@wharfkit/antelope').SendTransactionResponse|SignedTransaction>}
153
- */
154
- signingRequest(vsr) {
155
- const callback = window.crypto.randomUUID();
156
- const data = {
157
- method: "signingRequest",
158
- id: callback,
159
- params: { vsr }
160
- };
161
-
162
- return new Promise((resolve, reject) => {
163
- const func = (reply) => {
164
- if (reply.code === "SENT") {
165
- resolve(reply.result);
166
- } else if (reply.code === "SIGNED") {
167
- resolve(SignedTransaction.from(reply.result));
168
- } else {
169
- // ERROR | REJECT
170
- if (typeof reply.error === "string") {
171
- reject(new Error(reply.error));
172
- } else {
173
- reject(reply.error);
174
- }
175
- }
176
- };
177
- this.#callbacks.set(callback, func);
178
- this.#connection.send(data);
179
- });
180
- }
181
-
182
- /**
183
- * Requests a signature for an arbitrary message.
184
- * @param {string} message The message to be signed
185
- * @return {Promise<Signature>}
186
- */
187
- signMessage(message) {
188
- const callback = window.crypto.randomUUID();
189
- const data = {
190
- method: "signMessage",
191
- id: callback,
192
- params: { message }
193
- };
194
-
195
- return new Promise((resolve, reject) => {
196
- const func = (reply) => {
197
- if (reply.code === "SIGNED") {
198
- resolve(Signature.from(reply.result.signature));
199
- } else {
200
- reject(new Error(reply.error.message));
201
- }
202
- };
203
- this.#callbacks.set(callback, func);
204
- this.#connection.send(data);
205
- });
206
- }
207
-
208
- /**
209
- * Derives a shared secret using ECDH with the wallet's key.
210
- * @param {PublicKey} publicKey
211
- * @return {Promise<Checksum512>}
212
- */
213
- sharedSecret(publicKey) {
214
- const callback = window.crypto.randomUUID();
215
- const data = {
216
- method: "sharedSecret",
217
- id: callback,
218
- params: { key: publicKey.toString() }
219
- };
220
-
221
- return new Promise((resolve, reject) => {
222
- const func = (reply) => {
223
- if (reply.code === "CREATED") {
224
- resolve(Checksum512.from(reply.result.secret));
225
- } else if (reply.code === "ERROR") {
226
- reject(new Error(reply.error));
227
- }
228
- };
229
- this.#callbacks.set(callback, func);
230
- this.#connection.send(data);
231
- });
232
- }
233
-
234
- /**
235
- * Handles incoming data from the wallet and resolves the pending callback.
236
- * @param {{ id: string }} data
237
- * @private
238
- */
239
- #onDataReceived(data) {
240
- const callback = this.#callbacks.get(data.id);
241
- if (callback) {
242
- callback(data);
243
- this.#callbacks.delete(data.id);
244
- }
245
- }
246
- }
@@ -1,199 +0,0 @@
1
- import { Base64u, IdentityProof, SigningRequest } from "@wharfkit/signing-request";
2
- import { Int64, PermissionLevel, Serializer } from "@wharfkit/antelope";
3
- import { Peer } from "peerjs";
4
- import zlib from "pako";
5
- import { WalletSession } from "./WalletSession.js";
6
-
7
- /**
8
- * Handles communication with the signaling server
9
- * and manages secure DApp ↔ Wallet sessions.
10
- */
11
- export class WindConnector {
12
- #peer;
13
- #peerOptions = {};
14
- #peerId;
15
- #listeners = new Map();
16
- #session = new Map();
17
- #identityArgs = {};
18
-
19
- constructor() {
20
- this.#peerOptions.config = {
21
- iceServers: [
22
- { urls: "stun:stun.l.google.com:19302" },
23
- { urls: "stun:stun1.l.google.com:3478" },
24
- { urls: "stun:stun.relay.metered.ca:80" },
25
- {
26
- urls: "turn:asia.relay.metered.ca:80",
27
- username: "b66cd40a117bddb5cde924ab",
28
- credential: "4jRmuTehVCZ2a/S+"
29
- }
30
- ],
31
- sdpSemantics: "unified-plan"
32
- };
33
- this.#identityArgs.scope = "vexanium";
34
- this.#identityArgs.chainId = WalletSession.ChainID;
35
- this.#loadSession();
36
- }
37
-
38
- /**
39
- * Adds an additional STUN or TURN server to the peer connection.
40
- * @param {RTCIceServer} server
41
- */
42
- addIceServer(server) {
43
- this.#peerOptions.config.iceServers.push(server);
44
- }
45
-
46
- /**
47
- * Sets the signaling server address and port.
48
- * @param {string} host
49
- * @param {number} [port]
50
- */
51
- setServer(host, port) {
52
- this.#peerOptions.host = host;
53
- if (port) this.#peerOptions.port = port;
54
- }
55
-
56
- /**
57
- * Registers a listener for specific peer events.
58
- * Supported events: `open`, `close`, `disconnected`, `error`, `session`
59
- * @param {string} event
60
- * @param {Function} func
61
- */
62
- on(event, func) {
63
- this.#listeners.set(event, func);
64
- }
65
-
66
- /**
67
- * Connects to the signaling server.
68
- * The wallet's response can be captured using the `session` event listener.
69
- *
70
- * @see on
71
- * @see createLoginRequest
72
- */
73
- async connect() {
74
- if (!this.#peerId) throw new Error("Peer ID is not set");
75
- this.#peer = new Peer(this.#peerId, this.#peerOptions);
76
- this.#peer.on("connection", this.#onConnection.bind(this));
77
- this.#listeners.forEach((func, key) => {
78
- this.#peer.on(key, func);
79
- });
80
- }
81
-
82
- disconnect() {
83
- this.#peer.disconnect();
84
- }
85
-
86
- destroy() {
87
- this.#peer.destroy();
88
- }
89
-
90
- reconnect() {
91
- this.#peer.reconnect();
92
- }
93
-
94
- isDisconnected() {
95
- return this.#peer.disconnected;
96
- }
97
-
98
- isDestroyed() {
99
- return this.#peer.destroyed;
100
- }
101
-
102
- /**
103
- * Creates a VSR (Vexanium Signing Request) for login.
104
- * @param {string} name - Application name
105
- * @param {string} icon - Application icon URL
106
- * @returns {string} Encoded VSR string for use in QR codes or query URLs
107
- */
108
- createLoginRequest(name, icon) {
109
- const session = this.#getLastSession();
110
- if (session) {
111
- const [actor, perm] = session.permission.split("@");
112
- this.#identityArgs.account = actor;
113
- this.#identityArgs.permission = perm;
114
- this.#peerId = session.peerId;
115
- } else {
116
- // Generate a new peer ID
117
- this.#peerId = `VEX-${window.crypto.randomUUID()}`;
118
- }
119
- let req = SigningRequest.identity(this.#identityArgs, { zlib });
120
- req.setInfoKey("pi", this.#peerId);
121
- req.setInfoKey("na", name);
122
- req.setInfoKey("ic", icon);
123
- req.setInfoKey("do", window.location.origin);
124
- if (session) {
125
- req.setInfoKey("exp", Int64.from(session.exp));
126
- req.setInfoKey("sig", session.signature);
127
- }
128
- return req.encode(true, false, "vsr:");
129
- }
130
-
131
- #getLastSession() {
132
- const domain = window.location.origin;
133
- let current = this.#session.get(domain);
134
- if (current && current.exp < Date.now()) { // Expired
135
- this.#session.delete(domain);
136
- current = null;
137
- }
138
- return current;
139
- }
140
-
141
- #addSession(permission, exp, signature) {
142
- const domain = window.location.origin;
143
- let current = this.#session.get(domain);
144
- if (current) {
145
- current.permission = permission;
146
- current.exp = exp;
147
- current.signature = signature;
148
- } else {
149
- current = {
150
- permission, exp, signature, domain, peerId: this.#peerId
151
- };
152
- }
153
- this.#session.set(domain, current);
154
- }
155
-
156
- #saveSession() {
157
- const data = Array.from(this.#session.values());
158
- sessionStorage.setItem("session", JSON.stringify(data));
159
- }
160
-
161
- #loadSession() {
162
- const raw = sessionStorage.getItem("session");
163
- if (raw) {
164
- let data = JSON.parse(raw);
165
- data.forEach(it => {
166
- this.#session.set(it.domain, it);
167
- });
168
- }
169
- }
170
-
171
- /**
172
- * Handles incoming peer connections from the wallet.
173
- * @param {DataConnection} conn
174
- * @private
175
- */
176
- #onConnection(conn) {
177
- conn.once("data", payload => {
178
- if (payload.code === 'LOGIN_OK') {
179
- const auth = Base64u.decode(payload.result.auth);
180
- const proof = Serializer.decode({ data: auth, type: IdentityProof });
181
- const session = new WalletSession(conn);
182
- session.permissionLevel = proof.signer;
183
-
184
- // Store session
185
- this.#addSession(proof.signer.toString(), payload.result.exp, payload.result.signature);
186
- this.#saveSession();
187
-
188
- const func = this.#listeners.get("session");
189
- if (func) func(session, proof);
190
- } else if (payload.code === 'RE_LOGIN_OK') {
191
- const session = new WalletSession(conn);
192
- session.permissionLevel = PermissionLevel.from(payload.result.permission);
193
-
194
- const func = this.#listeners.get("session");
195
- if (func) func(session); // Only one parameter for re-login
196
- }
197
- });
198
- }
199
- }