windkit 0.2.0 → 0.2.2
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 +54 -0
- package/README.md +224 -49
- package/index.js +3 -0
- package/package.json +39 -41
- package/src/StoreSession.js +103 -0
- package/src/WalletSession.js +375 -0
- package/src/WindConnector.js +294 -0
- package/dist/index.cjs +0 -316
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -62
- package/dist/index.d.ts +0 -62
- package/dist/index.js +0 -293
- package/dist/index.js.map +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
This project follows Semantic Versioning.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## [0.2.2] - 2026-03-02
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Session storage key standardized to `"vex-session"`.
|
|
14
|
+
- Login identity request now stores compact app info keys:
|
|
15
|
+
- `pi` (peer id), `na` (app name), `ic` (icon), `do` (origin), optional `auth` (cached proof).
|
|
16
|
+
- Request method names standardized:
|
|
17
|
+
- `signRequest`, `signMessage`, `sharedSecret`.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- `clearSession()` helper.
|
|
22
|
+
- Session reuse:
|
|
23
|
+
- Reuses saved `peerID` and hints (`account@permission`) when present.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- Safer session loading (auto-clears invalid or expired payloads).
|
|
28
|
+
- Improved cleanup on disconnect (best-effort destroy/disconnect).
|
|
29
|
+
|
|
30
|
+
### Improved
|
|
31
|
+
|
|
32
|
+
- Low-memory friendly behavior:
|
|
33
|
+
- Lightweight heartbeat/ping with jitter (best-effort).
|
|
34
|
+
- Minimal allocations on message routing.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## [0.2.1]
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- Initial PeerJS signaling support.
|
|
43
|
+
- Session persistence via sessionStorage.
|
|
44
|
+
- Transaction signing via VSR.
|
|
45
|
+
- Message signing.
|
|
46
|
+
- Shared secret (ECDH).
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## [0.1.1]
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- Initial public release of WindKit.
|
package/README.md
CHANGED
|
@@ -2,82 +2,257 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/windkit)
|
|
4
4
|
[](LICENSE)
|
|
5
|
-
|
|
5
|
+
|
|
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
|
+
---
|
|
6
11
|
|
|
7
12
|
## Features
|
|
13
|
+
|
|
8
14
|
- Cross-device login via VSR (Vexanium Signing Request)
|
|
9
|
-
- Transaction signing (single
|
|
15
|
+
- Transaction signing (single action, multiple actions, or full transaction)
|
|
16
|
+
- Optional broadcast (sign-only or broadcast)
|
|
10
17
|
- Message signing
|
|
11
|
-
- Shared secret (ECDH)
|
|
18
|
+
- Shared secret derivation (ECDH)
|
|
19
|
+
- Session persistence via sessionStorage
|
|
20
|
+
- Lightweight keepalive (low memory footprint)
|
|
21
|
+
- Pure ESM module
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
npm install windkit
|
|
28
|
+
|
|
29
|
+
WindKit is ESM-only.
|
|
30
|
+
|
|
31
|
+
Your project must use:
|
|
32
|
+
|
|
33
|
+
{
|
|
34
|
+
"type": "module"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
### Create Connector
|
|
12
42
|
|
|
13
|
-
## Initialize the Connector
|
|
14
|
-
```javascript
|
|
15
43
|
import { WindConnector } from "windkit";
|
|
16
44
|
|
|
17
45
|
const connector = new WindConnector();
|
|
18
|
-
|
|
46
|
+
|
|
47
|
+
connector.on("session", (session, proof) => {
|
|
48
|
+
console.log("Connected as:", session.permissionLevel?.toString());
|
|
49
|
+
});
|
|
50
|
+
|
|
19
51
|
await connector.connect();
|
|
20
|
-
```
|
|
21
52
|
|
|
22
|
-
|
|
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];
|
|
53
|
+
By default, WindKit relies on PeerJS default signaling behavior (no host/port/path/secure configured).
|
|
27
54
|
|
|
28
|
-
|
|
29
|
-
const walletUrl = `https://windwallet.app/login?vsr=${request}`;
|
|
30
|
-
window.open(walletUrl, "Wind Wallet");
|
|
31
|
-
```
|
|
55
|
+
---
|
|
32
56
|
|
|
33
|
-
|
|
34
|
-
```javascript
|
|
35
|
-
import { ABICache } from "@wharfkit/abicache";
|
|
57
|
+
### Use Your Own PeerJS Server (Optional)
|
|
36
58
|
|
|
37
|
-
|
|
59
|
+
connector.setServer("peer.yourdomain.com", 443, "/", true);
|
|
38
60
|
|
|
39
|
-
|
|
40
|
-
// Optional on first login: verify IdentityProof as needed
|
|
41
|
-
const account = proof?.signer?.toString?.(); // e.g., "userxyz@active"
|
|
61
|
+
Signature:
|
|
42
62
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
63
|
+
setServer(host, port, path, secure)
|
|
64
|
+
|
|
65
|
+
Add custom STUN/TURN server:
|
|
66
|
+
|
|
67
|
+
connector.addIceServer({
|
|
68
|
+
urls: "stun:stun.cloudflare.com:3478"
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Login Flow (VSR)
|
|
74
|
+
|
|
75
|
+
const vsr = connector.createLoginRequest(
|
|
76
|
+
"My Vexanium DApp",
|
|
77
|
+
"https://example.com/icon.png"
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const payload = vsr.startsWith("vsr:") ? vsr.slice(4) : vsr;
|
|
81
|
+
|
|
82
|
+
window.open(
|
|
83
|
+
`https://wallet.windcrypto.com/login?vsr=${encodeURIComponent(payload)}`,
|
|
84
|
+
"Wind Wallet"
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
Wallet flow:
|
|
88
|
+
|
|
89
|
+
1. Decode VSR
|
|
90
|
+
2. Connect to embedded PeerID
|
|
91
|
+
3. Send LOGIN_OK
|
|
92
|
+
4. Emit session
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Session Handling
|
|
97
|
+
|
|
98
|
+
connector.on("session", (session, proof) => {
|
|
99
|
+
|
|
100
|
+
session.onClose(() => {
|
|
101
|
+
console.log("Wallet disconnected");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
session.onError((error) => {
|
|
105
|
+
console.error("Session error:", error);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
window.appSession = session;
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Send Transaction
|
|
114
|
+
|
|
115
|
+
### With ABI Cache (Recommended)
|
|
50
116
|
|
|
51
|
-
## Send a Transaction
|
|
52
|
-
```javascript
|
|
53
117
|
import { Action } from "@wharfkit/antelope";
|
|
118
|
+
import { ABICache } from "@wharfkit/abicache";
|
|
119
|
+
|
|
120
|
+
const abiCache = new ABICache();
|
|
121
|
+
appSession.setABICache(abiCache);
|
|
54
122
|
|
|
55
|
-
// Example: transfer VEX
|
|
56
123
|
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
124
|
|
|
64
125
|
const action = Action.from(
|
|
65
126
|
{
|
|
66
127
|
account: "vex.token",
|
|
67
128
|
name: "transfer",
|
|
68
|
-
data
|
|
69
|
-
|
|
129
|
+
data: {
|
|
130
|
+
from: "alice",
|
|
131
|
+
to: "bob",
|
|
132
|
+
quantity: "1.0000 VEX",
|
|
133
|
+
memo: "test"
|
|
134
|
+
},
|
|
135
|
+
authorization: [appSession.permissionLevel]
|
|
70
136
|
},
|
|
71
137
|
abi
|
|
72
138
|
);
|
|
73
139
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// result is either SendTransactionResponse (broadcast) or SignedTransaction (sign-only)
|
|
140
|
+
const result = await appSession.transact({ action });
|
|
141
|
+
|
|
77
142
|
console.log(result.transaction_id ?? result.id);
|
|
78
|
-
```
|
|
79
143
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### Sign Only (No Broadcast)
|
|
147
|
+
|
|
148
|
+
await appSession.transact(
|
|
149
|
+
{ action },
|
|
150
|
+
{ broadcast: false }
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Sign Message
|
|
156
|
+
|
|
157
|
+
const signature = await appSession.signMessage("Hello Wind!");
|
|
158
|
+
console.log(signature.toString());
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Shared Secret (ECDH)
|
|
163
|
+
|
|
164
|
+
import { PublicKey } from "@wharfkit/antelope";
|
|
165
|
+
|
|
166
|
+
const pub = PublicKey.from("PUB_K1_...");
|
|
167
|
+
const secret = await appSession.sharedSecret(pub);
|
|
168
|
+
|
|
169
|
+
console.log(secret.toString());
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Session Storage
|
|
174
|
+
|
|
175
|
+
WindKit stores session data in:
|
|
176
|
+
|
|
177
|
+
sessionStorage["vex-session"]
|
|
178
|
+
|
|
179
|
+
Example structure:
|
|
180
|
+
|
|
181
|
+
{
|
|
182
|
+
"peerID": "VEX-xxxx",
|
|
183
|
+
"permission": "account@active",
|
|
184
|
+
"expiration": "2026-03-01T12:00:00",
|
|
185
|
+
"auth": "base64u_identity_proof"
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
To clear session manually:
|
|
189
|
+
|
|
190
|
+
import { clearSession } from "windkit";
|
|
191
|
+
|
|
192
|
+
clearSession();
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Architecture
|
|
197
|
+
|
|
198
|
+
WindConnector
|
|
199
|
+
- Creates VSR identity login
|
|
200
|
+
- Hosts PeerJS PeerID (DApp-side)
|
|
201
|
+
- Waits for wallet connection
|
|
202
|
+
- Emits session
|
|
203
|
+
|
|
204
|
+
WalletSession
|
|
205
|
+
- Sends:
|
|
206
|
+
- signRequest
|
|
207
|
+
- signMessage
|
|
208
|
+
- sharedSecret
|
|
209
|
+
- Routes replies via request IDs
|
|
210
|
+
- Lightweight keepalive ping
|
|
211
|
+
- Handles account change events
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Protocol Notes
|
|
216
|
+
|
|
217
|
+
Transaction signing method name:
|
|
218
|
+
"signRequest"
|
|
219
|
+
|
|
220
|
+
Wallet push events handled:
|
|
221
|
+
LOGIN_OK
|
|
222
|
+
ACTIVE_ACCOUNT_CHANGED
|
|
223
|
+
|
|
224
|
+
All communication occurs via PeerJS DataConnection.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Technical Details
|
|
229
|
+
|
|
230
|
+
Chain ID is fixed internally via:
|
|
231
|
+
WalletSession.ChainID
|
|
232
|
+
|
|
233
|
+
Uses:
|
|
234
|
+
- @wharfkit/signing-request
|
|
235
|
+
- @wharfkit/antelope
|
|
236
|
+
- peerjs
|
|
237
|
+
- pako (zlib compression)
|
|
238
|
+
|
|
239
|
+
Designed for:
|
|
240
|
+
- Low-RAM mobile devices
|
|
241
|
+
- Background tabs
|
|
242
|
+
- Unstable WebRTC environments
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Security Model
|
|
247
|
+
|
|
248
|
+
- IdentityProof can be verified by the DApp (recommended).
|
|
249
|
+
- Private keys never leave the wallet.
|
|
250
|
+
- VSR ensures transaction integrity.
|
|
251
|
+
- PeerID is embedded inside VSR to prevent misrouting.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## License
|
|
256
|
+
|
|
257
|
+
MIT License
|
|
258
|
+
© Wind Stack
|
package/index.js
ADDED
package/package.json
CHANGED
|
@@ -1,61 +1,59 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "windkit",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.2",
|
|
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
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
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
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
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.
|
|
51
|
+
"@wharfkit/antelope": "^1.1.1",
|
|
52
52
|
"@wharfkit/signing-request": "^3.2.0",
|
|
53
53
|
"pako": "^2.1.0",
|
|
54
|
-
"peerjs": "^1.5.
|
|
54
|
+
"peerjs": "^1.5.5"
|
|
55
55
|
},
|
|
56
|
-
"
|
|
57
|
-
"
|
|
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
|
+
}
|