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