@vielzeug/mesh 26.11.12 → 26.11.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/guest.cjs +1 -1
- package/dist/guest.cjs.map +1 -1
- package/dist/guest.d.ts.map +1 -1
- package/dist/guest.js +55 -54
- package/dist/guest.js.map +1 -1
- package/dist/mesh.cjs +1 -1
- package/dist/mesh.cjs.map +1 -1
- package/dist/mesh.iife.js +1 -1
- package/dist/mesh.iife.js.map +1 -1
- package/dist/mesh.js +72 -72
- package/dist/mesh.js.map +1 -1
- package/package.json +2 -2
package/dist/mesh.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { base64UrlToText as e, bytesToBase64Url as t, randomFloat as n, tapper as r, textToBase64Url as i,
|
|
1
|
+
import { base64UrlToText as e, bytesToBase64Url as t, randomFloat as n, tapper as r, textToBase64Url as i, timer as a, utf8Bytes as o } from "@vielzeug/arsenal";
|
|
2
2
|
// src/errors.ts
|
|
3
3
|
var MeshError = class extends Error {
|
|
4
4
|
constructor(e, t) {
|
|
@@ -29,7 +29,7 @@ function parsePairingPayload(e) {
|
|
|
29
29
|
if (isInvitation(e) || isAnswer(e)) return e;
|
|
30
30
|
throw new MeshPairingError("Unrecognized pairing payload shape");
|
|
31
31
|
}
|
|
32
|
-
var
|
|
32
|
+
var s = {
|
|
33
33
|
decode(t) {
|
|
34
34
|
let n;
|
|
35
35
|
try {
|
|
@@ -145,8 +145,8 @@ function createMessenger(e) {
|
|
|
145
145
|
reject(i, "malformed");
|
|
146
146
|
return;
|
|
147
147
|
}
|
|
148
|
-
let
|
|
149
|
-
if (
|
|
148
|
+
let a = o(r);
|
|
149
|
+
if (a > e.maxMessageBytes) {
|
|
150
150
|
reject(i, "too-large");
|
|
151
151
|
return;
|
|
152
152
|
}
|
|
@@ -172,7 +172,7 @@ function createMessenger(e) {
|
|
|
172
172
|
return;
|
|
173
173
|
}
|
|
174
174
|
e.emitTap({
|
|
175
|
-
bytes:
|
|
175
|
+
bytes: a,
|
|
176
176
|
messageType: c.t,
|
|
177
177
|
peerId: i,
|
|
178
178
|
type: "message-received"
|
|
@@ -201,7 +201,7 @@ function createMessenger(e) {
|
|
|
201
201
|
sendTo(t, n, r) {
|
|
202
202
|
let i = t.dc;
|
|
203
203
|
if (!i || i.readyState !== "open" || t.status !== "connected") throw new MeshConnectionError(`Peer "${t.id}" is not connected`, t.id);
|
|
204
|
-
let
|
|
204
|
+
let a = {
|
|
205
205
|
id: randomId(e.random),
|
|
206
206
|
p: r,
|
|
207
207
|
t: n,
|
|
@@ -209,11 +209,11 @@ function createMessenger(e) {
|
|
|
209
209
|
v: 1
|
|
210
210
|
}, s;
|
|
211
211
|
try {
|
|
212
|
-
s = JSON.stringify(
|
|
212
|
+
s = JSON.stringify(a);
|
|
213
213
|
} catch (e) {
|
|
214
214
|
throw new MeshPayloadError(`Failed to serialize message "${n}"`, { cause: e });
|
|
215
215
|
}
|
|
216
|
-
let c =
|
|
216
|
+
let c = o(s);
|
|
217
217
|
if (c > e.maxMessageBytes) throw new MeshPayloadError(`Message "${n}" is ${c} bytes (max ${e.maxMessageBytes})`);
|
|
218
218
|
try {
|
|
219
219
|
i.send(s);
|
|
@@ -290,7 +290,7 @@ async function createProof(e, n) {
|
|
|
290
290
|
return t(new Uint8Array(o));
|
|
291
291
|
}
|
|
292
292
|
// src/_rtc.ts
|
|
293
|
-
var
|
|
293
|
+
var c = { createPeerConnection(e) {
|
|
294
294
|
let t = globalThis.RTCPeerConnection;
|
|
295
295
|
if (!t) throw new MeshUnsupportedError("WebRTC is unavailable in this environment: inject an `rtc` factory");
|
|
296
296
|
return new t(e);
|
|
@@ -328,79 +328,81 @@ function waitChannelOpen(e, t, n, r, i) {
|
|
|
328
328
|
}
|
|
329
329
|
// src/guest.ts
|
|
330
330
|
function createMeshGuest(e = {}) {
|
|
331
|
-
let t = e.rtc ??
|
|
331
|
+
let t = e.rtc ?? c, n = e.clock ?? (() => Date.now()), r = e.maxMessageBytes ?? 65536, i = e.channelOpenTimeoutMs ?? 6e4, o = e.iceGatheringTimeoutMs ?? 5e3, s = createNodeCore(e.signal), l = createMessenger({
|
|
332
332
|
clock: n,
|
|
333
|
-
emitTap:
|
|
333
|
+
emitTap: s.emitTap,
|
|
334
334
|
maxMessageBytes: r,
|
|
335
335
|
random: e.random
|
|
336
|
-
}),
|
|
336
|
+
}), u = null, d = a(() => {
|
|
337
|
+
u?.status === "connecting" && failPeer(u, openTimeoutError());
|
|
338
|
+
}), openTimeoutError = () => new MeshTimeoutError(`Timed out waiting ${i}ms for the data channel to open`);
|
|
337
339
|
function failPeer(e, t) {
|
|
338
|
-
|
|
340
|
+
s.disposed || e !== u || e.status === "failed" || (e.status = "failed", d.cancel(), setTimeout(() => {
|
|
339
341
|
e.dc?.close(), e.pc?.close();
|
|
340
|
-
}, 0),
|
|
342
|
+
}, 0), s.emitTap({
|
|
341
343
|
peerId: e.id,
|
|
342
344
|
status: "failed",
|
|
343
345
|
type: "peer-status-change"
|
|
344
|
-
}),
|
|
346
|
+
}), s.emitTap({
|
|
345
347
|
error: t,
|
|
346
348
|
type: "error"
|
|
347
|
-
}),
|
|
349
|
+
}), s.emitTap({
|
|
348
350
|
peer: e.publicPeer,
|
|
349
351
|
reason: t.message,
|
|
350
352
|
type: "peer-left"
|
|
351
|
-
}),
|
|
353
|
+
}), s.setStatus("failed"));
|
|
352
354
|
}
|
|
353
355
|
function disconnectPeer(e, t) {
|
|
354
|
-
|
|
356
|
+
s.disposed || e !== u || e.status !== "disconnected" && e.status !== "failed" && (e.status = "disconnected", e.pc?.close(), s.emitTap({
|
|
355
357
|
peerId: e.id,
|
|
356
358
|
status: "disconnected",
|
|
357
359
|
type: "peer-status-change"
|
|
358
|
-
}),
|
|
360
|
+
}), s.emitTap({
|
|
359
361
|
peer: e.publicPeer,
|
|
360
362
|
reason: t,
|
|
361
363
|
type: "peer-left"
|
|
362
|
-
}),
|
|
364
|
+
}), s.setStatus("disconnected"));
|
|
363
365
|
}
|
|
364
366
|
function wireChannel(e, t, n) {
|
|
365
367
|
e.dc = n, n.addEventListener("open", () => {
|
|
366
|
-
|
|
368
|
+
s.disposed || (d.cancel(), e.status = "connected", s.emitTap({
|
|
367
369
|
peerId: e.id,
|
|
368
370
|
status: "connected",
|
|
369
371
|
type: "peer-status-change"
|
|
370
|
-
}),
|
|
372
|
+
}), s.emitTap({
|
|
371
373
|
peer: e.publicPeer,
|
|
372
374
|
type: "peer-joined"
|
|
373
|
-
}),
|
|
375
|
+
}), s.setStatus("connected"));
|
|
374
376
|
}), n.addEventListener("message", (t) => {
|
|
375
|
-
|
|
377
|
+
s.disposed || l.handleInbound(e, t.data);
|
|
376
378
|
}), n.addEventListener("close", () => {
|
|
377
|
-
|
|
379
|
+
s.disposed || (e.status === "connecting" ? failPeer(e, d.pending ? openTimeoutError() : new MeshConnectionError("channel closed before opening", e.id)) : disconnectPeer(e, "channel closed"));
|
|
378
380
|
}), n.addEventListener("error", () => {
|
|
379
|
-
|
|
381
|
+
s.disposed || failPeer(e, new MeshConnectionError("channel error", e.id));
|
|
380
382
|
}), t.addEventListener("iceconnectionstatechange", () => {
|
|
381
|
-
if (
|
|
383
|
+
if (s.disposed) return;
|
|
382
384
|
let n = t.iceConnectionState;
|
|
383
385
|
n === "failed" || n === "closed" ? failPeer(e, new MeshConnectionError(`ice ${n}`, e.id)) : n === "disconnected" && e.status === "connected" && disconnectPeer(e, "ice disconnected");
|
|
384
386
|
});
|
|
385
387
|
}
|
|
386
388
|
return {
|
|
387
|
-
async acceptInvitation(r,
|
|
388
|
-
if (
|
|
389
|
+
async acceptInvitation(r, a) {
|
|
390
|
+
if (s.ensureLive(), u && u.status !== "failed" && u.status !== "disconnected") throw new MeshPairingError("Guest is already paired");
|
|
389
391
|
if (r?.v !== 1) throw new MeshPairingError("Unsupported invitation version");
|
|
390
392
|
if (n() >= r.expiresAt) throw new MeshPairingError("Invitation expired");
|
|
391
|
-
|
|
393
|
+
u &&= (d.cancel(), u.pc?.close(), null), s.setStatus("pairing");
|
|
392
394
|
let c;
|
|
393
395
|
try {
|
|
394
396
|
c = t.createPeerConnection({ iceServers: [...e.iceServers ?? []] });
|
|
395
397
|
} catch (e) {
|
|
396
|
-
throw
|
|
398
|
+
throw s.setStatus("idle"), e;
|
|
397
399
|
}
|
|
398
|
-
let
|
|
399
|
-
|
|
400
|
-
wireChannel(
|
|
400
|
+
let l = createPeerRecord(r.sessionId, r.hostName, "host");
|
|
401
|
+
l.pc = c, u = l, c.addEventListener("datachannel", (e) => {
|
|
402
|
+
wireChannel(l, c, e.channel);
|
|
401
403
|
}), c.addEventListener("iceconnectionstatechange", () => {
|
|
402
|
-
|
|
403
|
-
peerId:
|
|
404
|
+
s.disposed || s.emitTap({
|
|
405
|
+
peerId: l.id,
|
|
404
406
|
state: c.iceConnectionState,
|
|
405
407
|
type: "ice-state"
|
|
406
408
|
});
|
|
@@ -411,28 +413,26 @@ function createMeshGuest(e = {}) {
|
|
|
411
413
|
type: "offer"
|
|
412
414
|
});
|
|
413
415
|
} catch (e) {
|
|
414
|
-
throw
|
|
416
|
+
throw u = null, s.setStatus("idle"), new MeshPairingError("Invalid invitation SDP", { cause: e });
|
|
415
417
|
}
|
|
416
418
|
let f;
|
|
417
419
|
try {
|
|
418
|
-
await c.setLocalDescription(await c.createAnswer()), await waitIceGathering(c,
|
|
420
|
+
await c.setLocalDescription(await c.createAnswer()), await waitIceGathering(c, o), f = c.localDescription?.sdp ?? "";
|
|
419
421
|
} catch (e) {
|
|
420
|
-
throw
|
|
422
|
+
throw u = null, c.close(), s.setStatus("idle"), new MeshConnectionError("Failed to create answer", null, { cause: e });
|
|
421
423
|
}
|
|
422
|
-
if (
|
|
423
|
-
if (!f) throw
|
|
424
|
+
if (s.disposed) throw c.close(), new MeshDisposedError();
|
|
425
|
+
if (!f) throw u = null, c.close(), s.setStatus("idle"), new MeshConnectionError("Local description has no SDP");
|
|
424
426
|
let p = randomId(e.random), m;
|
|
425
427
|
try {
|
|
426
428
|
m = await createProof(r.secret, f);
|
|
427
429
|
} catch (e) {
|
|
428
|
-
throw
|
|
430
|
+
throw u = null, c.close(), s.setStatus("idle"), e;
|
|
429
431
|
}
|
|
430
|
-
return
|
|
431
|
-
|
|
432
|
-
}, i), {
|
|
433
|
-
peer: s?.name === void 0 ? { id: p } : {
|
|
432
|
+
return s.setStatus("connecting"), d.arm(i), {
|
|
433
|
+
peer: a?.name === void 0 ? { id: p } : {
|
|
434
434
|
id: p,
|
|
435
|
-
name:
|
|
435
|
+
name: a.name
|
|
436
436
|
},
|
|
437
437
|
proof: m,
|
|
438
438
|
sdp: f,
|
|
@@ -441,29 +441,29 @@ function createMeshGuest(e = {}) {
|
|
|
441
441
|
};
|
|
442
442
|
},
|
|
443
443
|
get disposalSignal() {
|
|
444
|
-
return
|
|
444
|
+
return s.disposalCtrl.signal;
|
|
445
445
|
},
|
|
446
446
|
dispose() {
|
|
447
|
-
|
|
447
|
+
s.disposed || (s.markDisposed(), d.cancel(), u && (u.dc?.close(), u.pc?.close()), l.clear());
|
|
448
448
|
},
|
|
449
449
|
get disposed() {
|
|
450
|
-
return
|
|
450
|
+
return s.disposed;
|
|
451
451
|
},
|
|
452
452
|
get host() {
|
|
453
|
-
return
|
|
453
|
+
return u?.publicPeer ?? null;
|
|
454
454
|
},
|
|
455
455
|
on(e, t) {
|
|
456
|
-
return
|
|
456
|
+
return s.ensureLive(), l.on(e, t);
|
|
457
457
|
},
|
|
458
458
|
send(e, t) {
|
|
459
|
-
if (
|
|
460
|
-
|
|
459
|
+
if (s.ensureLive(), !u) throw new MeshConnectionError("Guest is not paired");
|
|
460
|
+
l.sendTo(u, e, t);
|
|
461
461
|
},
|
|
462
462
|
get status() {
|
|
463
|
-
return
|
|
463
|
+
return s.status;
|
|
464
464
|
},
|
|
465
465
|
tap(e, t) {
|
|
466
|
-
return
|
|
466
|
+
return s.tap(e, t);
|
|
467
467
|
},
|
|
468
468
|
[Symbol.dispose]() {
|
|
469
469
|
this.dispose();
|
|
@@ -472,7 +472,7 @@ function createMeshGuest(e = {}) {
|
|
|
472
472
|
}
|
|
473
473
|
// src/host.ts
|
|
474
474
|
function createMeshHost(e = {}) {
|
|
475
|
-
let n = e.rtc ??
|
|
475
|
+
let n = e.rtc ?? c, r = e.clock ?? (() => Date.now()), i = e.maxMessageBytes ?? 65536, a = e.invitationTtlMs ?? 3e5, o = e.channelOpenTimeoutMs ?? 6e4, s = e.iceGatheringTimeoutMs ?? 5e3, l = {
|
|
476
476
|
label: "mesh",
|
|
477
477
|
ordered: !0,
|
|
478
478
|
...e.channel
|
|
@@ -585,12 +585,12 @@ function createMeshHost(e = {}) {
|
|
|
585
585
|
},
|
|
586
586
|
async createInvitation(i) {
|
|
587
587
|
u.ensureLive();
|
|
588
|
-
let o = n.createPeerConnection({ iceServers: [...e.iceServers ?? []] }),
|
|
588
|
+
let o = n.createPeerConnection({ iceServers: [...e.iceServers ?? []] }), c = o.createDataChannel(l.label, {
|
|
589
589
|
maxRetransmits: l.maxRetransmits,
|
|
590
590
|
ordered: l.ordered
|
|
591
591
|
}), d = randomId(e.random), f = t(randomBytes(32, e.random)), m = r() + a;
|
|
592
592
|
try {
|
|
593
|
-
await o.setLocalDescription(await o.createOffer()), await waitIceGathering(o,
|
|
593
|
+
await o.setLocalDescription(await o.createOffer()), await waitIceGathering(o, s);
|
|
594
594
|
} catch (e) {
|
|
595
595
|
throw o.close(), new MeshConnectionError("Failed to create offer", null, { cause: e });
|
|
596
596
|
}
|
|
@@ -600,7 +600,7 @@ function createMeshHost(e = {}) {
|
|
|
600
600
|
let g = setTimeout(() => expireInvitation(d), a);
|
|
601
601
|
return p.set(d, {
|
|
602
602
|
answered: !1,
|
|
603
|
-
dc:
|
|
603
|
+
dc: c,
|
|
604
604
|
expiresAt: m,
|
|
605
605
|
expiryTimer: g,
|
|
606
606
|
pc: o,
|
|
@@ -663,16 +663,16 @@ function createMeshHost(e = {}) {
|
|
|
663
663
|
};
|
|
664
664
|
}
|
|
665
665
|
// src/_base45.ts
|
|
666
|
-
var
|
|
666
|
+
var l = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:", u = new Map([...l].map((e, t) => [e, t]));
|
|
667
667
|
function bytesToBase45(e) {
|
|
668
668
|
let t = "";
|
|
669
669
|
for (let n = 0; n + 1 < e.length; n += 2) {
|
|
670
670
|
let r = e[n] * 256 + e[n + 1];
|
|
671
|
-
t +=
|
|
671
|
+
t += l[r % 45] + l[Math.floor(r / 45) % 45] + l[Math.floor(r / 2025)];
|
|
672
672
|
}
|
|
673
673
|
if (e.length % 2) {
|
|
674
674
|
let n = e[e.length - 1];
|
|
675
|
-
t +=
|
|
675
|
+
t += l[n % 45] + l[Math.floor(n / 45)];
|
|
676
676
|
}
|
|
677
677
|
return t;
|
|
678
678
|
}
|
|
@@ -691,12 +691,12 @@ function base45ToBytes(e) {
|
|
|
691
691
|
return new Uint8Array(t);
|
|
692
692
|
}
|
|
693
693
|
function digit(e, t) {
|
|
694
|
-
let n =
|
|
694
|
+
let n = u.get(e[t]);
|
|
695
695
|
if (n === void 0) throw new MeshPairingError("Malformed base45 payload");
|
|
696
696
|
return n;
|
|
697
697
|
}
|
|
698
698
|
// src/qr-codec.ts
|
|
699
|
-
var
|
|
699
|
+
var d = "mq2.", f = 1048576, p = new TextEncoder(), m = new TextDecoder();
|
|
700
700
|
function decompressionStream(e) {
|
|
701
701
|
if (typeof globalThis.DecompressionStream != "function") throw new MeshUnsupportedError("DecompressionStream is not available in this environment");
|
|
702
702
|
return new globalThis.DecompressionStream(e);
|
|
@@ -714,14 +714,14 @@ async function pump(e, t, n) {
|
|
|
714
714
|
for (let e of a) c.set(e, l), l += e.length;
|
|
715
715
|
return c;
|
|
716
716
|
}
|
|
717
|
-
var
|
|
717
|
+
var h = {
|
|
718
718
|
async decode(e) {
|
|
719
719
|
let t = e.trim();
|
|
720
|
-
if (t.startsWith(
|
|
720
|
+
if (t.startsWith(d)) {
|
|
721
721
|
let e;
|
|
722
722
|
try {
|
|
723
723
|
let n = base45ToBytes(t.slice(4));
|
|
724
|
-
e = JSON.parse(
|
|
724
|
+
e = JSON.parse(m.decode(await pump(n, decompressionStream("deflate-raw"), f)));
|
|
725
725
|
} catch (e) {
|
|
726
726
|
throw e instanceof MeshUnsupportedError || e instanceof MeshPairingError ? e : new MeshPairingError("Malformed pairing payload", { cause: e });
|
|
727
727
|
}
|
|
@@ -730,17 +730,17 @@ var m = {
|
|
|
730
730
|
sdp: restoreSdp(e.sdp)
|
|
731
731
|
}), parsePairingPayload(e);
|
|
732
732
|
}
|
|
733
|
-
return
|
|
733
|
+
return s.decode(t);
|
|
734
734
|
},
|
|
735
735
|
async encode(e) {
|
|
736
|
-
if (typeof globalThis.CompressionStream != "function") return
|
|
736
|
+
if (typeof globalThis.CompressionStream != "function") return s.encode(e);
|
|
737
737
|
let t = compactSdp(e.sdp);
|
|
738
|
-
return
|
|
738
|
+
return d + bytesToBase45(await pump(p.encode(JSON.stringify(t ? {
|
|
739
739
|
...e,
|
|
740
740
|
sdp: t
|
|
741
741
|
} : e)), new globalThis.CompressionStream("deflate-raw")));
|
|
742
742
|
}
|
|
743
743
|
};
|
|
744
|
-
export { MeshConnectionError, MeshDisposedError, MeshError, MeshPairingError, MeshPayloadError, MeshTimeoutError, MeshUnsupportedError, createMeshGuest, createMeshHost,
|
|
744
|
+
export { MeshConnectionError, MeshDisposedError, MeshError, MeshPairingError, MeshPayloadError, MeshTimeoutError, MeshUnsupportedError, createMeshGuest, createMeshHost, s as meshCodec, h as meshQrCodec };
|
|
745
745
|
|
|
746
746
|
//# sourceMappingURL=mesh.js.map
|