windkit 0.2.1 → 0.2.3

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/CHANGELOG.md ADDED
@@ -0,0 +1,91 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ This project follows [Semantic Versioning](https://semver.org/).
6
+
7
+ ---
8
+
9
+ ## [0.2.3] - 2026-03-02
10
+
11
+ Published: 2026-03-02T14:07:04Z
12
+
13
+ ### Changed
14
+
15
+ - Session storage key standardized to `"vex-session"`.
16
+ - Login identity payload compacted with standardized keys:
17
+ - `pi` (peer id)
18
+ - `na` (app name)
19
+ - `ic` (icon)
20
+ - `do` (origin)
21
+ - optional `auth` (cached identity proof)
22
+ - RPC method names standardized:
23
+ - `signRequest`
24
+ - `signMessage`
25
+ - `sharedSecret`
26
+
27
+ ### Added
28
+
29
+ - `clearSession()` helper for manual session reset.
30
+ - Smart session reuse:
31
+ - Reuses stored `peerID`
32
+ - Reuses permission hints (`account@permission`) when available.
33
+
34
+ ### Fixed
35
+
36
+ - Hardened session loader:
37
+ - Automatically clears expired or malformed session payloads.
38
+ - Improved disconnect cleanup:
39
+ - Safe destroy/disconnect (best-effort, non-throwing).
40
+
41
+ ### Improved
42
+
43
+ - Optimized for low-memory environments:
44
+ - Lightweight heartbeat with jitter
45
+ - Reduced message routing allocations
46
+ - Lower background CPU usage on mobile devices
47
+
48
+ ---
49
+
50
+ ## [0.2.1] - 2025-10-13
51
+
52
+ Published: 2025-10-13T16:28:38Z
53
+
54
+ ### Added
55
+
56
+ - PeerJS signaling support.
57
+ - Session persistence via `sessionStorage`.
58
+ - Transaction signing via Vexanium Signing Request (VSR).
59
+ - Message signing support.
60
+ - Shared secret derivation (ECDH).
61
+
62
+ ---
63
+
64
+ ## [0.2.0] - 2025-10-06
65
+
66
+ Published: 2025-10-06T14:44:23Z
67
+
68
+ ### Added
69
+
70
+ - Structured WebRTC connection lifecycle.
71
+ - WalletSession abstraction layer.
72
+ - Basic login flow via embedded PeerID inside VSR.
73
+ - Request/response routing via internal request IDs.
74
+
75
+ ### Improved
76
+
77
+ - More predictable session initialization flow.
78
+ - Internal protocol normalization groundwork.
79
+
80
+ ---
81
+
82
+ ## [0.1.1] - 2025-08-12
83
+
84
+ Published: 2025-08-12T01:33:25Z
85
+
86
+ ### Added
87
+
88
+ - Initial public release of WindKit.
89
+ - Basic VSR identity login.
90
+ - WebRTC DataConnection integration.
91
+ - Minimal transaction signing flow.
package/README.md CHANGED
@@ -2,82 +2,301 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/windkit.svg)](https://www.npmjs.com/package/windkit)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
5
- A protocol to connect Vexanium DApps to the Wind wallet.
6
5
 
7
- ## Features
6
+ WindKit is a lightweight WebRTC protocol for connecting Vexanium DApps to Wind Wallet using PeerJS and WharfKit Signing Requests (VSR).
7
+
8
+ It enables secure cross-device login and transaction signing without requiring browser extensions.
9
+
10
+ Designed for production environments, including low-RAM mobile devices.
11
+
12
+ ---
13
+
14
+ ## ✨ Features
15
+
8
16
  - Cross-device login via VSR (Vexanium Signing Request)
9
- - Transaction signing (single or multiple actions)
17
+ - Transaction signing (single action, multiple actions, or full transaction)
18
+ - Optional broadcast control (sign-only or broadcast)
10
19
  - Message signing
11
- - Shared secret (ECDH) for encryption
20
+ - Shared secret derivation (ECDH)
21
+ - Session persistence via `sessionStorage`
22
+ - Low-memory heartbeat strategy
23
+ - Pure ESM module (JavaScript-only)
24
+
25
+ ---
26
+
27
+ ## 📦 Installation
28
+
29
+ ```bash
30
+ npm install windkit
31
+ ```
32
+
33
+ WindKit is **ESM-only**.
34
+
35
+ Your project must include:
36
+
37
+ ```json
38
+ {
39
+ "type": "module"
40
+ }
41
+ ```
12
42
 
13
- ## Initialize the Connector
14
- ```javascript
43
+ ---
44
+
45
+ ## 🚀 Quick Start
46
+
47
+ ### Create Connector
48
+
49
+ ```js
15
50
  import { WindConnector } from "windkit";
16
51
 
17
52
  const connector = new WindConnector();
18
- connector.on("session", onSession); // fires after wallet approves login
53
+
54
+ connector.on("session", (session, proof) => {
55
+ console.log("Connected as:", session.permissionLevel?.toString());
56
+ });
57
+
19
58
  await connector.connect();
20
59
  ```
21
60
 
22
- ## Create a Login Request and Open the Wallet
23
- ```javascript
24
- // Build a VSR and deep-link / QR it to the wallet
25
- const vsr = connector.createLoginRequest("Vexanium DApp", "https://example.com/icon.png");
26
- const request = vsr.split(":")[1];
61
+ By default, WindKit uses PeerJS default signaling.
62
+
63
+ ---
64
+
65
+ ## 🌐 Custom PeerJS Server (Optional)
27
66
 
28
- // Open Wind Wallet login (adjust the URL/host as needed)
29
- const walletUrl = `https://windwallet.app/login?vsr=${request}`;
30
- window.open(walletUrl, "Wind Wallet");
67
+ ```js
68
+ connector.setServer("peer.yourdomain.com", 443, "/", true);
31
69
  ```
32
70
 
33
- ## Receive a WalletSession
34
- ```javascript
35
- import { ABICache } from "@wharfkit/abicache";
71
+ Signature:
36
72
 
37
- const abiCache = new ABICache({/* optional custom fetch */});
73
+ ```js
74
+ setServer(host, port, path, secure);
75
+ ```
38
76
 
39
- function onSession(session, proof) {
40
- // Optional on first login: verify IdentityProof as needed
41
- const account = proof?.signer?.toString?.(); // e.g., "userxyz@active"
77
+ Add custom ICE server:
42
78
 
43
- session.setABICache(abiCache); // faster ABI (de)serialization
44
- session.onClose(() => console.log("Disconnected from wallet"));
45
-
46
- // Store for later use
47
- Store.session = session;
48
- }
79
+ ```js
80
+ connector.addIceServer({
81
+ urls: "stun:stun.cloudflare.com:3478"
82
+ });
49
83
  ```
50
84
 
51
- ## Send a Transaction
52
- ```javascript
85
+ ---
86
+
87
+ ## 🔐 Login Flow (VSR)
88
+
89
+ ```js
90
+ const vsr = connector.createLoginRequest(
91
+ "My Vexanium DApp",
92
+ "https://example.com/icon.png"
93
+ );
94
+
95
+ const payload = vsr.startsWith("vsr:") ? vsr.slice(4) : vsr;
96
+
97
+ window.open(
98
+ `https://wallet.windcrypto.com/login?vsr=${encodeURIComponent(payload)}`,
99
+ "Wind Wallet"
100
+ );
101
+ ```
102
+
103
+ Wallet flow:
104
+
105
+ 1. Decode VSR
106
+ 2. Connect to embedded PeerID
107
+ 3. Send `LOGIN_OK`
108
+ 4. Emit session
109
+
110
+ ---
111
+
112
+ ## 🔄 Session Handling
113
+
114
+ ```js
115
+ connector.on("session", (session, proof) => {
116
+ session.onClose(() => {
117
+ console.log("Wallet disconnected");
118
+ });
119
+
120
+ session.onError((error) => {
121
+ console.error("Session error:", error);
122
+ });
123
+
124
+ window.appSession = session;
125
+ });
126
+ ```
127
+
128
+ ---
129
+
130
+ ## ✍️ Send Transaction
131
+
132
+ ### With ABI Cache (Recommended)
133
+
134
+ ```js
53
135
  import { Action } from "@wharfkit/antelope";
