@dxos/network-manager 0.6.13 → 0.6.14-main.1366248

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 (164) hide show
  1. package/dist/lib/browser/{chunk-XYSYUN63.mjs → chunk-UEVA7BFW.mjs} +1323 -1102
  2. package/dist/lib/browser/chunk-UEVA7BFW.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +9 -19
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/testing/index.mjs +30 -37
  6. package/dist/lib/browser/testing/index.mjs.map +3 -3
  7. package/dist/lib/browser/transport/tcp/index.mjs +38 -0
  8. package/dist/lib/browser/transport/tcp/index.mjs.map +7 -0
  9. package/dist/lib/node/{chunk-4YAYC7WN.cjs → chunk-LK5D44SA.cjs} +1336 -1239
  10. package/dist/lib/node/chunk-LK5D44SA.cjs.map +7 -0
  11. package/dist/lib/node/index.cjs +27 -37
  12. package/dist/lib/node/index.cjs.map +2 -2
  13. package/dist/lib/node/meta.json +1 -1
  14. package/dist/lib/node/testing/index.cjs +34 -38
  15. package/dist/lib/node/testing/index.cjs.map +3 -3
  16. package/dist/lib/node/transport/tcp/index.cjs +191 -0
  17. package/dist/lib/node/transport/tcp/index.cjs.map +7 -0
  18. package/dist/lib/node-esm/chunk-Y5TD36KR.mjs +4413 -0
  19. package/dist/lib/node-esm/chunk-Y5TD36KR.mjs.map +7 -0
  20. package/dist/lib/node-esm/index.mjs +50 -0
  21. package/dist/lib/node-esm/index.mjs.map +7 -0
  22. package/dist/lib/node-esm/meta.json +1 -0
  23. package/dist/lib/node-esm/testing/index.mjs +285 -0
  24. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  25. package/dist/lib/node-esm/transport/tcp/index.mjs +159 -0
  26. package/dist/lib/node-esm/transport/tcp/index.mjs.map +7 -0
  27. package/dist/types/src/network-manager.d.ts +2 -1
  28. package/dist/types/src/network-manager.d.ts.map +1 -1
  29. package/dist/types/src/signal/ice.d.ts.map +1 -1
  30. package/dist/types/src/signal/integration.node.test.d.ts +2 -0
  31. package/dist/types/src/signal/integration.node.test.d.ts.map +1 -0
  32. package/dist/types/src/signal/swarm-messenger.node.test.d.ts +2 -0
  33. package/dist/types/src/signal/swarm-messenger.node.test.d.ts.map +1 -0
  34. package/dist/types/src/swarm/connection.d.ts.map +1 -1
  35. package/dist/types/src/swarm/peer.d.ts.map +1 -1
  36. package/dist/types/src/swarm/swarm.d.ts +2 -1
  37. package/dist/types/src/swarm/swarm.d.ts.map +1 -1
  38. package/dist/types/src/testing/test-builder.d.ts +2 -2
  39. package/dist/types/src/testing/test-builder.d.ts.map +1 -1
  40. package/dist/types/src/testing/test-wire-protocol.d.ts +1 -2
  41. package/dist/types/src/testing/test-wire-protocol.d.ts.map +1 -1
  42. package/dist/types/src/tests/basic-test-suite.d.ts.map +1 -1
  43. package/dist/types/src/tests/property-test-suite.d.ts.map +1 -1
  44. package/dist/types/src/tests/tcp-transport.node.test.d.ts +2 -0
  45. package/dist/types/src/tests/tcp-transport.node.test.d.ts.map +1 -0
  46. package/dist/types/src/tests/utils.d.ts.map +1 -1
  47. package/dist/types/src/transport/index.d.ts +1 -5
  48. package/dist/types/src/transport/index.d.ts.map +1 -1
  49. package/dist/types/src/transport/memory-transport.d.ts +2 -2
  50. package/dist/types/src/transport/memory-transport.d.ts.map +1 -1
  51. package/dist/types/src/transport/tcp/index.d.ts +2 -0
  52. package/dist/types/src/transport/tcp/index.d.ts.map +1 -0
  53. package/dist/types/src/transport/{tcp-transport.browser.d.ts → tcp/tcp-transport.browser.d.ts} +3 -3
  54. package/dist/types/src/transport/tcp/tcp-transport.browser.d.ts.map +1 -0
  55. package/dist/types/src/transport/{tcp-transport.d.ts → tcp/tcp-transport.d.ts} +3 -3
  56. package/dist/types/src/transport/tcp/tcp-transport.d.ts.map +1 -0
  57. package/dist/types/src/transport/transport.d.ts +7 -6
  58. package/dist/types/src/transport/transport.d.ts.map +1 -1
  59. package/dist/types/src/transport/webrtc/index.d.ts +4 -0
  60. package/dist/types/src/transport/webrtc/index.d.ts.map +1 -0
  61. package/dist/types/src/transport/webrtc/rtc-connection-factory.d.ts +14 -0
  62. package/dist/types/src/transport/webrtc/rtc-connection-factory.d.ts.map +1 -0
  63. package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts +68 -0
  64. package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts.map +1 -0
  65. package/dist/types/src/transport/webrtc/rtc-transport-channel.d.ts +33 -0
  66. package/dist/types/src/transport/webrtc/rtc-transport-channel.d.ts.map +1 -0
  67. package/dist/types/src/transport/webrtc/rtc-transport-channel.test.d.ts +2 -0
  68. package/dist/types/src/transport/webrtc/rtc-transport-channel.test.d.ts.map +1 -0
  69. package/dist/types/src/transport/webrtc/rtc-transport-factory.d.ts +4 -0
  70. package/dist/types/src/transport/webrtc/rtc-transport-factory.d.ts.map +1 -0
  71. package/dist/types/src/transport/{simplepeer-transport-proxy.d.ts → webrtc/rtc-transport-proxy.d.ts} +10 -12
  72. package/dist/types/src/transport/webrtc/rtc-transport-proxy.d.ts.map +1 -0
  73. package/dist/types/src/transport/webrtc/rtc-transport-proxy.test.d.ts +2 -0
  74. package/dist/types/src/transport/webrtc/rtc-transport-proxy.test.d.ts.map +1 -0
  75. package/dist/types/src/transport/{simplepeer-transport-service.d.ts → webrtc/rtc-transport-service.d.ts} +9 -7
  76. package/dist/types/src/transport/webrtc/rtc-transport-service.d.ts.map +1 -0
  77. package/dist/types/src/transport/webrtc/rtc-transport-stats.d.ts +4 -0
  78. package/dist/types/src/transport/webrtc/rtc-transport-stats.d.ts.map +1 -0
  79. package/dist/types/src/transport/webrtc/rtc-transport.test.d.ts +2 -0
  80. package/dist/types/src/transport/webrtc/rtc-transport.test.d.ts.map +1 -0
  81. package/dist/types/src/transport/webrtc/test-utils.d.ts +5 -0
  82. package/dist/types/src/transport/webrtc/test-utils.d.ts.map +1 -0
  83. package/dist/types/src/transport/webrtc/utils.d.ts +3 -0
  84. package/dist/types/src/transport/webrtc/utils.d.ts.map +1 -0
  85. package/package.json +53 -36
  86. package/src/network-manager.ts +5 -13
  87. package/src/signal/ice.test.ts +1 -3
  88. package/src/signal/ice.ts +6 -1
  89. package/src/signal/{integration.test.ts → integration.node.test.ts} +9 -15
  90. package/src/signal/{swarm-messenger.test.ts → swarm-messenger.node.test.ts} +13 -23
  91. package/src/swarm/connection-limiter.test.ts +3 -6
  92. package/src/swarm/connection.test.ts +63 -38
  93. package/src/swarm/connection.ts +7 -7
  94. package/src/swarm/peer.ts +4 -1
  95. package/src/swarm/swarm.test.ts +10 -12
  96. package/src/swarm/swarm.ts +16 -3
  97. package/src/testing/test-builder.ts +14 -29
  98. package/src/testing/test-wire-protocol.ts +7 -8
  99. package/src/tests/basic-test-suite.ts +32 -31
  100. package/src/tests/memory-transport.test.ts +40 -42
  101. package/src/tests/property-test-suite.ts +21 -22
  102. package/src/tests/tcp-transport.node.test.ts +65 -0
  103. package/src/tests/utils.ts +3 -2
  104. package/src/tests/webrtc-transport.test.ts +10 -10
  105. package/src/transport/index.ts +1 -5
  106. package/src/transport/memory-transport.ts +2 -0
  107. package/src/transport/tcp/index.ts +5 -0
  108. package/src/transport/{tcp-transport.browser.ts → tcp/tcp-transport.browser.ts} +7 -3
  109. package/src/transport/{tcp-transport.ts → tcp/tcp-transport.ts} +3 -1
  110. package/src/transport/transport.ts +8 -7
  111. package/src/transport/webrtc/index.ts +7 -0
  112. package/src/transport/webrtc/rtc-connection-factory.ts +82 -0
  113. package/src/transport/webrtc/rtc-peer-connection.ts +472 -0
  114. package/src/transport/webrtc/rtc-transport-channel.test.ts +176 -0
  115. package/src/transport/webrtc/rtc-transport-channel.ts +195 -0
  116. package/src/transport/webrtc/rtc-transport-factory.ts +28 -0
  117. package/src/transport/webrtc/rtc-transport-proxy.test.ts +413 -0
  118. package/src/transport/webrtc/rtc-transport-proxy.ts +264 -0
  119. package/src/transport/webrtc/rtc-transport-service.ts +192 -0
  120. package/src/transport/webrtc/rtc-transport-stats.ts +67 -0
  121. package/src/transport/webrtc/rtc-transport.test.ts +210 -0
  122. package/src/transport/webrtc/test-utils.ts +22 -0
  123. package/src/transport/webrtc/utils.ts +36 -0
  124. package/src/typings.d.ts +8 -2
  125. package/dist/lib/browser/chunk-XYSYUN63.mjs.map +0 -7
  126. package/dist/lib/node/chunk-4YAYC7WN.cjs.map +0 -7
  127. package/dist/types/src/signal/integration.test.d.ts +0 -2
  128. package/dist/types/src/signal/integration.test.d.ts.map +0 -1
  129. package/dist/types/src/signal/swarm-messenger.test.d.ts +0 -2
  130. package/dist/types/src/signal/swarm-messenger.test.d.ts.map +0 -1
  131. package/dist/types/src/tests/tcp-transport.test.d.ts +0 -2
  132. package/dist/types/src/tests/tcp-transport.test.d.ts.map +0 -1
  133. package/dist/types/src/transport/libdatachannel-transport.d.ts +0 -42
  134. package/dist/types/src/transport/libdatachannel-transport.d.ts.map +0 -1
  135. package/dist/types/src/transport/libdatachannel-transport.test.d.ts +0 -2
  136. package/dist/types/src/transport/libdatachannel-transport.test.d.ts.map +0 -1
  137. package/dist/types/src/transport/memory-transport.test.d.ts +0 -2
  138. package/dist/types/src/transport/memory-transport.test.d.ts.map +0 -1
  139. package/dist/types/src/transport/simplepeer-simple-peer.d.ts +0 -2
  140. package/dist/types/src/transport/simplepeer-simple-peer.d.ts.map +0 -1
  141. package/dist/types/src/transport/simplepeer-transport-proxy-test.d.ts +0 -2
  142. package/dist/types/src/transport/simplepeer-transport-proxy-test.d.ts.map +0 -1
  143. package/dist/types/src/transport/simplepeer-transport-proxy.d.ts.map +0 -1
  144. package/dist/types/src/transport/simplepeer-transport-service.d.ts.map +0 -1
  145. package/dist/types/src/transport/simplepeer-transport.d.ts +0 -36
  146. package/dist/types/src/transport/simplepeer-transport.d.ts.map +0 -1
  147. package/dist/types/src/transport/simplepeer-transport.test.d.ts +0 -2
  148. package/dist/types/src/transport/simplepeer-transport.test.d.ts.map +0 -1
  149. package/dist/types/src/transport/tcp-transport.browser.d.ts.map +0 -1
  150. package/dist/types/src/transport/tcp-transport.d.ts.map +0 -1
  151. package/dist/types/src/transport/webrtc.d.ts +0 -6
  152. package/dist/types/src/transport/webrtc.d.ts.map +0 -1
  153. package/src/globals.d.ts +0 -7
  154. package/src/tests/tcp-transport.test.ts +0 -67
  155. package/src/transport/libdatachannel-transport.test.ts +0 -100
  156. package/src/transport/libdatachannel-transport.ts +0 -376
  157. package/src/transport/memory-transport.test.ts +0 -74
  158. package/src/transport/simplepeer-simple-peer.ts +0 -26
  159. package/src/transport/simplepeer-transport-proxy-test.ts +0 -181
  160. package/src/transport/simplepeer-transport-proxy.ts +0 -246
  161. package/src/transport/simplepeer-transport-service.ts +0 -160
  162. package/src/transport/simplepeer-transport.test.ts +0 -61
  163. package/src/transport/simplepeer-transport.ts +0 -250
  164. package/src/transport/webrtc.ts +0 -15
@@ -1,17 +1,4 @@
1
1
  import "@dxos/node-std/globals";
2
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
- }) : x)(function(x) {
5
- if (typeof require !== "undefined") return require.apply(this, arguments);
6
- throw Error('Dynamic require of "' + x + '" is not supported');
7
- });
8
-
9
- // inject-globals:@inject-globals
10
- import {
11
- global,
12
- Buffer as Buffer2,
13
- process
14
- } from "@dxos/node-std/inject-globals";
15
2
 
16
3
  // packages/core/mesh/network-manager/src/swarm/connection.ts
17
4
  import { DeferredTask, Event, sleep, scheduleTask, scheduleTaskInterval, synchronized, Trigger } from "@dxos/async";
@@ -20,7 +7,7 @@ import { ErrorStream } from "@dxos/debug";
20
7
  import { invariant } from "@dxos/invariant";
21
8
  import { PublicKey } from "@dxos/keys";
22
9
  import { log, logInfo } from "@dxos/log";
