@dxos/teleport 0.1.14

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.
Files changed (51) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +0 -0
  3. package/dist/lib/browser/index.mjs +544 -0
  4. package/dist/lib/browser/index.mjs.map +7 -0
  5. package/dist/lib/browser/meta.json +1 -0
  6. package/dist/lib/browser/testing.mjs +621 -0
  7. package/dist/lib/browser/testing.mjs.map +7 -0
  8. package/dist/lib/node/index.cjs +580 -0
  9. package/dist/lib/node/index.cjs.map +7 -0
  10. package/dist/lib/node/meta.json +1 -0
  11. package/dist/lib/node/testing.cjs +653 -0
  12. package/dist/lib/node/testing.cjs.map +7 -0
  13. package/dist/types/src/index.d.ts +3 -0
  14. package/dist/types/src/index.d.ts.map +1 -0
  15. package/dist/types/src/muxing/framer.d.ts +29 -0
  16. package/dist/types/src/muxing/framer.d.ts.map +1 -0
  17. package/dist/types/src/muxing/framer.test.d.ts +2 -0
  18. package/dist/types/src/muxing/framer.test.d.ts.map +1 -0
  19. package/dist/types/src/muxing/index.d.ts +4 -0
  20. package/dist/types/src/muxing/index.d.ts.map +1 -0
  21. package/dist/types/src/muxing/muxer.d.ts +60 -0
  22. package/dist/types/src/muxing/muxer.d.ts.map +1 -0
  23. package/dist/types/src/muxing/muxer.test.d.ts +2 -0
  24. package/dist/types/src/muxing/muxer.test.d.ts.map +1 -0
  25. package/dist/types/src/muxing/rpc-port.d.ts +11 -0
  26. package/dist/types/src/muxing/rpc-port.d.ts.map +1 -0
  27. package/dist/types/src/muxing/rpc-port.test.d.ts +2 -0
  28. package/dist/types/src/muxing/rpc-port.test.d.ts.map +1 -0
  29. package/dist/types/src/teleport.d.ts +47 -0
  30. package/dist/types/src/teleport.d.ts.map +1 -0
  31. package/dist/types/src/teleport.test.d.ts +2 -0
  32. package/dist/types/src/teleport.test.d.ts.map +1 -0
  33. package/dist/types/src/test-extension.d.ts +12 -0
  34. package/dist/types/src/test-extension.d.ts.map +1 -0
  35. package/dist/types/src/testing.d.ts +29 -0
  36. package/dist/types/src/testing.d.ts.map +1 -0
  37. package/package.json +47 -0
  38. package/src/index.ts +6 -0
  39. package/src/muxing/framer.test.ts +160 -0
  40. package/src/muxing/framer.ts +132 -0
  41. package/src/muxing/index.ts +7 -0
  42. package/src/muxing/muxer.test.ts +185 -0
  43. package/src/muxing/muxer.ts +301 -0
  44. package/src/muxing/rpc-port.test.ts +18 -0
  45. package/src/muxing/rpc-port.ts +15 -0
  46. package/src/teleport.test.ts +81 -0
  47. package/src/teleport.ts +277 -0
  48. package/src/test-extension.ts +65 -0
  49. package/src/testing.ts +75 -0
  50. package/testing.d.ts +11 -0
  51. package/testing.js +5 -0