136
+ import { ABICache } from "@wharfkit/abicache";
137
+
138
+ const abiCache = new ABICache();
139
+ appSession.setABICache(abiCache);
54
140
 
55
- // Example: transfer VEX
56
141
  const abi = await abiCache.getAbi("vex.token");
57
- const data = {
58
- from: "aiueo",
59
- to: "babibu",
60
- quantity: "1.0000 VEX",
61
- memo: "test transfer"
62
- };
63
142
 
64
143
  const action = Action.from(
65
144
  {
66
145
  account: "vex.token",
67
146
  name: "transfer",
68
- data,
69
- authorization: [Store.session.permissionLevel]
147
+ data: {
148
+ from: "alice",
149
+ to: "bob",
150
+ quantity: "1.0000 VEX",
151
+ memo: "WindKit test"
152
+ },
153
+ authorization: [appSession.permissionLevel]
70
154
  },
71
155
  abi
72
156
  );
73
157
 
74
- // By default, transact() broadcasts. Set { broadcast: false } to sign only.
75
- const result = await Store.session.transact({ action });
76
- // result is either SendTransactionResponse (broadcast) or SignedTransaction (sign-only)
158
+ const result = await appSession.transact({ action });
159
+
77
160
  console.log(result.transaction_id ?? result.id);