23
- import { CancelledError, ProtocolError, ConnectionResetError, ConnectivityError, TimeoutError, UnknownProtocolError, trace } from "@dxos/protocols";
10
+ import { CancelledError, ProtocolError, ConnectionResetError, ConnectivityError, TimeoutError, trace } from "@dxos/protocols";
24
11
  function _ts_decorate(decorators, target, key, desc) {
25
12
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
26
13
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -56,11 +43,11 @@ var Connection = class {
56
43
  this._callbacks = _callbacks;
57
44
  this._ctx = new Context(void 0, {
58
45
  F: __dxlog_file,
59
- L: 101
46
+ L: 100
60
47
  });
61
48
  this.connectedTimeoutContext = new Context(void 0, {
62
49
  F: __dxlog_file,
63
- L: 102
50
+ L: 101
64
51
  });
65
52
  this._protocolClosed = new Trigger();
66
53
  this._transportClosed = new Trigger();
@@ -83,7 +70,7 @@ var Connection = class {
83
70
  initiator: this.initiator
84
71
  }, {
85
72
  F: __dxlog_file,
86
- L: 138,
73
+ L: 137,
87
74
  S: this,
88
75
  C: (f, a) => f(...a)
89
76
  });
@@ -106,7 +93,7 @@ var Connection = class {
106
93
  async openConnection() {
107
94
  invariant(this._state === "INITIAL", "Invalid state.", {
108
95
  F: __dxlog_file,
109
- L: 168,
96
+ L: 167,
110
97
  S: this,
111
98
  A: [
112
99
  "this._state === ConnectionState.INITIAL",
@@ -117,7 +104,7 @@ var Connection = class {
117
104
  id: this._instanceId
118
105
  }), {
119
106
  F: __dxlog_file,
120
- L: 169,
107
+ L: 168,
121
108
  S: this,
122
109
  C: (f, a) => f(...a)
123
110
  });
@@ -129,7 +116,7 @@ var Connection = class {
129
116
  initiator: this.initiator
130
117
  }, {
131
118
  F: __dxlog_file,
132
- L: 170,
119
+ L: 169,
133
120
  S: this,
134
121
  C: (f, a) => f(...a)
135
122
  });
@@ -140,7 +127,7 @@ var Connection = class {
140
127
  this._protocol.stream.on("close", () => {
141
128
  log("protocol stream closed", void 0, {
142
129
  F: __dxlog_file,
143
- L: 187,
130
+ L: 186,
144
131
  S: this,
145
132
  C: (f, a) => f(...a)
146
133
  });
@@ -150,7 +137,7 @@ var Connection = class {
150
137
  scheduleTask(this.connectedTimeoutContext, async () => {
151
138
  log.info(`timeout waiting ${TRANSPORT_CONNECTION_TIMEOUT / 1e3}s for transport to connect, aborting`, void 0, {
152
139
  F: __dxlog_file,
153
- L: 195,
140
+ L: 194,
154
141
  S: this,
155
142
  C: (f, a) => f(...a)
156
143
  });
@@ -158,7 +145,7 @@ var Connection = class {
158
145
  }, TRANSPORT_CONNECTION_TIMEOUT);
159
146
  invariant(!this._transport, void 0, {
160
147
  F: __dxlog_file,
161
- L: 203,
148
+ L: 202,
162
149
  S: this,
163
150
  A: [
164
151
  "!this._transport",
@@ -166,12 +153,14 @@ var Connection = class {
166
153
  ]
167
154
  });
168
155
  this._transport = this._transportFactory.createTransport({
156
+ ownPeerKey: this.localInfo.peerKey,
157
+ remotePeerKey: this.remoteInfo.peerKey,
158
+ topic: this.topic.toHex(),
169
159
  initiator: this.initiator,
170
160
  stream: this._protocol.stream,
171
161
  sendSignal: async (signal) => this._sendSignal(signal),
172
162
  sessionId: this.sessionId
173
163
  });
174
- await this._transport.open();
175
164
  this._transport.connected.once(async () => {
176
165
  this._changeState("CONNECTED");
177
166
  await this.connectedTimeoutContext.dispose();
@@ -208,7 +197,7 @@ var Connection = class {
208
197
  S: this,
209
198
  C: (f, a) => f(...a)
210
199
  });
211
- this.abort().catch((err2) => this.errors.raise(err2));
200
+ this.abort(err).catch((err2) => this.errors.raise(err2));
212
201
  } else if (err instanceof ConnectivityError) {
213
202
  log.info("aborting due to transport ConnectivityError", void 0, {
214
203
  F: __dxlog_file,
@@ -216,22 +205,14 @@ var Connection = class {
216
205
  S: this,
217
206
  C: (f, a) => f(...a)
218
207
  });
219
- this.abort().catch((err2) => this.errors.raise(err2));
220
- } else if (err instanceof UnknownProtocolError) {
221
- log.warn("unsure what to do with UnknownProtocolError, will keep on truckin", {
222
- err
223
- }, {
224
- F: __dxlog_file,
225
- L: 242,
226
- S: this,
227
- C: (f, a) => f(...a)
228
- });
208
+ this.abort(err).catch((err2) => this.errors.raise(err2));
229
209
  }
230
210
  if (this._state !== "CLOSED" && this._state !== "CLOSING") {
231
211
  await this.connectedTimeoutContext.dispose();
232
212
  this.errors.raise(err);
233
213
  }
234
214
  });
215
+ await this._transport.open();
235
216
  for (const signal of this._incomingSignalBuffer) {
236
217
  void this._transport.onSignal(signal);
237
218
  }
@@ -598,15 +579,20 @@ var createIceProvider = (iceProviders) => {
598
579
  }
599
580
  cachedIceServers = (await Promise.all(iceProviders.map(({ urls }) => asyncTimeout(fetch(urls, {
600
581
  method: "GET"
601
- }), 1e4).then((response) => response.json()).catch((err) => log2.error("Failed to fetch ICE servers from provider", {
602
- urls,
603
- err
604
- }, {
605
- F: __dxlog_file2,
606
- L: 27,
607
- S: void 0,
608
- C: (f, a) => f(...a)
609
- }))))).filter(isNotNullOrUndefined).map(({ iceServers }) => iceServers).flat();
582
+ }), 1e4).then((response) => response.json()).catch((err) => {
583
+ const isDev = typeof window !== "undefined" && window.location.href.includes("localhost");
584
+ if (!isDev) {
585
+ log2.error("Failed to fetch ICE servers from provider", {
586
+ urls,
587
+ err
588
+ }, {
589
+ F: __dxlog_file2,
590
+ L: 30,
591
+ S: void 0,
592
+ C: (f, a) => f(...a)
593
+ });
594
+ }
595
+ })))).filter(isNotNullOrUndefined).map(({ iceServers }) => iceServers).flat();
610
596
  return cachedIceServers;
611
597
  }
612
598
  };
@@ -1197,21 +1183,22 @@ var Peer = class {
1197
1183
  });
1198
1184
  },
1199
1185
  onClosed: (err) => {
1200
- log4("connection closed", {
1186
+ const logMeta = {
1201
1187
  topic: this.topic,
1202
1188
  peerId: this.localInfo,
1203
1189
  remoteId: this.remoteInfo,
1204
1190
  initiator
1205
- }, {
1191
+ };
1192
+ log4("connection closed", logMeta, {
1206
1193
  F: __dxlog_file4,
1207
- L: 288,
1194
+ L: 289,
1208
1195
  S: this,
1209
1196
  C: (f, a) => f(...a)
1210
1197
  });
1211
1198
  this._connectionLimiter.doneConnecting(sessionId);
1212
1199
  invariant3(this.connection === connection, "Connection mismatch (race condition).", {
1213
1200
  F: __dxlog_file4,
1214
- L: 293,
1201
+ L: 294,
1215
1202
  S: this,
1216
1203
  A: [
1217
1204
  "this.connection === connection",
@@ -1226,7 +1213,7 @@ var Peer = class {
1226
1213
  initiator
1227
1214
  }, {
1228
1215
  F: __dxlog_file4,
1229
- L: 295,
1216
+ L: 296,
1230
1217
  S: this,
1231
1218
  C: (f, a) => f(...a)
1232
1219
  });
@@ -1241,6 +1228,12 @@ var Peer = class {
1241
1228
  }
1242
1229
  this._callbacks.onDisconnected();
1243
1230
  scheduleTask2(this._connectionCtx, () => {
1231
+ log4("peer became available", logMeta, {
1232
+ F: __dxlog_file4,
1233
+ L: 320,
1234
+ S: this,
1235
+ C: (f, a) => f(...a)
1236
+ });
1244
1237
  this.availableToConnect = true;
1245
1238
  this._callbacks.onPeerAvailable();
1246
1239
  }, this._availableAfter);
@@ -1261,7 +1254,7 @@ var Peer = class {
1261
1254
  err
1262
1255
  }, {
1263
1256
  F: __dxlog_file4,
1264
- L: 335,
1257
+ L: 338,
1265
1258
  S: this,
1266
1259
  C: (f, a) => f(...a)
1267
1260
  });
@@ -1274,7 +1267,7 @@ var Peer = class {
1274
1267
  err
1275
1268
  }, {
1276
1269
  F: __dxlog_file4,
1277
- L: 342,
1270
+ L: 345,
1278
1271
  S: this,
1279
1272
  C: (f, a) => f(...a)
1280
1273
  });
@@ -1293,7 +1286,7 @@ var Peer = class {
1293
1286
  sessionId: connection.sessionId
1294
1287
  }, {
1295
1288
  F: __dxlog_file4,
1296
- L: 367,
1289
+ L: 370,
1297
1290
  S: this,
1298
1291
  C: (f, a) => f(...a)
1299
1292
  });
@@ -1303,7 +1296,7 @@ var Peer = class {
1303
1296
  sessionId: connection.sessionId
1304
1297
  }, {
1305
1298
  F: __dxlog_file4,
1306
- L: 373,
1299
+ L: 376,
1307
1300
  S: this,
1308
1301
  C: (f, a) => f(...a)
1309
1302
  });
@@ -1314,7 +1307,7 @@ var Peer = class {
1314
1307
  message
1315
1308
  }, {
1316
1309
  F: __dxlog_file4,
1317
- L: 378,
1310
+ L: 381,
1318
1311
  S: this,
1319
1312
  C: (f, a) => f(...a)
1320
1313
  });
@@ -1329,7 +1322,7 @@ var Peer = class {
1329
1322
  topic: this.topic
1330
1323
  }, {
1331
1324
  F: __dxlog_file4,
1332
- L: 388,
1325
+ L: 391,
1333
1326
  S: this,
1334
1327
  C: (f, a) => f(...a)
1335
1328
  });