@@ -0,0 +1,621 @@
1
+ // packages/core/mesh/teleport/src/testing.ts
2
+ import { pipeline } from "@dxos/node-std/stream";
3
+ import { PublicKey as PublicKey2 } from "@dxos/keys";
4
+ import { log as log3 } from "@dxos/log";
5
+
6
+ // packages/core/mesh/teleport/src/teleport.ts
7
+ import assert3 from "@dxos/node-std/assert";
8
+ import { asyncTimeout, scheduleTaskInterval, runInContextAsync, synchronized, scheduleTask } from "@dxos/async";
9
+ import { Context } from "@dxos/context";
10
+ import { failUndefined as failUndefined2 } from "@dxos/debug";
11
+ import { PublicKey } from "@dxos/keys";
12
+ import { log as log2 } from "@dxos/log";
13
+ import { schema as schema2 } from "@dxos/protocols";
14
+ import { createProtoRpcPeer, RpcClosedError } from "@dxos/rpc";
15
+ import { Callback } from "@dxos/util";
16
+
17
+ // packages/core/mesh/teleport/src/muxing/framer.ts
18
+ import assert from "@dxos/node-std/assert";
19
+ import { Duplex } from "@dxos/node-std/stream";
20
+ import * as varint from "varint";
21
+ var Framer = class {
22
+ constructor() {
23
+ this._stream = new Duplex({
24
+ objectMode: false,
25
+ read: () => {
26
+ },
27
+ write: (chunk, encoding, callback) => {
28
+ assert(!this._subscribeCb, "Internal Framer bug. Concurrent writes detected.");
29
+ if (this._buffer && this._buffer.length > 0) {
30
+ this._buffer = Buffer.concat([
31
+ this._buffer,
32
+ chunk
33
+ ]);
34
+ } else {
35
+ this._buffer = chunk;
36
+ }
37
+ if (this._messageCb) {
38
+ this._popFrames();
39
+ callback();
40
+ } else {
41
+ this._subscribeCb = () => {
42
+ this._popFrames();
43
+ this._subscribeCb = void 0;
44
+ callback();
45
+ };
46
+ }
47
+ }
48
+ });
49
+ this.port = {
50
+ send: (message) => {
51
+ this._stream.push(encodeLength(message.length));
52
+ this._stream.push(message);
53
+ },
54
+ subscribe: (callback) => {
55
+ var _a;
56
+ assert(!this._messageCb, "Rpc port already has a message listener.");
57
+ this._messageCb = callback;
58
+ (_a = this._subscribeCb) == null ? void 0 : _a.call(this);
59
+ return () => {
60
+ this._messageCb = void 0;
61
+ };
62
+ }
63
+ };
64
+ }
65
+ get stream() {
66
+ return this._stream;
67
+ }
68
+ _popFrames() {
69
+ let offset = 0;
70
+ while (offset < this._buffer.length) {
71
+ const frame = readFrame(this._buffer, offset);
72
+ if (!frame) {
73
+ break;
74
+ }
75
+ offset += frame.bytesConsumed;
76
+ this._messageCb(frame.payload);
77
+ }
78
+ if (offset < this._buffer.length) {
79
+ this._buffer = this._buffer.subarray(offset);
80
+ } else {
81
+ this._buffer = void 0;
82
+ }
83
+ }
84
+ destroy() {
85
+ this._stream.destroy();
86
+ }
87
+ };
88
+ var readFrame = (buffer, offset) => {
89
+ try {
90
+ const frameLength = varint.decode(buffer, offset);
91
+ const tagLength = varint.decode.bytes;
92
+ if (buffer.length < offset + tagLength + frameLength) {
93
+ return void 0;
94
+ }
95
+ const payload = buffer.subarray(offset + tagLength, offset + tagLength + frameLength);
96
+ return {
97
+ payload,
98
+ bytesConsumed: tagLength + frameLength
99
+ };
100
+ } catch (err) {
101
+ if (err instanceof RangeError) {
102
+ return void 0;
103
+ } else {
104
+ throw err;
105
+ }
106
+ }
107
+ };
108
+ var encodeLength = (length) => {
109
+ const res = varint.encode(length, Buffer.allocUnsafe(4)).subarray(0, varint.encode.bytes);
110
+ if (varint.encode.bytes > 4) {
111
+ throw new Error("Frame too large");
112
+ }
113
+ return res;
114
+ };
115
+
116
+ // packages/core/mesh/teleport/src/muxing/muxer.ts
117
+ import assert2 from "@dxos/node-std/assert";
118
+ import { Duplex as Duplex2 } from "@dxos/node-std/stream";
119
+ import { Event } from "@dxos/async";
120
+ import { failUndefined } from "@dxos/debug";
121
+ import { log } from "@dxos/log";
122
+ import { schema } from "@dxos/protocols";
123
+ var codec = schema.getCodecForType("dxos.mesh.muxer.Command");
124
+ var Muxer = class {
125
+ constructor() {
126
+ this._framer = new Framer();
127
+ this.stream = this._framer.stream;
128
+ this._channelsByLocalId = /* @__PURE__ */ new Map();
129
+ this._channelsByTag = /* @__PURE__ */ new Map();
130
+ this._nextId = 0;
131
+ this._destroyed = false;
132
+ this._destroying = false;
133
+ this.close = new Event();
134
+ this._framer.port.subscribe((msg) => {
135
+ this._handleCommand(codec.decode(msg));
136
+ });
137
+ }
138
+ createStream(tag, opts = {}) {
139
+ const channel = this._getOrCreateStream({
140
+ tag,
141
+ contentType: opts.contentType
142
+ });
143
+ assert2(!channel.push, `Channel already open: ${tag}`);
144
+ const stream = new Duplex2({
145
+ write: (data, encoding, callback) => {
146
+ this._sendData(channel, data);
147
+ callback();
148
+ },
149
+ read: () => {
150
+ }
151
+ });
152
+ channel.push = (data) => {
153
+ stream.push(data);
154
+ };
155
+ channel.destroy = (err) => {
156
+ stream.destroy(err);
157
+ };
158
+ this._sendCommand({
159
+ openChannel: {
160
+ id: channel.id,
161
+ tag: channel.tag,
162
+ contentType: channel.contentType
163
+ }
164
+ });
165
+ return stream;
166
+ }
167
+ createPort(tag, opts = {}) {
168
+ const channel = this._getOrCreateStream({
169
+ tag,
170
+ contentType: opts.contentType
171
+ });
172
+ assert2(!channel.push, `Channel already open: ${tag}`);
173
+ let inboundBuffer = [];
174
+ let callback;
175
+ channel.push = (data) => {
176
+ if (callback) {
177
+ callback(data);
178
+ } else {
179
+ inboundBuffer.push(data);
180
+ }
181
+ };
182
+ const port = {
183
+ send: (data) => {
184
+ this._sendData(channel, data);
185
+ },
186
+ subscribe: (cb) => {
187
+ assert2(!callback, "Only one subscriber is allowed");
188
+ callback = cb;
189
+ for (const data of inboundBuffer) {
190
+ cb(data);
191
+ }
192
+ inboundBuffer = [];
193
+ }
194
+ };
195
+ this._sendCommand({
196
+ openChannel: {
197
+ id: channel.id,
198
+ tag: channel.tag,
199
+ contentType: channel.contentType
200
+ }
201
+ });
202
+ return port;
203
+ }
204
+ destroy(err) {
205
+ if (this._destroying) {
206
+ return;
207
+ }
208
+ this._destroying = true;
209
+ this._sendCommand({
210
+ destroy: {
211
+ error: err == null ? void 0 : err.message
212
+ }
213
+ });
214
+ this._dispose();
215
+ }
216
+ _dispose(err) {
217
+ var _a;
218
+ if (this._destroyed) {
219
+ return;
220
+ }
221
+ this._destroyed = true;
222
+ this._framer.destroy();
223
+ for (const channel of this._channelsByTag.values()) {
224
+ (_a = channel.destroy) == null ? void 0 : _a.call(channel, err);
225
+ }
226
+ this.close.emit(err);
227
+ this._channelsByLocalId.clear();
228
+ this._channelsByTag.clear();
229
+ }
230
+ _handleCommand(cmd) {
231
+ var _a;
232
+ log("Received command", {
233
+ cmd
234
+ }, {
235
+ file: "/home/runner/work/dxos/dxos/packages/core/mesh/teleport/src/muxing/muxer.ts",
236
+ line: 194,
237
+ scope: this,
238
+ callSite: (f, a) => f(...a)
239
+ });
240
+ if (this._destroyed || this._destroying) {
241
+ log.warn("Received command after destroy", {}, {
242
+ file: "/home/runner/work/dxos/dxos/packages/core/mesh/teleport/src/muxing/muxer.ts",
243
+ line: 197,
244
+ scope: this,
245
+ callSite: (f, a) => f(...a)
246
+ });
247
+ return;
248
+ }
249
+ if (cmd.openChannel) {
250
+ const channel = this._getOrCreateStream({
251
+ tag: cmd.openChannel.tag,
252
+ contentType: cmd.openChannel.contentType
253
+ });
254
+ channel.remoteId = cmd.openChannel.id;
255
+ for (const data of channel.buffer) {
256
+ this._sendCommand({
257
+ data: {
258
+ channelId: channel.remoteId,
259
+ data
260
+ }
261
+ });
262
+ }
263
+ channel.buffer = [];
264
+ } else if (cmd.data) {
265
+ const stream = (_a = this._channelsByLocalId.get(cmd.data.channelId)) != null ? _a : failUndefined();
266
+ if (!stream.push) {
267
+ log.warn("Received data for channel before it was opened", {
268
+ tag: stream.tag
269
+ }, {
270
+ file: "/home/runner/work/dxos/dxos/packages/core/mesh/teleport/src/muxing/muxer.ts",
271
+ line: 221,
272
+ scope: this,
273
+ callSite: (f, a) => f(...a)
274
+ });
275
+ return;
276
+ }
277
+ stream.push(cmd.data.data);
278
+ } else if (cmd.destroy) {
279
+ this._dispose();
280
+ }
281
+ }
282
+ _sendCommand(cmd) {
283
+ Promise.resolve(this._framer.port.send(codec.encode(cmd))).catch((err) => {
284
+ this.destroy(err);
285
+ });
286
+ }
287
+ _getOrCreateStream(params) {
288
+ let channel = this._channelsByTag.get(params.tag);
289
+ if (!channel) {
290
+ channel = {
291
+ id: this._nextId++,
292
+ remoteId: null,
293
+ tag: params.tag,
294
+ contentType: params.contentType,
295
+ buffer: [],
296
+ push: null,
297
+ destroy: null
298
+ };
299
+ this._channelsByTag.set(channel.tag, channel);
300
+ this._channelsByLocalId.set(channel.id, channel);
301
+ }
302
+ return channel;
303
+ }
304
+ _sendData(channel, data) {
305
+ if (channel.remoteId === null) {
306
+ channel.buffer.push(data);
307
+ } else {
308
+ this._sendCommand({
309
+ data: {
310
+ channelId: channel.remoteId,
311
+ data
312
+ }
313
+ });
314
+ }
315
+ }
316
+ };
317
+
318
+ // packages/core/mesh/teleport/src/teleport.ts
319
+ var __decorate = function(decorators, target, key, desc) {
320
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
321
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
322
+ r = Reflect.decorate(decorators, target, key, desc);
323
+ else
324
+ for (var i = decorators.length - 1; i >= 0; i--)
325
+ if (d = decorators[i])
326
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
327
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
328
+ };
329
+ var Teleport = class {
330
+ constructor({ initiator, localPeerId, remotePeerId }) {
331
+ this._ctx = new Context({
332
+ onError: (err) => {
333
+ void this.destroy(err).catch(() => {
334
+ log2.error("Error during destroy", err, {
335
+ file: "/home/runner/work/dxos/dxos/packages/core/mesh/teleport/src/teleport.ts",
336
+ line: 34,
337
+ scope: this,
338
+ callSite: (f, a) => f(...a)
339
+ });
340
+ });
341
+ }
342
+ });
343
+ this._muxer = new Muxer();
344
+ this._control = new ControlExtension({
345
+ heartbeatInterval: 3e3,
346
+ heartbeatTimeout: 3e3
347
+ });
348
+ this._extensions = /* @__PURE__ */ new Map();
349
+ this._remoteExtensions = /* @__PURE__ */ new Set();
350
+ this._open = false;
351
+ assert3(typeof initiator === "boolean");
352
+ assert3(PublicKey.isPublicKey(localPeerId));
353
+ assert3(PublicKey.isPublicKey(remotePeerId));
354
+ assert3(typeof initiator === "boolean");
355
+ this.initiator = initiator;
356
+ this.localPeerId = localPeerId;
357
+ this.remotePeerId = remotePeerId;
358
+ this._control.onExtensionRegistered.set(async (name) => {
359
+ log2("remote extension", {
360
+ name
361
+ }, {
362
+ file: "/home/runner/work/dxos/dxos/packages/core/mesh/teleport/src/teleport.ts",
363
+ line: 61,
364
+ scope: this,
365
+ callSite: (f, a) => f(...a)
366
+ });
367
+ assert3(!this._remoteExtensions.has(name), "Remote extension already exists");
368
+ this._remoteExtensions.add(name);
369
+ if (this._extensions.has(name)) {
370
+ try {
371
+ await this._openExtension(name);
372
+ } catch (err) {
373
+ await this.destroy(err);
374
+ }
375
+ }
376
+ });
377
+ {
378
+ this._muxer.stream.on("close", async () => {
379
+ await this.destroy();
380
+ });
381
+ this._muxer.stream.on("error", async (err) => {
382
+ await this.destroy(err);
383
+ });
384
+ }
385
+ }
386
+ get stream() {
387
+ return this._muxer.stream;
388
+ }
389
+ async open() {
390
+ this._setExtension("dxos.mesh.teleport.control", this._control);
391
+ await this._openExtension("dxos.mesh.teleport.control");
392
+ this._open = true;
393
+ }
394
+ async close(err) {
395
+ await this.destroy(err);
396
+ }
397
+ async destroy(err) {
398
+ if (this._ctx.disposed) {
399
+ return;
400
+ }
401
+ await this._ctx.dispose();
402
+ for (const extension of this._extensions.values()) {
403
+ try {
404
+ await extension.onClose(err);
405
+ } catch (err1) {
406
+ log2.catch(err1, {}, {
407
+ file: "/home/runner/work/dxos/dxos/packages/core/mesh/teleport/src/teleport.ts",
408
+ line: 117,
409
+ scope: this,
410
+ callSite: (f, a) => f(...a)
411
+ });
412
+ }
413
+ }
414
+ this._muxer.destroy(err);
415
+ }
416
+ addExtension(name, extension) {
417
+ if (!this._open) {
418
+ throw new Error("Not open");
419
+ }
420
+ log2("addExtension", {
421
+ name
422
+ }, {
423
+ file: "/home/runner/work/dxos/dxos/packages/core/mesh/teleport/src/teleport.ts",
424
+ line: 129,
425
+ scope: this,
426
+ callSite: (f, a) => f(...a)
427
+ });
428
+ this._setExtension(name, extension);
429
+ scheduleTask(this._ctx, async () => {
430
+ try {
431
+ await this._control.registerExtension(name);
432
+ } catch (err) {
433
+ if (err instanceof RpcClosedError) {
434
+ return;
435
+ }
436
+ throw err;
437
+ }
438
+ });
439
+ if (this._remoteExtensions.has(name)) {
440
+ scheduleTask(this._ctx, async () => {
441
+ await this._openExtension(name);
442
+ });
443
+ }
444
+ }
445
+ _setExtension(extensionName, extension) {
446
+ assert3(!extensionName.includes("/"), "Invalid extension name");
447
+ assert3(!this._extensions.has(extensionName), "Extension already exists");
448
+ this._extensions.set(extensionName, extension);
449
+ }
450
+ async _openExtension(extensionName) {
451
+ var _a;
452
+ log2("open extension", {
453
+ extensionName
454
+ }, {
455
+ file: "/home/runner/work/dxos/dxos/packages/core/mesh/teleport/src/teleport.ts",
456
+ line: 159,
457
+ scope: this,
458
+ callSite: (f, a) => f(...a)
459
+ });
460
+ const extension = (_a = this._extensions.get(extensionName)) != null ? _a : failUndefined2();
461
+ const context = {
462
+ initiator: this.initiator,
463
+ localPeerId: this.localPeerId,
464
+ remotePeerId: this.remotePeerId,
465
+ createPort: (channelName, opts) => {
466
+ assert3(!channelName.includes("/"), "Invalid channel name");
467
+ return this._muxer.createPort(`${extensionName}/${channelName}`, opts);
468
+ },
469
+ createStream: (channelName, opts) => {
470
+ assert3(!channelName.includes("/"), "Invalid channel name");
471
+ return this._muxer.createStream(`${extensionName}/${channelName}`, opts);
472
+ },
473
+ close: (err) => {
474
+ void runInContextAsync(this._ctx, async () => {
475
+ await this.close(err);
476
+ });
477
+ }
478
+ };
479
+ await extension.onOpen(context);
480
+ log2("extension opened", {
481
+ extensionName
482
+ }, {
483
+ file: "/home/runner/work/dxos/dxos/packages/core/mesh/teleport/src/teleport.ts",
484
+ line: 182,
485
+ scope: this,
486
+ callSite: (f, a) => f(...a)
487
+ });
488
+ }
489
+ };
490
+ __decorate([
491
+ synchronized
492
+ ], Teleport.prototype, "destroy", null);
493
+ var ControlExtension = class {
494
+ constructor(opts) {
495
+ this.opts = opts;
496
+ this._ctx = new Context({
497
+ onError: (err) => {
498
+ this._extensionContext.close(err);
499
+ }
500
+ });
501
+ this.onExtensionRegistered = new Callback();
502
+ this.onTimeout = new Callback();
503
+ }
504
+ async onOpen(extensionContext) {
505
+ this._extensionContext = extensionContext;
506
+ this._rpc = createProtoRpcPeer({
507
+ requested: {
508
+ Control: schema2.getService("dxos.mesh.teleport.control.ControlService")
509
+ },
510
+ exposed: {
511
+ Control: schema2.getService("dxos.mesh.teleport.control.ControlService")
512
+ },
513
+ handlers: {
514
+ Control: {
515
+ registerExtension: async (request) => {
516
+ this.onExtensionRegistered.call(request.name);
517
+ },
518
+ heartbeat: async (request) => {
519
+ }
520
+ }
521
+ },
522
+ port: extensionContext.createPort("rpc", {
523
+ contentType: 'application/x-protobuf; messageType="dxos.rpc.Message"'
524
+ })
525
+ });
526
+ await this._rpc.open();
527
+ scheduleTaskInterval(this._ctx, async () => {
528
+ try {
529
+ await asyncTimeout(this._rpc.rpc.Control.heartbeat(), this.opts.heartbeatTimeout);
530
+ } catch (err) {
531
+ this.onTimeout.call();
532
+ }
533
+ }, this.opts.heartbeatInterval);
534
+ }
535
+ async onClose(err) {
536
+ await this._ctx.dispose();
537
+ await this._rpc.close();
538
+ }
539
+ async registerExtension(name) {
540
+ await this._rpc.rpc.Control.registerExtension({
541
+ name
542
+ });
543
+ }
544
+ };
545
+
546
+ // packages/core/mesh/teleport/src/testing.ts
547
+ var TestBuilder = class {
548
+ constructor() {
549
+ this._peers = new Array();
550
+ }
551
+ createPeer(peerId) {
552
+ const peer = new TestPeer(peerId);
553
+ this._peers.push(peer);
554
+ return peer;
555
+ }
556
+ async destroy() {
557
+ await Promise.all(this._peers.map((agent) => agent.destroy()));
558
+ }
559
+ async createPipedPeers({ peerId1, peerId2 } = {}) {
560
+ const peer1 = this.createPeer(peerId1);
561
+ const peer2 = this.createPeer(peerId2);
562
+ peer1.initializeTeleport({
563
+ initiator: true,
564
+ remotePeerId: peer2.peerId
565
+ });
566
+ peer2.initializeTeleport({
567
+ initiator: false,
568
+ remotePeerId: peer1.peerId
569
+ });
570
+ peer1.pipeline(peer2);
571
+ peer2.pipeline(peer1);
572
+ await Promise.all([
573
+ peer1.teleport.open(),
574
+ peer2.teleport.open()
575
+ ]);
576
+ return {
577
+ peer1,
578
+ peer2
579
+ };
580
+ }
581
+ };
582
+ var TestPeer = class {
583
+ constructor(peerId = PublicKey2.random()) {
584
+ this.peerId = peerId;
585
+ }
586
+ initializeTeleport({ initiator, remotePeerId }) {
587
+ if (this.teleport) {
588
+ return this;
589
+ }
590
+ this.teleport = new Teleport({
591
+ initiator,
592
+ localPeerId: this.peerId,
593
+ remotePeerId
594
+ });
595
+ return this;
596
+ }
597
+ pipeline(peer) {
598
+ if (!this.teleport || !peer.teleport) {
599
+ throw new Error("Teleport not initialized");
600
+ }
601
+ pipeline(this.teleport.stream, peer.teleport.stream, (err) => {
602
+ if (err && err.code !== "ERR_STREAM_PREMATURE_CLOSE") {
603
+ log3.catch(err, {}, {
604
+ file: "/home/runner/work/dxos/dxos/packages/core/mesh/teleport/src/testing.ts",
605
+ line: 67,
606
+ scope: this,
607
+ callSite: (f, a) => f(...a)
608
+ });
609
+ }
610
+ });
611
+ }
612
+ async destroy() {
613
+ var _a;
614
+ await ((_a = this.teleport) == null ? void 0 : _a.destroy());
615
+ }
616
+ };
617
+ export {
618
+ TestBuilder,
619
+ TestPeer
620
+ };
621
+ //# sourceMappingURL=testing.mjs.map