78
161
  ```
79
162
 
80
- > Notes
81
- > - Class names: `WindConnector` (connector) and `WalletSession` (active session).
82
- > - Chain ID is handled internally by `WalletSession.ChainID` (Vexanium mainnet).
83
- > - For re-login, the `session` event may be called without `proof` (use `session.permissionLevel`).
163
+ ---
164
+
165
+ ### Sign Only (No Broadcast)
166
+
167
+ ```js
168
+ await appSession.transact(
169
+ { action },
170
+ { broadcast: false }
171
+ );
172
+ ```
173
+
174
+ ---
175
+
176
+ ## 📝 Sign Message
177
+
178
+ ```js
179
+ const signature = await appSession.signMessage("Hello Wind!");
180
+ console.log(signature.toString());
181
+ ```
182
+
183
+ ---
184
+
185
+ ## 🔑 Shared Secret (ECDH)
186
+
187
+ ```js
188
+ import { PublicKey } from "@wharfkit/antelope";
189
+
190
+ const pub = PublicKey.from("PUB_K1_...");
191
+ const secret = await appSession.sharedSecret(pub);
192
+
193
+ console.log(secret.toString());
194
+ ```
195
+
196
+ ---
197
+
198
+ ## 💾 Session Storage
199
+
200
+ WindKit stores session data in:
201
+
202
+ ```js
203
+ sessionStorage["vex-session"]
204
+ ```
205
+
206
+ Example structure:
207
+
208
+ ```json
209
+ {
210
+ "peerID": "VEX-xxxx",
211
+ "permission": "account@active",
212
+ "expiration": "2026-03-01T12:00:00",
213
+ "auth": "base64u_identity_proof"
214
+ }
215
+ ```
216
+
217
+ Clear session manually:
218
+
219
+ ```js
220
+ import { clearSession } from "windkit";
221
+
222
+ clearSession();
223
+ ```
224
+
225
+ ---
226
+
227
+ ## 🏗 Architecture
228
+
229
+ ### WindConnector
230
+
231
+ - Creates VSR identity login
232
+ - Hosts PeerJS PeerID (DApp-side)
233
+ - Waits for wallet connection
234
+ - Emits session
235
+
236
+ ### WalletSession
237
+
238
+ - Sends:
239
+ - `signRequest`
240
+ - `signMessage`
241
+ - `sharedSecret`
242
+ - Routes replies via request IDs
243
+ - Lightweight heartbeat ping
244
+ - Handles account change events
245
+
246
+ ---
247
+
248
+ ## 🔎 Protocol Notes
249
+
250
+ Transaction signing method:
251
+
252
+ ```
253
+ signRequest
254
+ ```
255
+
256
+ Wallet push events handled:
257
+
258
+ ```
259
+ LOGIN_OK
260
+ ACTIVE_ACCOUNT_CHANGED
261
+ ```
262
+
263
+ All communication occurs over PeerJS `DataConnection`.
264
+
265
+ ---
266
+
267
+ ## ⚙ Technical Details
268
+
269
+ Chain ID is internally fixed via:
270
+
271
+ ```js
272
+ WalletSession.ChainID
273
+ ```
274
+
275
+ Dependencies:
276
+
277
+ - `@wharfkit/signing-request`
278
+ - `@wharfkit/antelope`
279
+ - `peerjs`
280
+ - `pako`
281
+
282
+ Optimized for:
283
+
284
+ - Low-RAM mobile devices
285
+ - Background browser tabs
286
+ - Unstable WebRTC networks
287
+
288
+ ---
289
+
290
+ ## 🔐 Security Model
291
+
292
+ - IdentityProof can be verified by the DApp (recommended).
293
+ - Private keys never leave the wallet.
294
+ - VSR ensures transaction integrity.
295
+ - PeerID is embedded inside the VSR payload to prevent misrouting.
296
+
297
+ ---
298
+
299
+ ## 📄 License
300
+
301
+ MIT License
302
+ © Wind Stack
package/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { WindConnector } from "./src/WindConnector.js";
2
+ export { WalletSession } from "./src/WalletSession.js";
3
+ export { saveSession, loadSession, clearSession } from "./src/StoreSession.js";
package/package.json CHANGED
@@ -1,61 +1,59 @@
1
1
  {
2
2
  "name": "windkit",
3
- "version": "0.2.1",
4
- "description": "A protocol for connecting Vexanium DApps to the Wind wallet, enabling secure communication and transaction signing.",
3
+ "version": "0.2.3",
4
+ "description": "Lightweight protocol to connect Vexanium DApps to Wind Wallet via PeerJS and VSR.",
5
+ "license": "MIT",
6
+ "author": "windstack",
7
+ "type": "module",
8
+ "main": "./index.js",
9
+ "exports": {
10
+ ".": "./index.js"
11
+ },
12
+ "files": [
13
+ "index.js",
14
+ "src/**",
15
+ "README.md",
16
+ "CHANGELOG.md",
17
+ "LICENSE"
18
+ ],
5
19
  "repository": {
6
20
  "type": "git",
7
21
  "url": "git+https://github.com/windvex/windkit.git"
8
22
  },
23
+ "bugs": {
24
+ "url": "https://github.com/windvex/windkit/issues"
25
+ },
26
+ "homepage": "https://github.com/windvex/windkit#readme",
9
27
  "keywords": [
10
- "cryptocurrency",
11
- "web3",
12
- "dapp",
13
- "walletconnect",
14
- "windkit",
15
- "web-rtc",
16
- "peerjs",
17
28
  "vexanium",
18
29
  "vex",
30
+ "wind",
31
+ "wallet",
32
+ "web3",
33
+ "peerjs",
34
+ "webrtc",
35
+ "wharfkit",
36
+ "signing-request",
37
+ "vsr",
19
38
  "blockchain"
20
39
  ],
21
- "license": "MIT",
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
- }
40
+ "sideEffects": false,
41
+ "publishConfig": {
42
+ "access": "public"
37
43
  },
38
- "files": [
39
- "dist",
40
- "README.md",
41
- "LICENSE"
42
- ],
43
44
  "scripts": {
44
- "build": "tsup",
45
- "clean": "rm -rf dist",
46
- "prepublishOnly": "npm run clean && npm run build",
47
- "test": "echo \"(no tests yet)\""
45
+ "test": "node -e \"console.log('windkit ok')\"",
46
+ "pack:check": "npm pack --dry-run",
47
+ "publish:npm": "npm run pack:check && npm publish --access public"
48
48
  },
49
49
  "dependencies": {
50
50
  "@wharfkit/abicache": "^1.2.2",
51
- "@wharfkit/antelope": "^1.0.13",
51
+ "@wharfkit/antelope": "^1.1.1",
52
52
  "@wharfkit/signing-request": "^3.2.0",
53
53
  "pako": "^2.1.0",
54
- "peerjs": "^1.5.4"
54
+ "peerjs": "^1.5.5"
55
55
  },
56
- "devDependencies": {
57
- "@types/pako": "^2.0.4",
58
- "tsup": "^8.5.0",
59
- "typescript": "^5.9.3"
56
+ "engines": {
57
+ "node": ">=18"
60
58
  }
61
- }
59
+ }
@@ -0,0 +1,103 @@
1
+ // windkit/StoreSession.js
2
+ // Ultra Clean++ (single replace)
3
+ // ✅ sessionStorage SSOT for pairing
4
+ // ✅ auto-clear invalid/expired
5
+ // ✅ safe storage guards (private mode / SSR)
6
+
7
+ import { TimePointSec } from "@wharfkit/antelope";
8
+
9
+ const KEY = "vex-session";
10
+
11
+ function hasSessionStorage() {
12
+ try {
13
+ return typeof sessionStorage !== "undefined" && sessionStorage != null;
14
+ } catch {
15
+ return false;
16
+ }
17
+ }
18
+
19
+ /**
20
+ * @typedef {Object} StoredSession
21
+ * @property {string} peerID
22
+ * @property {string} permission // "account@active"
23
+ * @property {string|TimePointSec} expiration
24
+ * @property {string} auth // Base64u IdentityProof payload
25
+ */
26
+
27
+ export function saveSession(data) {
28
+ if (!hasSessionStorage()) return;
29
+
30
+ const exp =
31
+ typeof data?.expiration === "string"
32
+ ? data.expiration
33
+ : data?.expiration?.toString?.() ?? String(data?.expiration ?? "");
34
+
35
+ const payload = {
36
+ peerID: String(data?.peerID || ""),
37
+ permission: String(data?.permission || ""),
38
+ expiration: String(exp || ""),
39
+ auth: String(data?.auth || ""),
40
+ };
41
+
42
+ try {
43
+ sessionStorage.setItem(KEY, JSON.stringify(payload));
44
+ } catch {
45
+ // ignore (quota/private mode)
46
+ }
47
+ }
48
+
49
+ export function clearSession() {
50
+ if (!hasSessionStorage()) return;
51
+ try {
52
+ sessionStorage.removeItem(KEY);
53
+ } catch {
54
+ // ignore
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Load session from sessionStorage (auto-clears if invalid/expired).
60
+ * @returns {null | {peerID:string, permission:string, expiration:TimePointSec, auth:string}}
61
+ */
62
+ export function loadSession() {
63
+ if (!hasSessionStorage()) return null;
64
+
65
+ let raw = "";
66
+ try {
67
+ raw = sessionStorage.getItem(KEY) || "";
68
+ } catch {
69
+ return null;
70
+ }
71
+ if (!raw) return null;
72
+
73
+ try {
74
+ const data = JSON.parse(raw);
75
+ if (!data || typeof data !== "object") {
76
+ clearSession();
77
+ return null;
78
+ }
79
+
80
+ const peerID = String(data.peerID || "");
81
+ const permission = String(data.permission || "");
82
+ const auth = String(data.auth || "");
83
+ const expRaw = String(data.expiration || "");
84
+
85
+ if (!peerID || !permission || !auth || !expRaw) {
86
+ clearSession();
87
+ return null;
88
+ }
89
+
90
+ const expiration = TimePointSec.fromString(expRaw);
91
+ const expMs = expiration.toDate().getTime();
92
+
93
+ if (!Number.isFinite(expMs) || expMs <= Date.now()) {
94
+ clearSession();
95
+ return null;
96
+ }
97
+
98
+ return { peerID, permission, expiration, auth };
99
+ } catch {
100
+ clearSession();
101
+ return null;
102
+ }
103
+ }