@@ -1547,10 +1540,16 @@ var Swarm = class {
1547
1540
  const peer = this._peers.get(swarmEvent.peerLeft.peer);
1548
1541
  if (peer) {
1549
1542
  peer.advertizing = false;
1550
- if (peer.connection?.state !== ConnectionState.CONNECTED) {
1543
+ if (this._isConnectionEstablishmentInProgress(peer)) {
1544
+ log5(`destroying peer, state: ${peer.connection?.state}`, void 0, {
1545
+ F: __dxlog_file5,
1546
+ L: 195,
1547
+ S: this,
1548
+ C: (f, a) => f(...a)
1549
+ });
1551
1550
  void this._destroyPeer(swarmEvent.peerLeft.peer, "peer left").catch((err) => log5.catch(err, void 0, {
1552
1551
  F: __dxlog_file5,
1553
- L: 194,
1552
+ L: 196,
1554
1553
  S: this,
1555
1554
  C: (f, a) => f(...a)
1556
1555
  }));
@@ -1560,7 +1559,7 @@ var Swarm = class {
1560
1559
  peer: swarmEvent.peerLeft.peer.peerKey
1561
1560
  }, {
1562
1561
  F: __dxlog_file5,
1563
- L: 197,
1562
+ L: 199,
1564
1563
  S: this,
1565
1564
  C: (f, a) => f(...a)
1566
1565
  });
@@ -1573,14 +1572,14 @@ var Swarm = class {
1573
1572
  message
1574
1573
  }, {
1575
1574
  F: __dxlog_file5,
1576
- L: 206,
1575
+ L: 208,
1577
1576
  S: this,
1578
1577
  C: (f, a) => f(...a)
1579
1578
  });
1580
1579
  if (this._ctx.disposed) {
1581
1580
  log5("ignored for disposed swarm", void 0, {
1582
1581
  F: __dxlog_file5,
1583
- L: 208,
1582
+ L: 210,
1584
1583
  S: this,
1585
1584
  C: (f, a) => f(...a)
1586
1585
  });
@@ -1590,7 +1589,7 @@ var Swarm = class {
1590
1589
  }
1591
1590
  invariant4(message.author, void 0, {
1592
1591
  F: __dxlog_file5,
1593
- L: 213,
1592
+ L: 215,
1594
1593
  S: this,
1595
1594
  A: [
1596
1595
  "message.author",
@@ -1602,7 +1601,7 @@ var Swarm = class {
1602
1601
  message
1603
1602
  }, {
1604
1603
  F: __dxlog_file5,
1605
- L: 215,
1604
+ L: 217,
1606
1605
  S: this,
1607
1606
  C: (f, a) => f(...a)
1608
1607
  });
@@ -1615,7 +1614,7 @@ var Swarm = class {
1615
1614
  message
1616
1615
  }, {
1617
1616
  F: __dxlog_file5,
1618
- L: 219,
1617
+ L: 221,
1619
1618
  S: this,
1620
1619
  C: (f, a) => f(...a)
1621
1620
  });
@@ -1633,14 +1632,14 @@ var Swarm = class {
1633
1632
  message
1634
1633
  }, {
1635
1634
  F: __dxlog_file5,
1636
- L: 230,
1635
+ L: 232,
1637
1636
  S: this,
1638
1637
  C: (f, a) => f(...a)
1639
1638
  });
1640
1639
  if (this._ctx.disposed) {
1641
1640
  log5.info("ignored for offline swarm", void 0, {
1642
1641
  F: __dxlog_file5,
1643
- L: 232,
1642
+ L: 234,
1644
1643
  S: this,
1645
1644
  C: (f, a) => f(...a)
1646
1645
  });
@@ -1648,7 +1647,7 @@ var Swarm = class {
1648
1647
  }
1649
1648
  invariant4(message.recipient.peerKey === this._ownPeer.peerKey, `Invalid signal peer id expected=${this.ownPeerId}, actual=${message.recipient}`, {
1650
1649
  F: __dxlog_file5,
1651
- L: 235,
1650
+ L: 237,
1652
1651
  S: this,
1653
1652
  A: [
1654
1653
  "message.recipient.peerKey === this._ownPeer.peerKey",
@@ -1657,7 +1656,7 @@ var Swarm = class {
1657
1656
  });
1658
1657
  invariant4(message.topic?.equals(this._topic), void 0, {
1659
1658
  F: __dxlog_file5,
1660
- L: 239,
1659
+ L: 241,
1661
1660
  S: this,
1662
1661
  A: [
1663
1662
  "message.topic?.equals(this._topic)",
@@ -1666,7 +1665,7 @@ var Swarm = class {
1666
1665
  });
1667
1666
  invariant4(message.author, void 0, {
1668
1667
  F: __dxlog_file5,
1669
- L: 240,
1668
+ L: 242,
1670
1669
  S: this,
1671
1670
  A: [
1672
1671
  "message.author",
@@ -1687,13 +1686,13 @@ var Swarm = class {
1687
1686
  async goOnline() {
1688
1687
  this._ctx = new Context4(void 0, {
1689
1688
  F: __dxlog_file5,
1690
- L: 256
1689
+ L: 258
1691
1690
  });
1692
1691
  }
1693
1692
  _getOrCreatePeer(peerInfo) {
1694
1693
  invariant4(peerInfo.peerKey, "PeerInfo.peerKey is required", {
1695
1694
  F: __dxlog_file5,
1696
- L: 260,
1695
+ L: 262,
1697
1696
  S: this,
1698
1697
  A: [
1699
1698
  "peerInfo.peerKey",
@@ -1711,6 +1710,12 @@ var Swarm = class {
1711
1710
  },
1712
1711
  onDisconnected: async () => {
1713
1712
  if (this._isUnregistered(peer)) {
1713
+ log5.verbose("ignored onDisconnected for unregistered peer", void 0, {
1714
+ F: __dxlog_file5,
1715
+ L: 282,
1716
+ S: this,
1717
+ C: (f, a) => f(...a)
1718
+ });
1714
1719
  return;
1715
1720
  }
1716
1721
  if (!peer.advertizing) {
@@ -1725,7 +1730,7 @@ var Swarm = class {
1725
1730
  peerInfo
1726
1731
  }, {
1727
1732
  F: __dxlog_file5,
1728
- L: 293,
1733
+ L: 296,
1729
1734
  S: this,
1730
1735
  C: (f, a) => f(...a)
1731
1736
  });
@@ -1747,10 +1752,19 @@ var Swarm = class {
1747
1752
  return peer;
1748
1753
  }
1749
1754
  async _destroyPeer(peerInfo, reason) {
1755
+ log5("destroy peer", {
1756
+ peerKey: peerInfo.peerKey,
1757
+ reason
1758
+ }, {
1759
+ F: __dxlog_file5,
1760
+ L: 318,
1761
+ S: this,
1762
+ C: (f, a) => f(...a)
1763
+ });
1750
1764
  const peer = this._peers.get(peerInfo);
1751
1765
  invariant4(peer, void 0, {
1752
1766
  F: __dxlog_file5,
1753
- L: 316,
1767
+ L: 320,
1754
1768
  S: this,
1755
1769
  A: [
1756
1770
  "peer",
@@ -1780,7 +1794,7 @@ var Swarm = class {
1780
1794
  } catch (err) {
1781
1795
  log5("initiation error", err, {
1782
1796
  F: __dxlog_file5,
1783
- L: 343,
1797
+ L: 347,
1784
1798
  S: this,
1785
1799
  C: (f, a) => f(...a)
1786
1800
  });
@@ -1811,7 +1825,7 @@ var Swarm = class {
1811
1825
  remotePeer
1812
1826
  }, {
1813
1827
  F: __dxlog_file5,
1814
- L: 371,
1828
+ L: 375,
1815
1829
  S: this,
1816
1830
  C: (f, a) => f(...a)
1817
1831
  });
@@ -1830,7 +1844,7 @@ var Swarm = class {
1830
1844
  remotePeer
1831
1845
  }, {
1832
1846
  F: __dxlog_file5,
1833
- L: 387,
1847
+ L: 391,
1834
1848
  S: this,
1835
1849
  C: (f, a) => f(...a)
1836
1850
  });
@@ -1840,7 +1854,7 @@ var Swarm = class {
1840
1854
  remotePeer
1841
1855
  }, {
1842
1856
  F: __dxlog_file5,
1843
- L: 390,
1857
+ L: 394,
1844
1858
  S: this,
1845
1859
  C: (f, a) => f(...a)
1846
1860
  });
@@ -1852,6 +1866,16 @@ var Swarm = class {
1852
1866
  }
1853
1867
  await peer.closeConnection();
1854
1868
  }
1869
+ _isConnectionEstablishmentInProgress(peer) {
1870
+ if (!peer.connection) {
1871
+ return true;
1872
+ }
1873
+ return [
1874
+ ConnectionState.INITIAL,
1875
+ ConnectionState.CREATED,
1876
+ ConnectionState.CONNECTING
1877
+ ].includes(peer.connection.state);
1878
+ }
1855
1879
  _isUnregistered(peer) {
1856
1880
  return !peer || this._peers.get(peer.remoteInfo) !== peer;
1857
1881
  }
@@ -2226,52 +2250,37 @@ var SwarmNetworkManager = class {
2226
2250
  /**
2227
2251
  * Join the swarm.
2228
2252
  */
2229
- async joinSwarm({ topic, peerInfo, topology, protocolProvider: protocol, label }) {
2253
+ async joinSwarm({ topic, topology, protocolProvider: protocol, label }) {
2230
2254
  invariant6(PublicKey8.isPublicKey(topic), void 0, {
2231
2255
  F: __dxlog_file8,
2232
- L: 161,
2256
+ L: 160,
2233
2257
  S: this,
2234
2258
  A: [
2235
2259
  "PublicKey.isPublicKey(topic)",
2236
2260
  ""
2237
2261
  ]
2238
2262
  });
2239
- if (!peerInfo) {
2240
- peerInfo = {
2241
- peerKey: this._peerInfo?.peerKey ?? PublicKey8.random().toHex(),
2242
- identityKey: this._peerInfo?.identityKey ?? PublicKey8.random().toHex()
2243
- };
2244
- }
2245
- invariant6(PublicKey8.from(peerInfo.peerKey), void 0, {
2246
- F: __dxlog_file8,
2247
- L: 168,
2248
- S: this,
2249
- A: [
2250
- "PublicKey.from(peerInfo.peerKey)",
2251
- ""
2252
- ]
2253
- });
2254
- invariant6(PublicKey8.from(peerInfo.identityKey), void 0, {
2263
+ invariant6(topology, void 0, {
2255
2264
  F: __dxlog_file8,
2256
- L: 169,
2265
+ L: 161,
2257
2266
  S: this,
2258
2267
  A: [
2259
- "PublicKey.from(peerInfo.identityKey!)",
2268
+ "topology",
2260
2269
  ""
2261
2270
  ]
2262
2271
  });
2263
- invariant6(topology, void 0, {
2272
+ invariant6(this._peerInfo, void 0, {
2264
2273
  F: __dxlog_file8,
2265
- L: 170,
2274
+ L: 162,
2266
2275
  S: this,
2267
2276
  A: [
2268
- "topology",
2277
+ "this._peerInfo",
2269
2278
  ""
2270
2279
  ]
2271
2280
  });
2272
2281
  invariant6(typeof protocol === "function", void 0, {
2273
2282
  F: __dxlog_file8,
2274
- L: 171,
2283
+ L: 163,
2275
2284
  S: this,
2276
2285
  A: [
2277
2286
  "typeof protocol === 'function'",
@@ -2283,21 +2292,21 @@ var SwarmNetworkManager = class {
2283
2292
  }
2284
2293
  log8("joining", {
2285
2294
  topic: PublicKey8.from(topic),
2286
- peerInfo,
2295
+ peerInfo: this._peerInfo,
2287
2296
  topology: topology.toString()
2288
2297
  }, {
2289
2298
  F: __dxlog_file8,
2290
- L: 176,
2299
+ L: 168,
2291
2300
  S: this,
2292
2301
  C: (f, a) => f(...a)
2293
2302
  });
2294
- const swarm = new Swarm(topic, peerInfo, topology, protocol, this._messenger, this._transportFactory, label, this._connectionLimiter);
2303
+ const swarm = new Swarm(topic, this._peerInfo, topology, protocol, this._messenger, this._transportFactory, label, this._connectionLimiter);
2295
2304
  swarm.errors.handle((error) => {
2296
2305
  log8("swarm error", {
2297
2306
  error
2298
2307
  }, {
2299
2308
  F: __dxlog_file8,
2300
- L: 189,
2309
+ L: 181,
2301
2310
  S: this,
2302
2311
  C: (f, a) => f(...a)
2303
2312
  });
@@ -2307,10 +2316,10 @@ var SwarmNetworkManager = class {
2307
2316
  await swarm.open();
2308
2317
  this._signalConnection.join({
2309
2318
  topic,
2310
- peer: peerInfo
2319
+ peer: this._peerInfo
2311
2320
  }).catch((error) => log8.catch(error, void 0, {
2312
2321
  F: __dxlog_file8,
2313
- L: 198,
2322
+ L: 190,
2314
2323
  S: this,
2315
2324
  C: (f, a) => f(...a)
2316
2325
  }));
@@ -2321,7 +2330,7 @@ var SwarmNetworkManager = class {
2321
2330
  count: this._swarms.size
2322
2331
  }, {
2323
2332
  F: __dxlog_file8,
2324
- L: 202,
2333
+ L: 194,
2325
2334
  S: this,
2326
2335
  C: (f, a) => f(...a)
2327
2336
  });
@@ -2340,7 +2349,7 @@ var SwarmNetworkManager = class {
2340
2349
  topic: PublicKey8.from(topic)
2341
2350
  }, {
2342
2351
  F: __dxlog_file8,
2343
- L: 219,
2352
+ L: 211,
2344
2353
  S: this,
2345
2354
  C: (f, a) => f(...a)
2346
2355
  });
@@ -2361,7 +2370,7 @@ var SwarmNetworkManager = class {
2361
2370
  count: this._swarms.size
2362
2371
  }, {
2363
2372
  F: __dxlog_file8,
2364
- L: 233,
2373
+ L: 225,
2365
2374
  S: this,
2366
2375
  C: (f, a) => f(...a)
2367
2376
  });
@@ -2630,7 +2639,7 @@ var sortByXorDistance = (keys, reference) => {
2630
2639
  };
2631
2640
  var distXor = (a, b) => {
2632
2641
  const maxLength = Math.max(a.length, b.length);
2633
- const result = Buffer2.allocUnsafe(maxLength);
2642
+ const result = Buffer.allocUnsafe(maxLength);
2634
2643
  for (let i = 0; i < maxLength; i++) {
2635
2644
  result[i] = (a[i] || 0) ^ (b[i] || 0);
2636
2645
  }
@@ -2865,11 +2874,12 @@ var MemoryTransport = class _MemoryTransport {
2865
2874
  this.errors.raise(err);
2866
2875
  });
2867
2876
  }
2877
+ return this;
2868
2878
  }
2869
2879
  async close() {
2870
2880
  log11("closing...", void 0, {
2871
2881
  F: __dxlog_file12,
2872
- L: 129,
2882
+ L: 130,
2873
2883
  S: this,
2874
2884
  C: (f, a) => f(...a)
2875
2885
  });
@@ -2890,17 +2900,18 @@ var MemoryTransport = class _MemoryTransport {
2890
2900
  this.closed.emit();
2891
2901
  log11("closed", void 0, {
2892
2902
  F: __dxlog_file12,
2893
- L: 157,
2903
+ L: 158,
2894
2904
  S: this,
2895
2905
  C: (f, a) => f(...a)
2896
2906
  });
2907
+ return this;
2897
2908
  }
2898
2909
  async onSignal({ payload }) {
2899
2910
  log11("received signal", {
2900
2911
  payload
2901
2912
  }, {
2902
2913
  F: __dxlog_file12,
2903
- L: 161,
2914
+ L: 163,
2904
2915
  S: this,
2905
2916
  C: (f, a) => f(...a)
2906
2917
  });
@@ -2936,524 +2947,980 @@ var toError = (err) => err instanceof Error ? err : new Error(String(err));
2936
2947
  // packages/core/mesh/network-manager/src/transport/transport.ts
2937
2948
  var TransportKind;
2938
2949
  (function(TransportKind2) {
2939
- TransportKind2["SIMPLE_PEER"] = "SIMPLE_PEER";
2940
- TransportKind2["SIMPLE_PEER_PROXY"] = "SIMPLE_PEER_PROXY";
2941
- TransportKind2["LIBDATACHANNEL"] = "LIBDATACHANNEL";
2950
+ TransportKind2["WEB_RTC"] = "WEB-RTC";
2951
+ TransportKind2["WEB_RTC_PROXY"] = "WEB-RTC_PROXY";
2942
2952
  TransportKind2["MEMORY"] = "MEMORY";
2943
2953
  TransportKind2["TCP"] = "TCP";
2944
2954
  })(TransportKind || (TransportKind = {}));
2945
2955
 
2946
- // packages/core/mesh/network-manager/src/transport/simplepeer-transport.ts
2947
- import SimplePeerConstructor from "simple-peer";
2948
- import invariant11 from "tiny-invariant";
2949
- import { Event as Event8, synchronized as synchronized5 } from "@dxos/async";
2950
- import { ErrorStream as ErrorStream4, raise as raise2 } from "@dxos/debug";
2951
- import { PublicKey as PublicKey10 } from "@dxos/keys";
2952
- import { log as log12 } from "@dxos/log";
2953
- import { ConnectionResetError as ConnectionResetError2, ConnectivityError as ConnectivityError2, ProtocolError as ProtocolError2, UnknownProtocolError as UnknownProtocolError2, trace as trace4 } from "@dxos/protocols";
2956
+ // packages/core/mesh/network-manager/src/transport/webrtc/rtc-connection-factory.ts
2957
+ import { Mutex } from "@dxos/async";
2958
+ var BrowserRtcConnectionFactory = class {
2959
+ async initialize() {
2960
+ }
2961
+ async onConnectionDestroyed() {
2962
+ }
2963
+ async createConnection(config) {
2964
+ return new RTCPeerConnection(config);
2965
+ }
2966
+ async initConnection(connection, info) {
2967
+ }
2968
+ };
2969
+ var NodeRtcConnectionFactory = class _NodeRtcConnectionFactory {
2970
+ static {
2971
+ this._createdConnections = 0;
2972
+ }
2973
+ static {
2974
+ this._cleanupMutex = new Mutex();
2975
+ }
2976
+ // This should be inside the function to avoid triggering `eval` in the global scope.
2977
+ // eslint-disable-next-line no-new-func
2978
+ // TODO(burdon): Do imports here?
2979
+ async initialize() {
2980
+ }
2981
+ async onConnectionDestroyed() {
2982
+ return _NodeRtcConnectionFactory._cleanupMutex.executeSynchronized(async () => {
2983
+ if (--_NodeRtcConnectionFactory._createdConnections === 0) {
2984
+ (await import("#node-datachannel")).cleanup();
2985
+ }
2986
+ });
2987
+ }
2988
+ async createConnection(config) {
2989
+ return _NodeRtcConnectionFactory._cleanupMutex.executeSynchronized(async () => {
2990
+ const { RTCPeerConnection: RTCPeerConnection1 } = await import("#node-datachannel/polyfill");
2991
+ _NodeRtcConnectionFactory._createdConnections++;
2992
+ return new RTCPeerConnection1(config);
2993
+ });
2994
+ }
2995
+ async initConnection(connection, info) {
2996
+ if (info.initiator) {
2997
+ connection.onnegotiationneeded?.(null);
2998
+ }
2999
+ }
3000
+ };
3001
+ var getRtcConnectionFactory = () => {
3002
+ return typeof globalThis.RTCPeerConnection === "undefined" ? new NodeRtcConnectionFactory() : new BrowserRtcConnectionFactory();
3003
+ };
2954
3004
 
2955
- // packages/core/mesh/network-manager/src/transport/webrtc.ts
2956
- var wrtc = null;
2957
- try {
2958
- wrtc = __require("@koush/wrtc");
2959
- } catch {
2960
- }
3005
+ // packages/core/mesh/network-manager/src/transport/webrtc/rtc-peer-connection.ts
3006
+ import { synchronized as synchronized5, Trigger as Trigger3, Mutex as Mutex2 } from "@dxos/async";
3007
+ import { invariant as invariant12 } from "@dxos/invariant";
3008
+ import { log as log13, logInfo as logInfo4 } from "@dxos/log";
3009
+ import { ConnectivityError as ConnectivityError3 } from "@dxos/protocols";
3010
+ import { trace as trace4 } from "@dxos/tracing";
2961
3011
 
2962
- // packages/core/mesh/network-manager/src/transport/simplepeer-transport.ts
2963
- function _ts_decorate6(decorators, target, key, desc) {
2964
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2965
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2966
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2967
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2968
- }
2969
- var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/simplepeer-transport.ts";
2970
- var createSimplePeerTransportFactory = (webrtcConfig, iceProvider) => ({
2971
- createTransport: (options) => new SimplePeerTransport({
2972
- ...options,
2973
- webrtcConfig,
2974
- iceProvider
2975
- })
2976
- });
2977
- var SimplePeerTransport = class {
2978
- get isOpen() {
2979
- return this._piped && !this._closed;
3012
+ // packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-channel.ts
3013
+ import { Duplex } from "@dxos/node-std/stream";
3014
+ import { Event as AsyncEvent } from "@dxos/async";
3015
+ import { Resource } from "@dxos/context";
3016
+ import { ErrorStream as ErrorStream4 } from "@dxos/debug";
3017
+ import { invariant as invariant11 } from "@dxos/invariant";
3018
+ import { log as log12 } from "@dxos/log";
3019
+ import { ConnectivityError as ConnectivityError2 } from "@dxos/protocols";
3020
+
3021
+ // packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-stats.ts
3022
+ var describeSelectedRemoteCandidate = async (connection) => {
3023
+ const stats = connection && await getRtcConnectionStats(connection);
3024
+ const rc = stats?.remoteCandidate;
3025
+ if (!rc) {
3026
+ return "unavailable";
2980
3027
  }
2981
- /**
2982
- * @params opts.config formatted as per https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection
2983
- */
2984
- constructor(_params) {
2985
- this._params = _params;
2986
- this._peer = void 0;
2987
- this._closed = false;
2988
- this._piped = false;
2989
- this.closed = new Event8();
2990
- this.connected = new Event8();
2991
- this.errors = new ErrorStream4();
2992
- this._instanceId = PublicKey10.random().toHex();
3028
+ if (rc.candidateType === "relay") {
3029
+ return `${rc.ip}:${rc.port} relay for ${rc.relatedAddress}:${rc.relatedPort}`;
2993
3030
  }
2994
- async getStats() {
2995
- const stats = await this._getStats();
2996
- if (!stats) {
2997
- return {
2998
- bytesSent: 0,
2999
- bytesReceived: 0,
3000
- packetsSent: 0,
3001
- packetsReceived: 0,
3002
- rawStats: {}
3003
- };
3004
- }
3031
+ return `${rc.ip}:${rc.port} ${rc.candidateType}`;
3032
+ };
3033
+ var createRtcTransportStats = async (connection, topic) => {
3034
+ const stats = connection && await getRtcConnectionStats(connection, topic);
3035
+ if (!stats) {
3005
3036
  return {
3006
- bytesSent: stats.transport.bytesSent,
3007
- bytesReceived: stats.transport.bytesReceived,
3008
- packetsSent: stats.transport.packetsSent,
3009
- packetsReceived: stats.transport.packetsReceived,
3010
- rawStats: stats.raw
3037
+ bytesSent: 0,
3038
+ bytesReceived: 0,
3039
+ packetsSent: 0,
3040
+ packetsReceived: 0,
3041
+ rawStats: {}
3011
3042
  };
3012
3043
  }
3013
- async _getStats() {
3014
- if (typeof this._peer?._pc?.getStats !== "function") {
3015
- return null;
3016
- }
3017
- return await this._peer._pc.getStats().then((stats) => {
3018
- const statsEntries = Array.from(stats.entries());
3019
- const transport = statsEntries.filter((s) => s[1].type === "transport")[0][1];
3020
- const candidatePair = statsEntries.filter((s) => s[0] === transport.selectedCandidatePairId);
3021
- let selectedCandidatePair;
3022
- let remoteCandidate;
3023
- if (candidatePair.length > 0) {
3024
- selectedCandidatePair = candidatePair[0][1];
3025
- remoteCandidate = statsEntries.filter((s) => s[0] === selectedCandidatePair.remoteCandidateId)[0][1];
3026
- }
3027
- return {
3028
- datachannel: statsEntries.filter((s) => s[1].type === "data-channel")[0][1],
3029
- transport,
3030
- selectedCandidatePair,
3031
- remoteCandidate,
3032
- raw: Object.fromEntries(stats.entries())
3033
- };
3034
- });
3044
+ return {
3045
+ bytesSent: stats.dataChannel?.bytesSent,
3046
+ bytesReceived: stats.dataChannel?.bytesReceived,
3047
+ packetsSent: 0,
3048
+ packetsReceived: 0,
3049
+ rawStats: stats.raw
3050
+ };
3051
+ };
3052
+ var getRtcConnectionStats = async (connection, channelTopic) => {
3053
+ const stats = await connection.getStats();
3054
+ const statsEntries = Array.from(stats.entries());
3055
+ const transport = statsEntries.find(([_, entry]) => entry.type === "transport")?.[1];
3056
+ const selectedCandidatePair = transport && statsEntries.find(([entryId]) => entryId === transport.selectedCandidatePairId)?.[1];
3057
+ const remoteCandidate = selectedCandidatePair && statsEntries.find(([entryId]) => entryId === selectedCandidatePair.remoteCandidateId)?.[1];
3058
+ const dataChannel = channelTopic && statsEntries.find(([_, entry]) => entry.type === "data-channel" && entry.label === channelTopic)?.[1];
3059
+ return {
3060
+ transport,
3061
+ selectedCandidatePair,
3062
+ dataChannel,
3063
+ remoteCandidate,
3064
+ raw: Object.fromEntries(stats)
3065
+ };
3066
+ };
3067
+
3068
+ // packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-channel.ts
3069
+ var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-channel.ts";
3070
+ var MAX_MESSAGE_SIZE = 64 * 1024;
3071
+ var MAX_BUFFERED_AMOUNT = 64 * 1024;
3072
+ var RtcTransportChannel = class extends Resource {
3073
+ constructor(_connection, _options) {
3074
+ super();
3075
+ this._connection = _connection;
3076
+ this._options = _options;
3077
+ this.closed = new AsyncEvent();
3078
+ this.connected = new AsyncEvent();
3079
+ this.errors = new ErrorStream4();
3080
+ this._streamDataFlushedCallback = null;
3081
+ this._isChannelCreationInProgress = false;
3035
3082
  }
3036
- async getDetails() {
3037
- const stats = await this._getStats();
3038
- const rc = stats?.remoteCandidate;
3039
- if (!rc) {
3040
- return "unavailable";
3041
- }
3042
- if (rc.candidateType === "relay") {
3043
- return `${rc.ip}:${rc.port}/${rc.protocol} relay for ${rc.relatedAddress}:${rc.relatedPort}`;
3083
+ get isRtcChannelCreationInProgress() {
3084
+ return this._isChannelCreationInProgress;
3085
+ }
3086
+ onConnectionError(error) {
3087
+ if (this.isOpen) {
3088
+ this.errors.raise(error);
3044
3089
  }
3045
- return `${rc.ip}:${rc.port}/${rc.protocol} ${rc.candidateType}`;
3046
3090
  }
3047
- async open() {
3048
- log12.trace("dxos.mesh.webrtc-transport.open", trace4.begin({
3049
- id: this._instanceId
3050
- }), {
3091
+ async _open() {
3092
+ invariant11(!this._isChannelCreationInProgress, void 0, {
3051
3093
  F: __dxlog_file13,
3052
- L: 122,
3094
+ L: 56,
3053
3095
  S: this,
3054
- C: (f, a) => f(...a)
3096
+ A: [
3097
+ "!this._isChannelCreationInProgress",
3098
+ ""
3099
+ ]
3055
3100
  });
3056
- log12("created connection", {
3057
- params: this._params
3058
- }, {
3101
+ this._isChannelCreationInProgress = true;
3102
+ this._connection.createDataChannel(this._options.topic).then((channel) => {
3103
+ if (this.isOpen) {
3104
+ this._channel = channel;
3105
+ this._initChannel(this._channel);
3106
+ } else {
3107
+ this._safeCloseChannel(channel);
3108
+ }
3109
+ }).catch((err) => {
3110
+ if (this.isOpen) {
3111
+ this.errors.raise(new ConnectivityError2(`Failed to create a channel: ${err?.message ?? "unknown reason."}`));
3112
+ }
3113
+ }).finally(() => {
3114
+ this._isChannelCreationInProgress = false;
3115
+ });
3116
+ }
3117
+ async _close() {
3118
+ if (this._channel) {
3119
+ this._safeCloseChannel(this._channel);
3120
+ this._channel = void 0;
3121
+ this._stream = void 0;
3122
+ }
3123
+ this.closed.emit();
3124
+ log12("closed", void 0, {
3059
3125
  F: __dxlog_file13,
3060
- L: 123,
3126
+ L: 86,
3061
3127
  S: this,
3062
3128
  C: (f, a) => f(...a)
3063
3129
  });
3064
- const providedIceServers = await this._params.iceProvider?.getIceServers();
3065
- if (!this._params.webrtcConfig) {
3066
- this._params.webrtcConfig = {};
3067
- }
3068
- this._params.webrtcConfig.iceServers = [
3069
- ...this._params.webrtcConfig.iceServers ?? [],
3070
- ...providedIceServers ?? []
3071
- ];
3072
- this._peer = new SimplePeerConstructor({
3073
- channelName: "dxos.mesh.transport",
3074
- initiator: this._params.initiator,
3075
- wrtc: SimplePeerConstructor.WEBRTC_SUPPORT ? void 0 : wrtc ?? raise2(new Error("wrtc not available")),
3076
- config: this._params.webrtcConfig
3077
- });
3078
- this._peer.on("signal", async (data) => {
3079
- log12("signal", data, {
3080
- F: __dxlog_file13,
3081
- L: 142,
3082
- S: this,
3083
- C: (f, a) => f(...a)
3084
- });
3085
- await this._params.sendSignal({
3086
- payload: {
3087
- data
3088
- }
3089
- });
3090
- });
3091
- this._peer.on("connect", () => {
3092
- log12("connected", void 0, {
3093
- F: __dxlog_file13,
3094
- L: 147,
3095
- S: this,
3096
- C: (f, a) => f(...a)
3097
- });
3098
- this._params.stream.pipe(this._peer).pipe(this._params.stream);
3099
- this._piped = true;
3100
- this.connected.emit();
3101
- });
3102
- this._peer.on("close", async () => {
3103
- log12("closed", void 0, {
3104
- F: __dxlog_file13,
3105
- L: 154,
3106
- S: this,
3107
- C: (f, a) => f(...a)
3108
- });
3109
- await this.close();
3110
- });
3111
- this._peer.on("error", async (err) => {
3112
- if (typeof RTCError !== "undefined" && err instanceof RTCError) {
3113
- if (err.errorDetail === "sctp-failure") {
3114
- this.errors.raise(new ConnectionResetError2("sctp-failure from RTCError", err));
3115
- } else {
3116
- log12.info("unknown RTCError", {
3117
- err
3130
+ }
3131
+ _initChannel(channel) {
3132
+ Object.assign(channel, {
3133
+ onopen: () => {
3134
+ if (!this.isOpen) {
3135
+ log12.warn("channel opened in a closed transport", {
3136
+ topic: this._options.topic
3118
3137
  }, {
3119
3138
  F: __dxlog_file13,
3120
- L: 165,
3139
+ L: 93,
3121
3140
  S: this,
3122
3141
  C: (f, a) => f(...a)
3123
3142
  });
3124
- this.errors.raise(new UnknownProtocolError2("unknown RTCError", err));
3143
+ this._safeCloseChannel(channel);
3144
+ return;
3125
3145
  }
3126
- } else if ("code" in err) {
3127
- log12.info("simple-peer error", err, {
3146
+ log12("onopen", void 0, {
3128
3147
  F: __dxlog_file13,
3129
- L: 170,
3148
+ L: 98,
3130
3149
  S: this,
3131
3150
  C: (f, a) => f(...a)
3132
3151
  });
3133
- switch (err.code) {
3134
- case "ERR_WEBRTC_SUPPORT":
3135
- this.errors.raise(new ProtocolError2("WebRTC not supported", err));
3136
- break;
3137
- case "ERR_SIGNALING":
3138
- this.errors.raise(new ConnectivityError2("signaling failure", err));
3139
- break;
3140
- case "ERR_ICE_CONNECTION_FAILURE":
3141
- case "ERR_DATA_CHANNEL":
3142
- case "ERR_CONNECTION_FAILURE":
3143
- this.errors.raise(new ConnectivityError2("unknown communication failure", err));
3144
- break;
3145
- // errors due to library issues or improper API usage
3146
- case "ERR_CREATE_OFFER":
3147
- case "ERR_CREATE_ANSWER":
3148
- case "ERR_SET_LOCAL_DESCRIPTION":
3149
- case "ERR_SET_REMOTE_DESCRIPTION":
3150
- case "ERR_ADD_ICE_CANDIDATE":
3151
- this.errors.raise(new UnknownProtocolError2("unknown simple-peer library failure", err));
3152
- break;
3153
- default:
3154
- this.errors.raise(new Error("unknown simple-peer error"));
3155
- break;
3156
- }
3157
- } else {
3158
- log12.info("unknown peer connection error", err, {
3152
+ const duplex = new Duplex({
3153
+ read: () => {
3154
+ },
3155
+ write: (chunk, encoding, callback) => {
3156
+ return this._handleChannelWrite(chunk, callback);
3157
+ }
3158
+ });
3159
+ duplex.pipe(this._options.stream).pipe(duplex);
3160
+ this._stream = duplex;
3161
+ this.connected.emit();
3162
+ },
3163
+ onclose: async () => {
3164
+ log12("onclose", void 0, {
3159
3165
  F: __dxlog_file13,
3160
- L: 196,
3166
+ L: 111,
3161
3167
  S: this,
3162
3168
  C: (f, a) => f(...a)
3163
3169
  });
3164
- this.errors.raise(err);
3165
- }
3166
- try {
3167
- if (typeof this._peer?._pc?.getStats === "function") {
3168
- this._peer._pc.getStats().then((stats) => {
3169
- log12.info("report after webrtc error", {
3170
- config: this._params.webrtcConfig,
3171
- stats: Object.fromEntries(stats.entries())
3172
- }, {
3173
- F: __dxlog_file13,
3174
- L: 204,
3175
- S: this,
3176
- C: (f, a) => f(...a)
3177
- });
3170
+ await this.close();
3171
+ },
3172
+ onmessage: (event) => {
3173
+ if (!this._stream) {
3174
+ log12.warn("ignoring message on a closed channel", void 0, {
3175
+ F: __dxlog_file13,
3176
+ L: 117,
3177
+ S: this,
3178
+ C: (f, a) => f(...a)
3178
3179
  });
3180
+ return;
3179
3181
  }
3180
- } catch (err2) {
3181
- log12.catch(err2, void 0, {
3182
- F: __dxlog_file13,
3183
- L: 211,
3184
- S: this,
3185
- C: (f, a) => f(...a)
3186
- });
3182
+ let data = event.data;
3183
+ if (data instanceof ArrayBuffer) {
3184
+ data = Buffer.from(data);
3185
+ }
3186
+ this._stream.push(data);
3187
+ },
3188
+ onerror: (event) => {
3189
+ if (this.isOpen) {
3190
+ const err = event.error instanceof Error ? event.error : new Error(`Datachannel error: ${event.type}.`);
3191
+ this.errors.raise(err);
3192
+ }
3193
+ },
3194
+ onbufferedamountlow: () => {
3195
+ const cb = this._streamDataFlushedCallback;
3196
+ this._streamDataFlushedCallback = null;
3197
+ cb?.();
3187
3198
  }
3188
- await this.close();
3189
- });
3190
- log12.trace("dxos.mesh.webrtc-transport.open", trace4.end({
3191
- id: this._instanceId
3192
- }), {
3193
- F: __dxlog_file13,
3194
- L: 217,
3195
- S: this,
3196
- C: (f, a) => f(...a)
3197
3199
  });
3198
3200
  }
3199
- async close() {
3200
- log12("closing...", void 0, {
3201
- F: __dxlog_file13,
3202
- L: 222,
3203
- S: this,
3204
- C: (f, a) => f(...a)
3205
- });
3206
- if (this._closed) {
3201
+ async _handleChannelWrite(chunk, callback) {
3202
+ if (!this._channel) {
3203
+ log12.warn("writing to a channel after a connection was closed", void 0, {
3204
+ F: __dxlog_file13,
3205
+ L: 145,
3206
+ S: this,
3207
+ C: (f, a) => f(...a)
3208
+ });
3207
3209
  return;
3208
3210
  }
3209
- this._disconnectStreams();
3210
- this._peer.destroy();
3211
- this._closed = true;
3212
- this.closed.emit();
3213
- log12("closed", void 0, {
3214
- F: __dxlog_file13,
3215
- L: 230,
3216
- S: this,
3217
- C: (f, a) => f(...a)
3218
- });
3219
- }
3220
- async onSignal(signal) {
3221
- if (this._closed) {
3211
+ if (chunk.length > MAX_MESSAGE_SIZE) {
3212
+ const error = new Error(`Message too large: ${chunk.length} > ${MAX_MESSAGE_SIZE}.`);
3213
+ this.errors.raise(error);
3214
+ callback();
3222
3215
  return;
3223
3216
  }
3224
- invariant11(signal.payload.data, "Signal message must contain signal data.");
3225
- invariant11(this._peer, "Peer must be initialized before receiving signals.");
3226
- this._peer.signal(signal.payload.data);
3227
- }
3228
- _disconnectStreams() {
3229
- if (this._piped) {
3230
- this._params.stream.unpipe?.(this._peer)?.unpipe?.(this._params.stream);
3217
+ try {
3218
+ this._channel.send(chunk);
3219
+ } catch (err) {
3220
+ this.errors.raise(err);
3221
+ callback();
3222
+ return;
3223
+ }
3224
+ if (this._channel.bufferedAmount > MAX_BUFFERED_AMOUNT) {
3225
+ if (this._streamDataFlushedCallback !== null) {
3226
+ log12.error("consumer trying to write before we are ready for more data", void 0, {
3227
+ F: __dxlog_file13,
3228
+ L: 166,
3229
+ S: this,
3230
+ C: (f, a) => f(...a)
3231
+ });
3232
+ }
3233
+ this._streamDataFlushedCallback = callback;
3234
+ } else {
3235
+ callback();
3231
3236
  }
3232
3237
  }
3233
- };
3234
- _ts_decorate6([
3235
- synchronized5
3236
- ], SimplePeerTransport.prototype, "open", null);
3237
- _ts_decorate6([
3238
- synchronized5
3239
- ], SimplePeerTransport.prototype, "close", null);
3240
- _ts_decorate6([
3241
- synchronized5
3242
- ], SimplePeerTransport.prototype, "onSignal", null);
3238
+ _safeCloseChannel(channel) {
3239
+ try {
3240
+ channel.close();
3241
+ } catch (error) {
3242
+ log12.catch(error, void 0, {
3243
+ F: __dxlog_file13,
3244
+ L: 178,
3245
+ S: this,
3246
+ C: (f, a) => f(...a)
3247
+ });
3248
+ }
3249
+ }
3250
+ onSignal(signal) {
3251
+ return this._connection.onSignal(signal);
3252
+ }
3253
+ async getDetails() {
3254
+ return describeSelectedRemoteCandidate(this._connection.currentConnection);
3255
+ }
3256
+ async getStats() {
3257
+ return createRtcTransportStats(this._connection.currentConnection, this._options.topic);
3258
+ }
3259
+ };
3243
3260
 
3244
- // packages/core/mesh/network-manager/src/transport/simplepeer-transport-service.ts
3245
- import { Duplex } from "@dxos/node-std/stream";
3246
- import { Stream } from "@dxos/codec-protobuf";
3247
- import { invariant as invariant12 } from "@dxos/invariant";
3248
- import { PublicKey as PublicKey11 } from "@dxos/keys";
3249
- import { log as log13 } from "@dxos/log";
3250
- import { ConnectionState as ConnectionState3 } from "@dxos/protocols/proto/dxos/mesh/bridge";
3251
- import { ComplexMap as ComplexMap8 } from "@dxos/util";
3252
- var __dxlog_file14 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/simplepeer-transport-service.ts";
3253
- var SimplePeerTransportService = class {
3254
- constructor(_webrtcConfig, _iceProvider) {
3255
- this._webrtcConfig = _webrtcConfig;
3256
- this._iceProvider = _iceProvider;
3257
- this.transports = new ComplexMap8(PublicKey11.hash);
3261
+ // packages/core/mesh/network-manager/src/transport/webrtc/utils.ts
3262
+ var chooseInitiatorPeer = (peer1Key, peer2Key) => peer1Key < peer2Key ? peer1Key : peer2Key;
3263
+ var areSdpEqual = (sdp1, sdp2) => {
3264
+ const sdp1Lines = deduplicatedSdpLines(sdp1);
3265
+ const sdp2Lines = deduplicatedSdpLines(sdp2);
3266
+ if (sdp1Lines.length !== sdp2Lines.length) {
3267
+ return false;
3268
+ }
3269
+ return sdp1Lines.every((line, idx) => line === sdp2Lines[idx]);
3270
+ };
3271
+ var deduplicatedSdpLines = (sdp) => {
3272
+ const deduplicatedLines = [];
3273
+ const seenLines = [];
3274
+ for (const line of sdp.split("\r\n")) {
3275
+ if (line.startsWith("m")) {
3276
+ seenLines.length = 0;
3277
+ }
3278
+ if (seenLines.includes(line)) {
3279
+ continue;
3280
+ }
3281
+ seenLines.push(line);
3282
+ deduplicatedLines.push(line);
3258
3283
  }
3259
- open(request) {
3260
- const rpcStream = new Stream(({ ready, next, close }) => {
3261
- const duplex = new Duplex({
3262
- read: () => {
3263
- const callbacks = [
3264
- ...transportState.writeCallbacks
3265
- ];
3266
- transportState.writeCallbacks.length = 0;
3267
- for (const cb of callbacks) {
3268
- cb();
3269
- }
3270
- },
3271
- write: function(chunk, _, callback) {
3272
- next({
3273
- data: {
3274
- payload: chunk
3275
- }
3276
- });
3277
- callback();
3278
- }
3284
+ return deduplicatedLines;
3285
+ };
3286
+
3287
+ // packages/core/mesh/network-manager/src/transport/webrtc/rtc-peer-connection.ts
3288
+ function _ts_decorate6(decorators, target, key, desc) {
3289
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3290
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3291
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
3292
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
3293
+ }
3294
+ var __dxlog_file14 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/webrtc/rtc-peer-connection.ts";
3295
+ var RtcPeerConnection = class {
3296
+ constructor(_factory, _options) {
3297
+ this._factory = _factory;
3298
+ this._options = _options;
3299
+ this._channelCreatedCallbacks = /* @__PURE__ */ new Map();
3300
+ this._transportChannels = /* @__PURE__ */ new Map();
3301
+ this._dataChannels = /* @__PURE__ */ new Map();
3302
+ this._readyForCandidates = new Trigger3();
3303
+ this._offerProcessingMutex = new Mutex2();
3304
+ this._initiator = chooseInitiatorPeer(_options.ownPeerKey, _options.remotePeerKey) === _options.ownPeerKey;
3305
+ }
3306
+ get transportChannelCount() {
3307
+ return this._transportChannels.size;
3308
+ }
3309
+ get currentConnection() {
3310
+ return this._connection;
3311
+ }
3312
+ async createDataChannel(topic) {
3313
+ const connection = await this._openConnection();
3314
+ if (!this._transportChannels.has(topic)) {
3315
+ if (!this._transportChannels.size) {
3316
+ this._lockAndCloseConnection();
3317
+ }
3318
+ throw new Error("Transport closed while connection was being open");
3319
+ }
3320
+ if (this._initiator) {
3321
+ const channel = connection.createDataChannel(topic);
3322
+ this._dataChannels.set(topic, channel);
3323
+ return channel;
3324
+ } else {
3325
+ const existingChannel = this._dataChannels.get(topic);
3326
+ if (existingChannel) {
3327
+ return existingChannel;
3328
+ }
3329
+ log13("waiting for initiator-peer to open a data channel", void 0, {
3330
+ F: __dxlog_file14,
3331
+ L: 90,
3332
+ S: this,
3333
+ C: (f, a) => f(...a)
3279
3334
  });
3280
- const transport = new SimplePeerTransport({
3281
- initiator: request.initiator,
3282
- stream: duplex,
3283
- webrtcConfig: this._webrtcConfig,
3284
- sendSignal: async (signal) => {
3285
- next({
3286
- signal: {
3287
- payload: signal
3288
- }
3289
- });
3290
- },
3291
- iceProvider: this._iceProvider
3335
+ return new Promise((resolve, reject) => {
3336
+ this._channelCreatedCallbacks.set(topic, {
3337
+ resolve,
3338
+ reject
3339
+ });
3292
3340
  });
3293
- void transport.open();
3294
- next({
3295
- connection: {
3296
- state: ConnectionState3.CONNECTING
3341
+ }
3342
+ }
3343
+ createTransportChannel(options) {
3344
+ const channel = new RtcTransportChannel(this, options);
3345
+ this._transportChannels.set(options.topic, channel);
3346
+ channel.closed.on(() => {
3347
+ this._transportChannels.delete(options.topic);
3348
+ if (this._transportChannels.size === 0) {
3349
+ this._lockAndCloseConnection();
3350
+ }
3351
+ });
3352
+ return channel;
3353
+ }
3354
+ async _openConnection() {
3355
+ if (this._connection) {
3356
+ return this._connection;
3357
+ }
3358
+ log13("initializing connection...", () => ({
3359
+ remotePeer: this._options.remotePeerKey
3360
+ }), {
3361
+ F: __dxlog_file14,
3362
+ L: 115,
3363
+ S: this,
3364
+ C: (f, a) => f(...a)
3365
+ });
3366
+ const config = await this._loadConnectionConfig();
3367
+ const connection = await this._factory.createConnection(config);
3368
+ const iceCandidateErrors = [];
3369
+ Object.assign(connection, {
3370
+ onnegotiationneeded: async () => {
3371
+ invariant12(this._initiator, void 0, {
3372
+ F: __dxlog_file14,
3373
+ L: 130,
3374
+ S: this,
3375
+ A: [
3376
+ "this._initiator",
3377
+ ""
3378
+ ]
3379
+ });
3380
+ if (connection !== this._connection) {
3381
+ this._onConnectionCallbackAfterClose("onnegotiationneeded", connection);
3382
+ return;
3297
3383
  }
3298
- });
3299
- transport.connected.on(() => {
3300
- next({
3301
- connection: {
3302
- state: ConnectionState3.CONNECTED
3303
- }
3384
+ log13("onnegotiationneeded", void 0, {
3385
+ F: __dxlog_file14,
3386
+ L: 137,
3387
+ S: this,
3388
+ C: (f, a) => f(...a)
3304
3389
  });
3305
- });
3306
- transport.errors.handle((err) => {
3307
- next({
3308
- connection: {
3309
- state: ConnectionState3.CLOSED,
3310
- error: err.toString()
3311
- }
3390
+ try {
3391
+ const offer = await connection.createOffer();
3392
+ await connection.setLocalDescription(offer);
3393
+ await this._sendDescription(connection, offer);
3394
+ } catch (err) {
3395
+ this._lockAndAbort(connection, err);
3396
+ }
3397
+ },
3398
+ // When ICE candidate identified (should be sent to remote peer) and when ICE gathering finalized.
3399
+ // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icecandidate_event
3400
+ onicecandidate: async (event) => {
3401
+ if (connection !== this._connection) {
3402
+ this._onConnectionCallbackAfterClose("onicecandidate", connection);
3403
+ return;
3404
+ }
3405
+ if (event.candidate) {
3406
+ log13("onicecandidate", {
3407
+ candidate: event.candidate.candidate
3408
+ }, {
3409
+ F: __dxlog_file14,
3410
+ L: 156,
3411
+ S: this,
3412
+ C: (f, a) => f(...a)
3413
+ });
3414
+ await this._sendIceCandidate(event.candidate);
3415
+ } else {
3416
+ log13("onicecandidate gathering complete", void 0, {
3417
+ F: __dxlog_file14,
3418
+ L: 159,
3419
+ S: this,
3420
+ C: (f, a) => f(...a)
3421
+ });
3422
+ }
3423
+ },
3424
+ // When error occurs while performing ICE negotiations through a STUN or TURN server.
3425
+ // It's ok for some candidates to fail if a working pair is eventually found.
3426
+ // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icecandidateerror_event
3427
+ onicecandidateerror: (event) => {
3428
+ const { url, errorCode, errorText } = event;
3429
+ iceCandidateErrors.push({
3430
+ url,
3431
+ errorCode,
3432
+ errorText
3312
3433
  });
3313
- close(err);
3314
- });
3315
- transport.closed.on(() => {
3316
- next({
3317
- connection: {
3318
- state: ConnectionState3.CLOSED
3434
+ },
3435
+ // When possible error during ICE gathering.
3436
+ // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceconnectionstatechange_event
3437
+ oniceconnectionstatechange: () => {
3438
+ if (connection !== this._connection) {
3439
+ this._onConnectionCallbackAfterClose("oniceconnectionstatechange", connection);
3440
+ return;
3441
+ }
3442
+ log13("oniceconnectionstatechange", {
3443
+ state: connection.iceConnectionState
3444
+ }, {
3445
+ F: __dxlog_file14,
3446
+ L: 179,
3447
+ S: this,
3448
+ C: (f, a) => f(...a)
3449
+ });
3450
+ if (connection.iceConnectionState === "failed") {
3451
+ this._lockAndAbort(connection, createIceFailureError(iceCandidateErrors));
3452
+ }
3453
+ },
3454
+ // When new track (or channel) is added.
3455
+ // State: { new, connecting, connected, disconnected, failed, closed }
3456
+ // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/connectionstatechange_event
3457
+ onconnectionstatechange: () => {
3458
+ if (connection !== this._connection) {
3459
+ if (connection.connectionState !== "closed" && connection.connectionState !== "failed") {
3460
+ this._onConnectionCallbackAfterClose("onconnectionstatechange", connection);
3319
3461
  }
3462
+ return;
3463
+ }
3464
+ log13("onconnectionstatechange", {
3465
+ state: connection.connectionState
3466
+ }, {
3467
+ F: __dxlog_file14,
3468
+ L: 196,
3469
+ S: this,
3470
+ C: (f, a) => f(...a)
3320
3471
  });
3321
- close();
3322
- });
3323
- const transportState = {
3324
- transport,
3325
- stream: duplex,
3326
- writeCallbacks: [],
3327
- state: "OPEN"
3328
- };
3329
- ready();
3330
- this.transports.set(request.proxyId, transportState);
3472
+ if (connection.connectionState === "failed") {
3473
+ this._lockAndAbort(connection, new Error("Connection failed."));
3474
+ }
3475
+ },
3476
+ onsignalingstatechange: () => {
3477
+ log13("onsignalingstatechange", {
3478
+ state: connection.signalingState
3479
+ }, {
3480
+ F: __dxlog_file14,
3481
+ L: 203,
3482
+ S: this,
3483
+ C: (f, a) => f(...a)
3484
+ });
3485
+ },
3486
+ // When channel is added to connection.
3487
+ // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/datachannel_event
3488
+ ondatachannel: (event) => {
3489
+ invariant12(!this._initiator, "Initiator is expected to create data channels.", {
3490
+ F: __dxlog_file14,
3491
+ L: 209,
3492
+ S: this,
3493
+ A: [
3494
+ "!this._initiator",
3495
+ "'Initiator is expected to create data channels.'"
3496
+ ]
3497
+ });
3498
+ if (connection !== this._connection) {
3499
+ this._onConnectionCallbackAfterClose("ondatachannel", connection);
3500
+ return;
3501
+ }
3502
+ log13("ondatachannel", {
3503
+ label: event.channel.label
3504
+ }, {
3505
+ F: __dxlog_file14,
3506
+ L: 216,
3507
+ S: this,
3508
+ C: (f, a) => f(...a)
3509
+ });
3510
+ this._dataChannels.set(event.channel.label, event.channel);
3511
+ const pendingCallback = this._channelCreatedCallbacks.get(event.channel.label);
3512
+ if (pendingCallback) {
3513
+ this._channelCreatedCallbacks.delete(event.channel.label);
3514
+ pendingCallback.resolve(event.channel);
3515
+ }
3516
+ }
3331
3517
  });
3332
- return rpcStream;
3518
+ this._connection = connection;
3519
+ this._readyForCandidates.reset();
3520
+ await this._factory.initConnection(connection, {
3521
+ initiator: this._initiator
3522
+ });
3523
+ return this._connection;
3333
3524
  }
3334
- async sendSignal({ proxyId, signal }) {
3335
- invariant12(this.transports.has(proxyId), void 0, {
3525
+ _lockAndAbort(connection, error) {
3526
+ this._abortConnection(connection, error);
3527
+ }
3528
+ _abortConnection(connection, error) {
3529
+ if (connection !== this._connection) {
3530
+ log13.error("attempted to abort an inactive connection", {
3531
+ error
3532
+ }, {
3533
+ F: __dxlog_file14,
3534
+ L: 241,
3535
+ S: this,
3536
+ C: (f, a) => f(...a)
3537
+ });
3538
+ this._safeCloseConnection(connection);
3539
+ return;
3540
+ }
3541
+ for (const [topic, pendingCallback] of this._channelCreatedCallbacks.entries()) {
3542
+ pendingCallback.reject(error);
3543
+ this._transportChannels.delete(topic);
3544
+ }
3545
+ this._channelCreatedCallbacks.clear();
3546
+ for (const channel of this._transportChannels.values()) {
3547
+ channel.onConnectionError(error);
3548
+ }
3549
+ this._transportChannels.clear();
3550
+ this._safeCloseConnection();
3551
+ log13("connection aborted", {
3552
+ reason: error.message
3553
+ }, {
3336
3554
  F: __dxlog_file14,
3337
- L: 124,
3555
+ L: 255,
3338
3556
  S: this,
3339
- A: [
3340
- "this.transports.has(proxyId)",
3341
- ""
3342
- ]
3557
+ C: (f, a) => f(...a)
3343
3558
  });
3344
- await this.transports.get(proxyId).transport.onSignal(signal);
3345
3559
  }
3346
- async getDetails({ proxyId }) {
3347
- invariant12(this.transports.has(proxyId), void 0, {
3560
+ _lockAndCloseConnection() {
3561
+ invariant12(this._transportChannels.size === 0, void 0, {
3348
3562
  F: __dxlog_file14,
3349
- L: 129,
3563
+ L: 260,
3350
3564
  S: this,
3351
3565
  A: [
3352
- "this.transports.has(proxyId)",
3566
+ "this._transportChannels.size === 0",
3353
3567
  ""
3354
3568
  ]
3355
3569
  });
3356
- return {
3357
- details: await this.transports.get(proxyId).transport.getDetails()
3358
- };
3570
+ if (this._connection) {
3571
+ this._safeCloseConnection();
3572
+ log13("connection closed", void 0, {
3573
+ F: __dxlog_file14,
3574
+ L: 263,
3575
+ S: this,
3576
+ C: (f, a) => f(...a)
3577
+ });
3578
+ }
3359
3579
  }
3360
- async getStats({ proxyId }) {
3361
- invariant12(this.transports.has(proxyId), void 0, {
3580
+ async onSignal(signal) {
3581
+ const connection = this._connection;
3582
+ if (!connection) {
3583
+ log13.warn("a signal ignored because the connection was closed", {
3584
+ type: signal.payload.data.type
3585
+ }, {
3586
+ F: __dxlog_file14,
3587
+ L: 271,
3588
+ S: this,
3589
+ C: (f, a) => f(...a)
3590
+ });
3591
+ return;
3592
+ }
3593
+ const data = signal.payload.data;
3594
+ switch (data.type) {
3595
+ case "offer": {
3596
+ await this._offerProcessingMutex.executeSynchronized(async () => {
3597
+ if (isRemoteDescriptionSet(connection, data)) {
3598
+ return;
3599
+ }
3600
+ if (connection.connectionState !== "new") {
3601
+ this._abortConnection(connection, new Error(`Received an offer in ${connection.connectionState}.`));
3602
+ return;
3603
+ }
3604
+ try {
3605
+ await connection.setRemoteDescription({
3606
+ type: data.type,
3607
+ sdp: data.sdp
3608
+ });
3609
+ const answer = await connection.createAnswer();
3610
+ await connection.setLocalDescription(answer);
3611
+ await this._sendDescription(connection, answer);
3612
+ this._onSessionNegotiated(connection);
3613
+ } catch (err) {
3614
+ this._abortConnection(connection, new Error("Error handling a remote offer.", {
3615
+ cause: err
3616
+ }));
3617
+ }
3618
+ });
3619
+ break;
3620
+ }
3621
+ case "answer":
3622
+ await this._offerProcessingMutex.executeSynchronized(async () => {
3623
+ try {
3624
+ if (isRemoteDescriptionSet(connection, data)) {
3625
+ return;
3626
+ }
3627
+ if (connection.signalingState !== "have-local-offer") {
3628
+ this._abortConnection(connection, new Error(`Unexpected answer from remote peer, signalingState was ${connection.signalingState}.`));
3629
+ return;
3630
+ }
3631
+ await connection.setRemoteDescription({
3632
+ type: data.type,
3633
+ sdp: data.sdp
3634
+ });
3635
+ this._onSessionNegotiated(connection);
3636
+ } catch (err) {
3637
+ this._abortConnection(connection, new Error("Error handling a remote answer.", {
3638
+ cause: err
3639
+ }));
3640
+ }
3641
+ });
3642
+ break;
3643
+ case "candidate":
3644
+ void this._processIceCandidate(connection, data.candidate);
3645
+ break;
3646
+ default:
3647
+ this._abortConnection(connection, new Error(`Unknown signal type ${data.type}.`));
3648
+ break;
3649
+ }
3650
+ log13("signal processed", {
3651
+ type: data.type
3652
+ }, {
3362
3653
  F: __dxlog_file14,
3363
- L: 134,
3654
+ L: 330,
3364
3655
  S: this,
3365
- A: [
3366
- "this.transports.has(proxyId)",
3367
- ""
3368
- ]
3656
+ C: (f, a) => f(...a)
3369
3657
  });
3370
- return {
3371
- stats: await this.transports.get(proxyId).transport.getStats()
3372
- };
3373
3658
  }
3374
- async sendData({ proxyId, payload }) {
3375
- if (this.transports.get(proxyId)?.state !== "OPEN") {
3376
- log13.debug("transport is closed", void 0, {
3659
+ async _processIceCandidate(connection, candidate) {
3660
+ try {
3661
+ await this._readyForCandidates.wait();
3662
+ if (connection === this._connection) {
3663
+ log13("adding ice candidate", {
3664
+ candidate
3665
+ }, {
3666
+ F: __dxlog_file14,
3667
+ L: 338,
3668
+ S: this,
3669
+ C: (f, a) => f(...a)
3670
+ });
3671
+ await connection.addIceCandidate(candidate);
3672
+ }
3673
+ } catch (err) {
3674
+ log13.catch(err, void 0, {
3675
+ F: __dxlog_file14,
3676
+ L: 342,
3677
+ S: this,
3678
+ C: (f, a) => f(...a)
3679
+ });
3680
+ }
3681
+ }
3682
+ _onSessionNegotiated(connection) {
3683
+ if (connection === this._connection) {
3684
+ log13("ready to process ice candidates", void 0, {
3685
+ F: __dxlog_file14,
3686
+ L: 348,
3687
+ S: this,
3688
+ C: (f, a) => f(...a)
3689
+ });
3690
+ this._readyForCandidates.wake();
3691
+ } else {
3692
+ log13.warn("session was negotiated after connection became inactive", void 0, {
3377
3693
  F: __dxlog_file14,
3378
- L: 140,
3694
+ L: 351,
3379
3695
  S: this,
3380
3696
  C: (f, a) => f(...a)
3381
3697
  });
3382
3698
  }
3383
- invariant12(this.transports.has(proxyId), void 0, {
3699
+ }
3700
+ _onConnectionCallbackAfterClose(callback, connection) {
3701
+ log13.warn("callback invoked after a connection was destroyed, this is probably a bug", {
3702
+ callback,
3703
+ state: connection.connectionState
3704
+ }, {
3384
3705
  F: __dxlog_file14,
3385
- L: 142,
3706
+ L: 356,
3386
3707
  S: this,
3387
- A: [
3388
- "this.transports.has(proxyId)",
3389
- ""
3390
- ]
3708
+ C: (f, a) => f(...a)
3391
3709
  });
3392
- const state = this.transports.get(proxyId);
3393
- const bufferHasSpace = state.stream.push(payload);
3394
- if (!bufferHasSpace) {
3395
- await new Promise((resolve) => {
3396
- state.writeCallbacks.push(resolve);
3710
+ this._safeCloseConnection(connection);
3711
+ }
3712
+ _safeCloseConnection(connection = this._connection) {
3713
+ const resetFields = this._connection && connection === this._connection;
3714
+ try {
3715
+ connection?.close();
3716
+ } catch (err) {
3717
+ log13.catch(err, void 0, {
3718
+ F: __dxlog_file14,
3719
+ L: 368,
3720
+ S: this,
3721
+ C: (f, a) => f(...a)
3722
+ });
3723
+ }
3724
+ if (resetFields) {
3725
+ this._connection = void 0;
3726
+ this._dataChannels.clear();
3727
+ this._readyForCandidates.wake();
3728
+ void this._factory.onConnectionDestroyed().catch((err) => log13.catch(err, void 0, {
3729
+ F: __dxlog_file14,
3730
+ L: 374,
3731
+ S: this,
3732
+ C: (f, a) => f(...a)
3733
+ }));
3734
+ for (const [_, pendingCallback] of this._channelCreatedCallbacks.entries()) {
3735
+ pendingCallback.reject("Connection closed.");
3736
+ }
3737
+ this._channelCreatedCallbacks.clear();
3738
+ }
3739
+ }
3740
+ async _loadConnectionConfig() {
3741
+ const config = {
3742
+ ...this._options.webrtcConfig
3743
+ };
3744
+ try {
3745
+ const providedIceServers = await this._options.iceProvider?.getIceServers() ?? [];
3746
+ if (providedIceServers.length > 0) {
3747
+ config.iceServers = [
3748
+ ...config.iceServers ?? [],
3749
+ ...providedIceServers
3750
+ ];
3751
+ }
3752
+ } catch (error) {
3753
+ log13.catch(error, void 0, {
3754
+ F: __dxlog_file14,
3755
+ L: 390,
3756
+ S: this,
3757
+ C: (f, a) => f(...a)
3758
+ });
3759
+ }
3760
+ return config;
3761
+ }
3762
+ async _sendIceCandidate(candidate) {
3763
+ try {
3764
+ await this._options.sendSignal({
3765
+ payload: {
3766
+ data: {
3767
+ type: "candidate",
3768
+ candidate: {
3769
+ candidate: candidate.candidate,
3770
+ // These fields never seem to be not null, but connecting to Chrome doesn't work if they are.
3771
+ sdpMLineIndex: candidate.sdpMLineIndex ?? "0",
3772
+ sdpMid: candidate.sdpMid ?? "0"
3773
+ }
3774
+ }
3775
+ }
3776
+ });
3777
+ } catch (err) {
3778
+ log13.warn("signaling error", {
3779
+ err
3780
+ }, {
3781
+ F: __dxlog_file14,
3782
+ L: 411,
3783
+ S: this,
3784
+ C: (f, a) => f(...a)
3397
3785
  });
3398
3786
  }
3399
3787
  }
3400
- async close({ proxyId }) {
3401
- await this.transports.get(proxyId)?.transport.close();
3402
- await this.transports.get(proxyId)?.stream.end();
3403
- if (this.transports.get(proxyId)) {
3404
- this.transports.get(proxyId).state = "CLOSED";
3788
+ async _sendDescription(connection, description) {
3789
+ if (connection !== this._connection) {
3790
+ return;
3405
3791
  }
3406
- log13("Closed.", void 0, {
3407
- F: __dxlog_file14,
3408
- L: 158,
3409
- S: this,
3410
- C: (f, a) => f(...a)
3792
+ const data = {
3793
+ type: description.type,
3794
+ sdp: description.sdp
3795
+ };
3796
+ await this._options.sendSignal({
3797
+ payload: {
3798
+ data
3799
+ }
3411
3800
  });
3412
3801
  }
3802
+ get _connectionInfo() {
3803
+ const connectionInfo = this._connection && {
3804
+ connectionState: this._connection.connectionState,
3805
+ iceConnectionState: this._connection.iceConnectionState,
3806
+ iceGatheringState: this._connection.iceGatheringState,
3807
+ signalingState: this._connection.signalingState,
3808
+ remoteDescription: this._connection.remoteDescription,
3809
+ localDescription: this._connection.localDescription
3810
+ };
3811
+ return {
3812
+ ...connectionInfo,
3813
+ ts: Date.now(),
3814
+ remotePeerKey: this._options.remotePeerKey,
3815
+ channels: [
3816
+ ...this._transportChannels.keys()
3817
+ ].map((topic) => topic),
3818
+ config: this._connection?.getConfiguration()
3819
+ };
3820
+ }
3821
+ get _loggerContext() {
3822
+ return {
3823
+ ownPeerKey: this._options.ownPeerKey,
3824
+ remotePeerKey: this._options.remotePeerKey,
3825
+ initiator: this._initiator,
3826
+ channels: this._transportChannels.size
3827
+ };
3828
+ }
3829
+ };
3830
+ _ts_decorate6([
3831
+ synchronized5
3832
+ ], RtcPeerConnection.prototype, "_openConnection", null);
3833
+ _ts_decorate6([
3834
+ synchronized5
3835
+ ], RtcPeerConnection.prototype, "_lockAndAbort", null);
3836
+ _ts_decorate6([
3837
+ synchronized5
3838
+ ], RtcPeerConnection.prototype, "_lockAndCloseConnection", null);
3839
+ _ts_decorate6([
3840
+ synchronized5
3841
+ ], RtcPeerConnection.prototype, "onSignal", null);
3842
+ _ts_decorate6([
3843
+ trace4.info()
3844
+ ], RtcPeerConnection.prototype, "_connectionInfo", null);
3845
+ _ts_decorate6([
3846
+ logInfo4
3847
+ ], RtcPeerConnection.prototype, "_loggerContext", null);
3848
+ RtcPeerConnection = _ts_decorate6([
3849
+ trace4.resource()
3850
+ ], RtcPeerConnection);
3851
+ var isRemoteDescriptionSet = (connection, data) => {
3852
+ if (!connection.remoteDescription?.type || connection.remoteDescription?.type !== data.type) {
3853
+ return false;
3854
+ }
3855
+ return areSdpEqual(connection.remoteDescription.sdp, data.sdp);
3856
+ };
3857
+ var createIceFailureError = (details) => {
3858
+ const candidateErrors = details.map(({ url, errorCode, errorText }) => `${errorCode} ${url}: ${errorText}`);
3859
+ return new ConnectivityError3(`ICE failed:
3860
+ ${candidateErrors.join("\n")}`);
3861
+ };
3862
+
3863
+ // packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-factory.ts
3864
+ var createRtcTransportFactory = (webrtcConfig, iceProvider) => {
3865
+ const connectionFactory = getRtcConnectionFactory();
3866
+ return {
3867
+ createTransport: (options) => {
3868
+ const connection = new RtcPeerConnection(connectionFactory, {
3869
+ ownPeerKey: options.ownPeerKey,
3870
+ remotePeerKey: options.remotePeerKey,
3871
+ sendSignal: options.sendSignal,
3872
+ webrtcConfig,
3873
+ iceProvider
3874
+ });
3875
+ return connection.createTransportChannel(options);
3876
+ }
3877
+ };
3413
3878
  };
3414
3879
 
3415
- // packages/core/mesh/network-manager/src/transport/simplepeer-transport-proxy.ts
3880
+ // packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-proxy.ts
3416
3881
  import { Writable } from "@dxos/node-std/stream";
3417
- import { Event as Event9, scheduleTask as scheduleTask4 } from "@dxos/async";
3418
- import { Context as Context6 } from "@dxos/context";
3882
+ import { Event as Event8, scheduleTask as scheduleTask4 } from "@dxos/async";
3883
+ import { Resource as Resource2 } from "@dxos/context";
3419
3884
  import { ErrorStream as ErrorStream5 } from "@dxos/debug";
3420
3885
  import { invariant as invariant13 } from "@dxos/invariant";
3421
- import { PublicKey as PublicKey12 } from "@dxos/keys";
3886
+ import { PublicKey as PublicKey10 } from "@dxos/keys";
3422
3887
  import { log as log14 } from "@dxos/log";
3423
- import { ConnectionResetError as ConnectionResetError3, TimeoutError as TimeoutError3, ProtocolError as ProtocolError3, ConnectivityError as ConnectivityError3, UnknownProtocolError as UnknownProtocolError3 } from "@dxos/protocols";
3424
- import { ConnectionState as ConnectionState4 } from "@dxos/protocols/proto/dxos/mesh/bridge";
3888
+ import { ConnectionResetError as ConnectionResetError2, ConnectivityError as ConnectivityError4, TimeoutError as TimeoutError3 } from "@dxos/protocols";
3889
+ import { ConnectionState as ConnectionState3 } from "@dxos/protocols/proto/dxos/mesh/bridge";
3425
3890
  import { arrayToBuffer } from "@dxos/util";
3426
- var __dxlog_file15 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/simplepeer-transport-proxy.ts";
3891
+ var __dxlog_file15 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-proxy.ts";
3427
3892
  var RPC_TIMEOUT = 1e4;
3893
+ var CLOSE_RPC_TIMEOUT = 3e3;
3428
3894
  var RESP_MIN_THRESHOLD = 500;
3429
- var TIMEOUT_THRESHOLD = 10;
3430
- var SimplePeerTransportProxy = class {
3895
+ var RtcTransportProxy = class extends Resource2 {
3431
3896
  constructor(_options) {
3897
+ super();
3432
3898
  this._options = _options;
3433
- this._proxyId = PublicKey12.random();
3434
- this._ctx = new Context6(void 0, {
3435
- F: __dxlog_file15,
3436
- L: 37
3437
- });
3438
- this._timeoutCount = 0;
3439
- this.closed = new Event9();
3440
- this.connected = new Event9();
3899
+ this._proxyId = PublicKey10.random();
3900
+ this.closed = new Event8();
3901
+ this.connected = new Event8();
3441
3902
  this.errors = new ErrorStream5();
3442
- this._closed = false;
3443
3903
  }
3444
- get isOpen() {
3445
- return !this._closed;
3446
- }
3447
- async open() {
3448
- this._serviceStream = this._options.bridgeService.open({
3449
- proxyId: this._proxyId,
3450
- initiator: this._options.initiator
3451
- }, {
3452
- timeout: RPC_TIMEOUT
3453
- });
3454
- this._serviceStream.waitUntilReady().then(() => {
3455
- this._serviceStream.subscribe(async (event) => {
3456
- log14("SimplePeerTransportProxy: event", event, {
3904
+ async _open() {
3905
+ let stream;
3906
+ try {
3907
+ stream = this._options.bridgeService.open({
3908
+ proxyId: this._proxyId,
3909
+ remotePeerKey: this._options.remotePeerKey,
3910
+ ownPeerKey: this._options.ownPeerKey,
3911
+ topic: this._options.topic,
3912
+ initiator: this._options.initiator ?? false
3913
+ }, {
3914
+ timeout: RPC_TIMEOUT
3915
+ });
3916
+ } catch (error) {
3917
+ this.errors.raise(error);
3918
+ return;
3919
+ }
3920
+ this._serviceStream = stream;
3921
+ stream.waitUntilReady().then(() => {
3922
+ stream.subscribe(async (event) => {
3923
+ log14("rtc transport proxy event", event, {
3457
3924
  F: __dxlog_file15,
3458
3925
  L: 66,
3459
3926
  S: this,
@@ -3466,20 +3933,34 @@ var SimplePeerTransportProxy = class {
3466
3933
  } else if (event.signal) {
3467
3934
  await this._handleSignal(event.signal);
3468
3935
  }
3936
+ }, (err) => {
3937
+ log14("rtc bridge stream closed", {
3938
+ err
3939
+ }, {
3940
+ F: __dxlog_file15,
3941
+ L: 76,
3942
+ S: this,
3943
+ C: (f, a) => f(...a)
3944
+ });
3945
+ if (err) {
3946
+ this._raiseIfOpen(err);
3947
+ } else {
3948
+ void this.close();
3949
+ }
3469
3950
  });
3470
- const proxyStream = new Writable({
3951
+ const connectorStream = new Writable({
3471
3952
  write: (chunk, _, callback) => {
3472
- const then = performance.now();
3953
+ const sendStartMs = Date.now();
3473
3954
  this._options.bridgeService.sendData({
3474
3955
  proxyId: this._proxyId,
3475
3956
  payload: chunk
3476
3957
  }, {
3477
3958
  timeout: RPC_TIMEOUT
3478
3959
  }).then(() => {
3479
- if (performance.now() - then > RESP_MIN_THRESHOLD) {
3960
+ if (Date.now() - sendStartMs > RESP_MIN_THRESHOLD) {
3480
3961
  log14("slow response, delaying callback", void 0, {
3481
3962
  F: __dxlog_file15,
3482
- L: 90,
3963
+ L: 93,
3483
3964
  S: this,
3484
3965
  C: (f, a) => f(...a)
3485
3966
  });
@@ -3487,60 +3968,41 @@ var SimplePeerTransportProxy = class {
3487
3968
  } else {
3488
3969
  callback();
3489
3970
  }
3490
- this._timeoutCount = 0;
3491
3971
  }, (err) => {
3492
- if (err instanceof TimeoutError3 || err.constructor.name === "TimeoutError") {
3493
- if (this._timeoutCount++ > TIMEOUT_THRESHOLD) {
3494
- throw new TimeoutError3(`too many timeouts (${this._timeoutCount} > ${TIMEOUT_THRESHOLD}`);
3495
- } else {
3496
- log14("timeout error, but still invoking callback", void 0, {
3497
- F: __dxlog_file15,
3498
- L: 102,
3499
- S: this,
3500
- C: (f, a) => f(...a)
3501
- });
3502
- callback();
3503
- }
3504
- } else {
3505
- log14.catch(err, void 0, {
3506
- F: __dxlog_file15,
3507
- L: 106,
3508
- S: this,
3509
- C: (f, a) => f(...a)
3510
- });
3511
- }
3972
+ callback();
3973
+ this._raiseIfOpen(err);
3512
3974
  });
3513
3975
  }
3514
3976
  });
3515
- proxyStream.on("error", (err) => {
3516
- log14("proxystream error", {
3517
- err
3518
- }, {
3519
- F: __dxlog_file15,
3520
- L: 114,
3521
- S: this,
3522
- C: (f, a) => f(...a)
3523
- });
3977
+ connectorStream.on("error", (err) => {
3978
+ this._raiseIfOpen(err);
3524
3979
  });
3525
- this._options.stream.pipe(proxyStream);
3526
- }, (error) => log14.catch(error, void 0, {
3527
- F: __dxlog_file15,
3528
- L: 119,
3529
- S: this,
3530
- C: (f, a) => f(...a)
3531
- }));
3980
+ this._options.stream.pipe(connectorStream);
3981
+ }, (error) => {
3982
+ if (error) {
3983
+ this._raiseIfOpen(error);
3984
+ } else {
3985
+ void this.close();
3986
+ }
3987
+ });
3532
3988
  }
3533
- async close() {
3534
- await this._ctx.dispose();
3535
- if (this._closed) {
3536
- return;
3989
+ async _close() {
3990
+ try {
3991
+ await this._serviceStream?.close();
3992
+ this._serviceStream = void 0;
3993
+ } catch (err) {
3994
+ log14.catch(err, void 0, {
3995
+ F: __dxlog_file15,
3996
+ L: 128,
3997
+ S: this,
3998
+ C: (f, a) => f(...a)
3999
+ });
3537
4000
  }
3538
- await this._serviceStream.close();
3539
4001
  try {
3540
4002
  await this._options.bridgeService.close({
3541
4003
  proxyId: this._proxyId
3542
4004
  }, {
3543
- timeout: RPC_TIMEOUT
4005
+ timeout: CLOSE_RPC_TIMEOUT
3544
4006
  });
3545
4007
  } catch (err) {
3546
4008
  log14.catch(err, void 0, {
@@ -3551,7 +4013,6 @@ var SimplePeerTransportProxy = class {
3551
4013
  });
3552
4014
  }
3553
4015
  this.closed.emit();
3554
- this._closed = true;
3555
4016
  }
3556
4017
  async onSignal(signal) {
3557
4018
  this._options.bridgeService.sendSignal({
@@ -3559,581 +4020,347 @@ var SimplePeerTransportProxy = class {
3559
4020
  signal
3560
4021
  }, {
3561
4022
  timeout: RPC_TIMEOUT
3562
- }).catch((err) => this.errors.raise(decodeError(err)));
4023
+ }).catch((err) => this._raiseIfOpen(decodeError(err)));
3563
4024
  }
3564
4025
  async _handleConnection(connectionEvent) {
3565
4026
  if (connectionEvent.error) {
3566
4027
  this.errors.raise(decodeError(connectionEvent.error));
4028
+ return;
3567
4029
  }
3568
4030
  switch (connectionEvent.state) {
3569
- case ConnectionState4.CONNECTED: {
4031
+ case ConnectionState3.CONNECTED: {
3570
4032
  this.connected.emit();
3571
4033
  break;
3572
4034
  }
3573
- case ConnectionState4.CLOSED: {
4035
+ case ConnectionState3.CLOSED: {
3574
4036
  await this.close();
3575
4037
  break;
3576
4038
  }
3577
4039
  }
3578
4040
  }
3579
4041
  _handleData(dataEvent) {
3580
- this._options.stream.write(arrayToBuffer(dataEvent.payload));
4042
+ try {
4043
+ this._options.stream.write(arrayToBuffer(dataEvent.payload));
4044
+ } catch (error) {
4045
+ this._raiseIfOpen(error);
4046
+ }
3581
4047
  }
3582
4048
  async _handleSignal(signalEvent) {
3583
- await this._options.sendSignal(signalEvent.payload);
3584
- }
3585
- async getDetails() {
3586
- return (await this._options.bridgeService.getDetails({
3587
- proxyId: this._proxyId
3588
- }, {
3589
- timeout: RPC_TIMEOUT
3590
- })).details;
3591
- }
3592
- async getStats() {
3593
- return (await this._options.bridgeService.getStats({
3594
- proxyId: this._proxyId
3595
- }, {
3596
- timeout: RPC_TIMEOUT
3597
- })).stats;
3598
- }
3599
- /**
3600
- * Called when underlying proxy service becomes unavailable.
3601
- */
3602
- // TODO(burdon): Option on close method.
3603
- forceClose() {
3604
- void this._serviceStream.close();
3605
- this.closed.emit();
3606
- this._closed = true;
3607
- }
3608
- };
3609
- var SimplePeerTransportProxyFactory = class {
3610
- constructor() {
3611
- this._connections = /* @__PURE__ */ new Set();
3612
- }
3613
- /**
3614
- * Sets the current BridgeService to be used to open connections.
3615
- * Calling this method will close any existing connections.
3616
- */
3617
- setBridgeService(bridgeService) {
3618
- this._bridgeService = bridgeService;
3619
- for (const connection of this._connections) {
3620
- connection.forceClose();
4049
+ try {
4050
+ await this._options.sendSignal(signalEvent.payload);
4051
+ } catch (error) {
4052
+ const type = signalEvent.payload.payload.data?.type;
4053
+ if (type === "offer" || type === "answer") {
4054
+ this._raiseIfOpen(new ConnectivityError4(`Session establishment failed: ${type} couldn't be sent.`));
4055
+ }
3621
4056
  }
3622
- return this;
3623
- }
3624
- createTransport(options) {
3625
- invariant13(this._bridgeService, "SimplePeerTransportProxyFactory is not ready to open connections", {
3626
- F: __dxlog_file15,
3627
- L: 218,
3628
- S: this,
3629
- A: [
3630
- "this._bridgeService",
3631
- "'SimplePeerTransportProxyFactory is not ready to open connections'"
3632
- ]
3633
- });
3634
- const transport = new SimplePeerTransportProxy({
3635
- ...options,
3636
- bridgeService: this._bridgeService
3637
- });
3638
- this._connections.add(transport);
3639
- transport.closed.on(() => this._connections.delete(transport));
3640
- return transport;
3641
- }
3642
- };
3643
- var decodeError = (err) => {
3644
- const message = typeof err === "string" ? err : err.message;
3645
- if (message.includes("CONNECTION_RESET")) {
3646
- return new ConnectionResetError3(message);
3647
- } else if (message.includes("TIMEOUT")) {
3648
- return new TimeoutError3(message);
3649
- } else if (message.includes("PROTOCOL_ERROR")) {
3650
- return new ProtocolError3(message);
3651
- } else if (message.includes("CONNECTIVITY_ERROR")) {
3652
- return new ConnectivityError3(message);
3653
- } else if (message.includes("UNKNOWN_PROTOCOL_ERROR")) {
3654
- return new UnknownProtocolError3(message);
3655
- } else {
3656
- return typeof err === "string" ? new Error(err) : err;
3657
- }
3658
- };
3659
-
3660
- // packages/core/mesh/network-manager/src/transport/libdatachannel-transport.ts
3661
- import { Duplex as Duplex2 } from "stream";
3662
- import { Event as Event10, Trigger as Trigger3, synchronized as synchronized6 } from "@dxos/async";
3663
- import { ErrorStream as ErrorStream6 } from "@dxos/debug";
3664
- import { invariant as invariant14 } from "@dxos/invariant";
3665
- import { log as log15 } from "@dxos/log";
3666
- function _ts_decorate7(decorators, target, key, desc) {
3667
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3668
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3669
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
3670
- return c > 3 && r && Object.defineProperty(target, key, r), r;
3671
- }
3672
- var __dxlog_file16 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/libdatachannel-transport.ts";
3673
- var DATACHANNEL_LABEL = "dxos.mesh.transport";
3674
- var MAX_BUFFERED_AMOUNT = 64 * 1024;
3675
- var MAX_MESSAGE_SIZE = 64 * 1024;
3676
- var createLibDataChannelTransportFactory = (webrtcConfig, iceProvider) => {
3677
- return {
3678
- createTransport: (options) => new LibDataChannelTransport({
3679
- ...options,
3680
- webrtcConfig,
3681
- iceProvider
3682
- })
3683
- };
3684
- };
3685
- var LibDataChannelTransport = class _LibDataChannelTransport {
3686
- static {
3687
- this._instanceCount = 0;
3688
- }
3689
- constructor(_options) {
3690
- this._options = _options;
3691
- this._closed = false;
3692
- this._connected = false;
3693
- this._writeCallback = null;
3694
- this._readyForCandidates = new Trigger3();
3695
- this.closed = new Event10();
3696
- this.connected = new Event10();
3697
- this.errors = new ErrorStream6();
3698
4057
  }
3699
- get isOpen() {
3700
- return !!this._peer && !this._closed;
3701
- }
3702
- async open() {
3703
- if (this._closed) {
3704
- this.errors.raise(new Error("connection already closed"));
3705
- }
3706
- const { RTCPeerConnection } = (await importESM("node-datachannel/polyfill")).default;
3707
- const providedIceServers = await this._options.iceProvider?.getIceServers();
3708
- if (!this._options.webrtcConfig) {
3709
- this._options.webrtcConfig = {};
3710
- }
3711
- this._options.webrtcConfig.iceServers = [
3712
- ...this._options.webrtcConfig.iceServers ?? [],
3713
- ...providedIceServers ?? []
3714
- ];
3715
- this._peer = new RTCPeerConnection(this._options.webrtcConfig);
3716
- this._peer.onicecandidateerror = (event) => {
3717
- log15.error("peer.onicecandidateerror", {
3718
- event
3719
- }, {
3720
- F: __dxlog_file16,
3721
- L: 93,
3722
- S: this,
3723
- C: (f, a) => f(...a)
3724
- });
3725
- };
3726
- this._peer.onconnectionstatechange = (event) => {
3727
- log15.debug("peer.onconnectionstatechange", {
3728
- event,
3729
- peerConnectionState: this._peer?.connectionState,
3730
- transportConnectionState: this._connected
4058
+ async getDetails() {
4059
+ try {
4060
+ const response = await this._options.bridgeService.getDetails({
4061
+ proxyId: this._proxyId
3731
4062
  }, {
3732
- F: __dxlog_file16,
3733
- L: 97,
3734
- S: this,
3735
- C: (f, a) => f(...a)
4063
+ timeout: RPC_TIMEOUT
3736
4064
  });
3737
- };
3738
- this._peer.onicecandidate = async (event) => {
3739
- log15.debug("peer.onicecandidate", {
3740
- event
4065
+ return response.details;
4066
+ } catch (err) {
4067
+ return "bridge-svc unreachable";
4068
+ }
4069
+ }
4070
+ async getStats() {
4071
+ try {
4072
+ const response = await this._options.bridgeService.getStats({
4073
+ proxyId: this._proxyId
3741
4074
  }, {
3742
- F: __dxlog_file16,
3743
- L: 107,
3744
- S: this,
3745
- C: (f, a) => f(...a)
3746
- });
3747
- if (event.candidate) {
3748
- try {
3749
- await this._options.sendSignal({
3750
- payload: {
3751
- data: {
3752
- type: "candidate",
3753
- candidate: {
3754
- candidate: event.candidate.candidate,
3755
- // These fields never seem to be not null, but connecting to Chrome doesn't work if they are.
3756
- sdpMLineIndex: event.candidate.sdpMLineIndex ?? 0,
3757
- sdpMid: event.candidate.sdpMid ?? 0
3758
- }
3759
- }
3760
- }
3761
- });
3762
- } catch (err) {
3763
- log15.info("signaling error", {
3764
- err
3765
- }, {
3766
- F: __dxlog_file16,
3767
- L: 124,
3768
- S: this,
3769
- C: (f, a) => f(...a)
3770
- });
3771
- }
3772
- }
3773
- };
3774
- if (this._options.initiator) {
3775
- invariant14(this._peer, "not open", {
3776
- F: __dxlog_file16,
3777
- L: 130,
3778
- S: this,
3779
- A: [
3780
- "this._peer",
3781
- "'not open'"
3782
- ]
3783
- });
3784
- this._peer.createOffer().then(async (offer) => {
3785
- if (this._closed) {
3786
- return;
3787
- }
3788
- if (this._peer?.connectionState !== "connecting") {
3789
- log15.error("peer not connecting", {
3790
- peer: this._peer
3791
- }, {
3792
- F: __dxlog_file16,
3793
- L: 141,
3794
- S: this,
3795
- C: (f, a) => f(...a)
3796
- });
3797
- this.errors.raise(new Error("invalid state: peer is initiator, but other peer not in state connecting"));
3798
- }
3799
- log15.debug("creating offer", {
3800
- peer: this._peer,
3801
- offer
3802
- }, {
3803
- F: __dxlog_file16,
3804
- L: 145,
3805
- S: this,
3806
- C: (f, a) => f(...a)
3807
- });
3808
- await this._peer.setLocalDescription(offer);
3809
- await this._options.sendSignal({
3810
- payload: {
3811
- data: {
3812
- type: offer.type,
3813
- sdp: offer.sdp
3814
- }
3815
- }
3816
- });
3817
- }).catch((err) => {
3818
- this.errors.raise(err);
3819
- });
3820
- this._handleChannel(this._peer.createDataChannel(DATACHANNEL_LABEL));
3821
- log15.debug("created data channel", void 0, {
3822
- F: __dxlog_file16,
3823
- L: 155,
3824
- S: this,
3825
- C: (f, a) => f(...a)
4075
+ timeout: RPC_TIMEOUT
3826
4076
  });
3827
- this._peer.ondatachannel = () => {
3828
- this.errors.raise(new Error("unexpected ondatachannel event for initiator"));
3829
- };
3830
- } else {
3831
- this._peer.ondatachannel = (event) => {
3832
- log15.debug("peer.ondatachannel (non-initiator)", {
3833
- event
3834
- }, {
3835
- F: __dxlog_file16,
3836
- L: 161,
3837
- S: this,
3838
- C: (f, a) => f(...a)
3839
- });
3840
- if (event.channel.label !== DATACHANNEL_LABEL) {
3841
- this.errors.raise(new Error(`unexpected channel label ${event.channel.label}`));
3842
- }
3843
- this._handleChannel(event.channel);
4077
+ return response.stats;
4078
+ } catch (err) {
4079
+ return {
4080
+ bytesSent: 0,
4081
+ bytesReceived: 0,
4082
+ packetsSent: 0,
4083
+ packetsReceived: 0,
4084
+ rawStats: "bridge-svc unreachable"
3844
4085
  };
3845
4086
  }
3846
- _LibDataChannelTransport._instanceCount++;
3847
4087
  }
3848
- async close() {
3849
- await this._close();
3850
- if (--_LibDataChannelTransport._instanceCount === 0) {
3851
- (await importESM("node-datachannel")).cleanup();
4088
+ _raiseIfOpen(error) {
4089
+ if (this.isOpen) {
4090
+ this.errors.raise(error);
4091
+ } else {
4092
+ log14.info("error swallowed because transport was closed", {
4093
+ message: error.message
4094
+ }, {
4095
+ F: __dxlog_file15,
4096
+ L: 215,
4097
+ S: this,
4098
+ C: (f, a) => f(...a)
4099
+ });
3852
4100
  }
3853
4101
  }
3854
- async _close() {
3855
- if (this._closed) {
3856
- return;
3857
- }
3858
- await this._disconnectStreams();
3859
- try {
3860
- this._peer?.close();
3861
- } catch (err) {
3862
- this.errors.raise(err);
3863
- }
3864
- this._peer = void 0;
3865
- this._closed = true;
4102
+ /**
4103
+ * Called when underlying proxy service becomes unavailable.
4104
+ */
4105
+ forceClose() {
4106
+ void this._serviceStream?.close();
3866
4107
  this.closed.emit();
3867
4108
  }
4109
+ };
4110
+ var RtcTransportProxyFactory = class {
4111
+ constructor() {
4112
+ this._connections = /* @__PURE__ */ new Set();
4113
+ }
3868
4114
  /**
3869
- * Handle data channel events.
4115
+ * Sets the current BridgeService to be used to open connections.
4116
+ * Calling this method will close any existing connections.
3870
4117
  */
3871
- _handleChannel(dataChannel) {
3872
- this._channel = dataChannel;
3873
- this._channel.onopen = () => {
3874
- log15.debug("channel.onopen", void 0, {
4118
+ setBridgeService(bridgeService) {
4119
+ this._bridgeService = bridgeService;
4120
+ for (const connection of this._connections) {
4121
+ connection.forceClose();
4122
+ }
4123
+ return this;
4124
+ }
4125
+ createTransport(options) {
4126
+ invariant13(this._bridgeService, "RtcTransportProxyFactory is not ready to open connections", {
4127
+ F: __dxlog_file15,
4128
+ L: 245,
4129
+ S: this,
4130
+ A: [
4131
+ "this._bridgeService",
4132
+ "'RtcTransportProxyFactory is not ready to open connections'"
4133
+ ]
4134
+ });
4135
+ const transport = new RtcTransportProxy({
4136
+ ...options,
4137
+ bridgeService: this._bridgeService
4138
+ });
4139
+ this._connections.add(transport);
4140
+ transport.closed.on(() => this._connections.delete(transport));
4141
+ return transport;
4142
+ }
4143
+ };
4144
+ var decodeError = (err) => {
4145
+ const message = typeof err === "string" ? err : err.message;
4146
+ if (message.includes("CONNECTION_RESET")) {
4147
+ return new ConnectionResetError2(message);
4148
+ } else if (message.includes("TIMEOUT")) {
4149
+ return new TimeoutError3(message);
4150
+ } else if (message.includes("CONNECTIVITY_ERROR")) {
4151
+ return new ConnectivityError4(message);
4152
+ } else {
4153
+ return typeof err === "string" ? new Error(err) : err;
4154
+ }
4155
+ };
4156
+
4157
+ // packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-service.ts
4158
+ import { Duplex as Duplex2 } from "@dxos/node-std/stream";
4159
+ import { Stream } from "@dxos/codec-protobuf";
4160
+ import { invariant as invariant14 } from "@dxos/invariant";
4161
+ import { PublicKey as PublicKey11 } from "@dxos/keys";
4162
+ import { log as log15 } from "@dxos/log";
4163
+ import { ConnectionState as ConnectionState4 } from "@dxos/protocols/proto/dxos/mesh/bridge";
4164
+ import { ComplexMap as ComplexMap8 } from "@dxos/util";
4165
+ var __dxlog_file16 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-service.ts";
4166
+ var RtcTransportService = class {
4167
+ constructor(webrtcConfig, iceProvider, _transportFactory = createRtcTransportFactory(webrtcConfig, iceProvider)) {
4168
+ this._transportFactory = _transportFactory;
4169
+ this._openTransports = new ComplexMap8(PublicKey11.hash);
4170
+ }
4171
+ hasOpenTransports() {
4172
+ return this._openTransports.size > 0;
4173
+ }
4174
+ open(request) {
4175
+ const existingTransport = this._openTransports.get(request.proxyId);
4176
+ if (existingTransport) {
4177
+ log15.error("requesting a new transport bridge for an existing proxy", void 0, {
3875
4178
  F: __dxlog_file16,
3876
- L: 206,
4179
+ L: 53,
3877
4180
  S: this,
3878
4181
  C: (f, a) => f(...a)
3879
4182
  });
3880
- const duplex = new Duplex2({
4183
+ void this._safeCloseTransport(existingTransport);
4184
+ this._openTransports.delete(request.proxyId);
4185
+ }
4186
+ return new Stream(({ ready, next, close }) => {
4187
+ const pushNewState = createStateUpdater(next);
4188
+ const transportStream = new Duplex2({
3881
4189
  read: () => {
4190
+ const callbacks = [
4191
+ ...transportState.writeProcessedCallbacks
4192
+ ];
4193
+ transportState.writeProcessedCallbacks.length = 0;
4194
+ callbacks.forEach((cb) => cb());
3882
4195
  },
3883
- write: async (chunk, encoding, callback) => {
3884
- if (chunk.length > MAX_MESSAGE_SIZE) {
3885
- this.errors.raise(new Error(`message too large: ${chunk.length} > ${MAX_MESSAGE_SIZE}`));
3886
- }
3887
- try {
3888
- dataChannel.send(chunk);
3889
- } catch (err) {
3890
- this.errors.raise(err);
3891
- await this._close();
3892
- }
3893
- if (this._channel.bufferedAmount > MAX_BUFFERED_AMOUNT) {
3894
- if (this._writeCallback !== null) {
3895
- log15.error("consumer trying to write before we are ready for more data", void 0, {
3896
- F: __dxlog_file16,
3897
- L: 223,
3898
- S: this,
3899
- C: (f, a) => f(...a)
3900
- });
4196
+ write: function(chunk, _, callback) {
4197
+ next({
4198
+ data: {
4199
+ payload: chunk
3901
4200
  }
3902
- this._writeCallback = callback;
3903
- } else {
3904
- callback();
3905
- }
4201
+ });
4202
+ callback();
3906
4203
  }
3907
4204
  });
3908
- duplex.pipe(this._options.stream).pipe(duplex);
3909
- this._stream = duplex;
3910
- this._connected = true;
3911
- this.connected.emit();
3912
- };
3913
- this._channel.onclose = async (err) => {
3914
- log15.info("channel.onclose", {
3915
- err
3916
- }, {
3917
- F: __dxlog_file16,
3918
- L: 239,
3919
- S: this,
3920
- C: (f, a) => f(...a)
4205
+ const transport = this._transportFactory.createTransport({
4206
+ initiator: request.initiator,
4207
+ topic: request.topic,
4208
+ ownPeerKey: request.ownPeerKey,
4209
+ remotePeerKey: request.remotePeerKey,
4210
+ stream: transportStream,
4211
+ sendSignal: async (signal) => {
4212
+ next({
4213
+ signal: {
4214
+ payload: signal
4215
+ }
4216
+ });
4217
+ }
3921
4218
  });
3922
- await this._close();
3923
- };
3924
- this._channel.onerror = async (err) => {
3925
- this.errors.raise(new Error("channel error: " + err.toString()));
3926
- await this._close();
3927
- };
3928
- this._channel.onbufferedamountlow = () => {
3929
- const cb = this._writeCallback;
3930
- this._writeCallback = null;
3931
- cb?.();
3932
- };
3933
- this._channel.onmessage = (event) => {
3934
- let data = event.data;
3935
- if (data instanceof ArrayBuffer) {
3936
- data = Buffer2.from(data);
3937
- }
3938
- this._stream.push(data);
3939
- };
4219
+ const transportState = {
4220
+ proxyId: request.proxyId,
4221
+ transport,
4222
+ connectorStream: transportStream,
4223
+ writeProcessedCallbacks: []
4224
+ };
4225
+ pushNewState(ConnectionState4.CONNECTING);
4226
+ transport.connected.on(() => pushNewState(ConnectionState4.CONNECTED));
4227
+ transport.errors.handle(async (err) => {
4228
+ pushNewState(ConnectionState4.CLOSED, err);
4229
+ void this._safeCloseTransport(transportState);
4230
+ close(err);
4231
+ });
4232
+ transport.closed.on(async () => {
4233
+ pushNewState(ConnectionState4.CLOSED);
4234
+ void this._safeCloseTransport(transportState);
4235
+ close();
4236
+ });
4237
+ this._openTransports.set(request.proxyId, transportState);
4238
+ transport.open().catch(async (err) => {
4239
+ pushNewState(ConnectionState4.CLOSED, err);
4240
+ void this._safeCloseTransport(transportState);
4241
+ close(err);
4242
+ });
4243
+ ready();
4244
+ });
3940
4245
  }
3941
- async onSignal(signal) {
3942
- invariant14(this._peer, "not open", {
4246
+ async sendSignal({ proxyId, signal }) {
4247
+ const transport = this._openTransports.get(proxyId);
4248
+ invariant14(transport, void 0, {
3943
4249
  F: __dxlog_file16,
3944
- L: 265,
4250
+ L: 121,
3945
4251
  S: this,
3946
4252
  A: [
3947
- "this._peer",
3948
- "'not open'"
4253
+ "transport",
4254
+ ""
3949
4255
  ]
3950
4256
  });
3951
- try {
3952
- const data = signal.payload.data;
3953
- switch (data.type) {
3954
- case "offer": {
3955
- if (this._peer.connectionState !== "new") {
3956
- log15.error("received offer but peer not in state new", {
3957
- peer: this._peer
3958
- }, {
3959
- F: __dxlog_file16,
3960
- L: 272,
3961
- S: this,
3962
- C: (f, a) => f(...a)
3963
- });
3964
- this.errors.raise(new Error("invalid signalling state: received offer when peer is not in state new"));
3965
- break;
3966
- }
3967
- try {
3968
- await this._peer.setRemoteDescription({
3969
- type: data.type,
3970
- sdp: data.sdp
3971
- });
3972
- const answer = await this._peer.createAnswer();
3973
- await this._peer.setLocalDescription(answer);
3974
- await this._options.sendSignal({
3975
- payload: {
3976
- data: {
3977
- type: answer.type,
3978
- sdp: answer.sdp
3979
- }
3980
- }
3981
- });
3982
- this._readyForCandidates.wake();
3983
- } catch (err) {
3984
- log15.error("cannot handle offer from signalling server", {
3985
- err
3986
- }, {
3987
- F: __dxlog_file16,
3988
- L: 284,
3989
- S: this,
3990
- C: (f, a) => f(...a)
3991
- });
3992
- this.errors.raise(new Error("error handling offer"));
3993
- }
3994
- break;
3995
- }
3996
- case "answer":
3997
- try {
3998
- await this._peer.setRemoteDescription({
3999
- type: data.type,
4000
- sdp: data.sdp
4001
- });
4002
- this._readyForCandidates.wake();
4003
- } catch (err) {
4004
- log15.error("cannot handle answer from signalling server", {
4005
- err
4006
- }, {
4007
- F: __dxlog_file16,
4008
- L: 295,
4009
- S: this,
4010
- C: (f, a) => f(...a)
4011
- });
4012
- this.errors.raise(new Error("error handling answer"));
4013
- }
4014
- break;
4015
- case "candidate":
4016
- await this._readyForCandidates.wait();
4017
- await this._peer.addIceCandidate({
4018
- candidate: data.candidate.candidate
4019
- });
4020
- break;
4021
- default:
4022
- log15.error("unhandled signal type", {
4023
- type: data.type,
4024
- signal
4025
- }, {
4026
- F: __dxlog_file16,
4027
- L: 306,
4028
- S: this,
4029
- C: (f, a) => f(...a)
4030
- });
4031
- this.errors.raise(new Error(`unhandled signal type ${data.type}`));
4032
- }
4033
- } catch (err) {
4034
- log15.catch(err, void 0, {
4035
- F: __dxlog_file16,
4036
- L: 310,
4037
- S: this,
4038
- C: (f, a) => f(...a)
4039
- });
4040
- }
4041
- }
4042
- async getDetails() {
4043
- const stats = await this._getStats();
4044
- const rc = stats?.remoteCandidate;
4045
- if (!rc) {
4046
- return "unavailable";
4047
- }
4048
- if (rc.candidateType === "relay") {
4049
- return `${rc.ip}:${rc.port} relay for ${rc.relatedAddress}:${rc.relatedPort}`;
4050
- }
4051
- return `${rc.ip}:${rc.port} ${rc.candidateType}`;
4257
+ await transport.transport.onSignal(signal);
4052
4258
  }
4053
- async getStats() {
4054
- const stats = await this._getStats();
4055
- if (!stats) {
4056
- return {
4057
- bytesSent: 0,
4058
- bytesReceived: 0,
4059
- packetsSent: 0,
4060
- packetsReceived: 0,
4061
- rawStats: {}
4062
- };
4063
- }
4259
+ async getDetails({ proxyId }) {
4260
+ const transport = this._openTransports.get(proxyId);
4261
+ invariant14(transport, void 0, {
4262
+ F: __dxlog_file16,
4263
+ L: 128,
4264
+ S: this,
4265
+ A: [
4266
+ "transport",
4267
+ ""
4268
+ ]
4269
+ });
4064
4270
  return {
4065
- bytesSent: stats.transport.bytesSent,
4066
- bytesReceived: stats.transport.bytesReceived,
4067
- packetsSent: 0,
4068
- packetsReceived: 0,
4069
- rawStats: stats.raw
4271
+ details: await transport.transport.getDetails()
4070
4272
  };
4071
4273
  }
4072
- async _getStats() {
4073
- invariant14(this._peer, "not open", {
4274
+ async getStats({ proxyId }) {
4275
+ const transport = this._openTransports.get(proxyId);
4276
+ invariant14(transport, void 0, {
4074
4277
  F: __dxlog_file16,
4075
- L: 350,
4278
+ L: 135,
4076
4279
  S: this,
4077
4280
  A: [
4078
- "this._peer",
4079
- "'not open'"
4281
+ "transport",
4282
+ ""
4080
4283
  ]
4081
4284
  });
4082
- const stats = await this._peer.getStats();
4083
- const statsEntries = Array.from(stats.entries());
4084
- const transport = statsEntries.filter((s) => s[1].type === "transport")[0][1];
4085
- const candidatePair = statsEntries.filter((s) => s[0] === transport.selectedCandidatePairId);
4086
- let selectedCandidatePair;
4087
- let remoteCandidate;
4088
- if (candidatePair.length > 0) {
4089
- selectedCandidatePair = candidatePair[0][1];
4090
- remoteCandidate = statsEntries.filter((s) => s[0] === selectedCandidatePair.remoteCandidateId)[0][1];
4091
- }
4092
4285
  return {
4093
- transport,
4094
- selectedCandidatePair,
4095
- remoteCandidate,
4096
- raw: Object.fromEntries(stats)
4286
+ stats: await transport.transport.getStats()
4097
4287
  };
4098
4288
  }
4099
- async _disconnectStreams() {
4100
- this._options.stream.unpipe?.(this._stream)?.unpipe?.(this._options.stream);
4101
- }
4102
- };
4103
- _ts_decorate7([
4104
- synchronized6
4105
- ], LibDataChannelTransport.prototype, "_close", null);
4106
- var importESM = Function("path", "return import(path)");
4107
-
4108
- // packages/core/mesh/network-manager/src/transport/tcp-transport.browser.ts
4109
- import { Event as Event11 } from "@dxos/async";
4110
- import { ErrorStream as ErrorStream7 } from "@dxos/debug";
4111
- var TcpTransportFactory = {
4112
- createTransport: () => new TcpTransport()
4113
- };
4114
- var TcpTransport = class {
4115
- constructor() {
4116
- this.closed = new Event11();
4117
- this.connected = new Event11();
4118
- this.errors = new ErrorStream7();
4119
- }
4120
- get isOpen() {
4121
- return true;
4122
- }
4123
- async open() {
4124
- }
4125
- async close() {
4126
- }
4127
- async onSignal() {
4128
- throw new Error("Method not implemented.");
4289
+ async sendData({ proxyId, payload }) {
4290
+ const transport = this._openTransports.get(proxyId);
4291
+ invariant14(transport, void 0, {
4292
+ F: __dxlog_file16,
4293
+ L: 142,
4294
+ S: this,
4295
+ A: [
4296
+ "transport",
4297
+ ""
4298
+ ]
4299
+ });
4300
+ const bufferHasSpace = transport.connectorStream.push(payload);
4301
+ if (!bufferHasSpace) {
4302
+ await new Promise((resolve) => {
4303
+ transport.writeProcessedCallbacks.push(resolve);
4304
+ });
4305
+ }
4129
4306
  }
4130
- async getStats() {
4131
- throw new Error("Method not implemented.");
4307
+ async close({ proxyId }) {
4308
+ const transport = this._openTransports.get(proxyId);
4309
+ if (!transport) {
4310
+ return;
4311
+ }
4312
+ this._openTransports.delete(proxyId);
4313
+ await this._safeCloseTransport(transport);
4132
4314
  }
4133
- async getDetails() {
4134
- throw new Error("Method not implemented.");
4315
+ async _safeCloseTransport(transport) {
4316
+ if (this._openTransports.get(transport.proxyId) === transport) {
4317
+ this._openTransports.delete(transport.proxyId);
4318
+ }
4319
+ transport.writeProcessedCallbacks.forEach((cb) => cb());
4320
+ try {
4321
+ await transport.transport.close();
4322
+ } catch (error) {
4323
+ log15.warn("transport close error", {
4324
+ message: error?.message
4325
+ }, {
4326
+ F: __dxlog_file16,
4327
+ L: 172,
4328
+ S: this,
4329
+ C: (f, a) => f(...a)
4330
+ });
4331
+ }
4332
+ try {
4333
+ transport.connectorStream.end();
4334
+ } catch (error) {
4335
+ log15.warn("connectorStream close error", {
4336
+ message: error?.message
4337
+ }, {
4338
+ F: __dxlog_file16,
4339
+ L: 177,
4340
+ S: this,
4341
+ C: (f, a) => f(...a)
4342
+ });
4343
+ }
4344
+ log15("closed", void 0, {
4345
+ F: __dxlog_file16,
4346
+ L: 179,
4347
+ S: this,
4348
+ C: (f, a) => f(...a)
4349
+ });
4135
4350
  }
4136
4351
  };
4352
+ var createStateUpdater = (next) => {
4353
+ return (state, err) => {
4354
+ next({
4355
+ connection: {
4356
+ state,
4357
+ ...err ? {
4358
+ error: err.message
4359
+ } : void 0
4360
+ }
4361
+ });
4362
+ };
4363
+ };
4137
4364
 
4138
4365
  // packages/core/mesh/network-manager/src/wire-protocol.ts
4139
4366
  import { Teleport } from "@dxos/teleport";
@@ -4160,7 +4387,6 @@ var createTeleportProtocolFactory = (onConnection, defaultParams) => {
4160
4387
  };
4161
4388
 
4162
4389
  export {
4163
- process,
4164
4390
  ConnectionState,
4165
4391
  Connection,
4166
4392
  createIceProvider,
@@ -4178,15 +4404,10 @@ export {
4178
4404
  MemoryTransportFactory,
4179
4405
  MemoryTransport,
4180
4406
  TransportKind,
4181
- createSimplePeerTransportFactory,
4182
- SimplePeerTransport,
4183
- SimplePeerTransportService,
4184
- SimplePeerTransportProxy,
4185
- SimplePeerTransportProxyFactory,
4186
- createLibDataChannelTransportFactory,
4187
- LibDataChannelTransport,
4188
- TcpTransportFactory,
4189
- TcpTransport,
4407
+ createRtcTransportFactory,
4408
+ RtcTransportProxy,
4409
+ RtcTransportProxyFactory,
4410
+ RtcTransportService,
4190
4411
  createTeleportProtocolFactory
4191
4412
  };
4192
- //# sourceMappingURL=chunk-XYSYUN63.mjs.map
4413
+ //# sourceMappingURL=chunk-UEVA7BFW.mjs.map