@dxos/network-manager 0.4.10-main.fa5a270 → 0.4.10-main.fe71b4c

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 (47) hide show
  1. package/dist/lib/browser/{chunk-KEN4UCZF.mjs → chunk-OSMVZUEK.mjs} +503 -453
  2. package/dist/lib/browser/chunk-OSMVZUEK.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +1 -1
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/testing/index.mjs +1 -1
  6. package/dist/lib/node/{chunk-5D3NBEP2.cjs → chunk-M4CGCR2I.cjs} +519 -468
  7. package/dist/lib/node/chunk-M4CGCR2I.cjs.map +7 -0
  8. package/dist/lib/node/index.cjs +27 -27
  9. package/dist/lib/node/index.cjs.map +1 -1
  10. package/dist/lib/node/meta.json +1 -1
  11. package/dist/lib/node/testing/index.cjs +18 -18
  12. package/dist/types/src/swarm/connection.d.ts.map +1 -1
  13. package/dist/types/src/swarm/peer.d.ts.map +1 -1
  14. package/dist/types/src/swarm/swarm.d.ts.map +1 -1
  15. package/dist/types/src/transport/libdatachannel-transport.d.ts +20 -19
  16. package/dist/types/src/transport/libdatachannel-transport.d.ts.map +1 -1
  17. package/dist/types/src/transport/memory-transport.d.ts +17 -10
  18. package/dist/types/src/transport/memory-transport.d.ts.map +1 -1
  19. package/dist/types/src/transport/simplepeer-transport-proxy.d.ts +7 -9
  20. package/dist/types/src/transport/simplepeer-transport-proxy.d.ts.map +1 -1
  21. package/dist/types/src/transport/simplepeer-transport-service.d.ts.map +1 -1
  22. package/dist/types/src/transport/simplepeer-transport.d.ts +9 -11
  23. package/dist/types/src/transport/simplepeer-transport.d.ts.map +1 -1
  24. package/dist/types/src/transport/tcp-transport.browser.d.ts +7 -2
  25. package/dist/types/src/transport/tcp-transport.browser.d.ts.map +1 -1
  26. package/dist/types/src/transport/tcp-transport.d.ts +6 -4
  27. package/dist/types/src/transport/tcp-transport.d.ts.map +1 -1
  28. package/dist/types/src/transport/transport.d.ts +18 -12
  29. package/dist/types/src/transport/transport.d.ts.map +1 -1
  30. package/package.json +17 -17
  31. package/src/swarm/connection.ts +7 -5
  32. package/src/swarm/peer.ts +0 -1
  33. package/src/swarm/swarm.ts +1 -0
  34. package/src/transport/libdatachannel-transport.test.ts +14 -9
  35. package/src/transport/libdatachannel-transport.ts +226 -204
  36. package/src/transport/memory-transport.test.ts +10 -7
  37. package/src/transport/memory-transport.ts +49 -42
  38. package/src/transport/simplepeer-transport-proxy-test.ts +13 -8
  39. package/src/transport/simplepeer-transport-proxy.ts +57 -50
  40. package/src/transport/simplepeer-transport-service.ts +5 -2
  41. package/src/transport/simplepeer-transport.test.ts +9 -5
  42. package/src/transport/simplepeer-transport.ts +25 -25
  43. package/src/transport/tcp-transport.browser.ts +10 -5
  44. package/src/transport/tcp-transport.ts +31 -22
  45. package/src/transport/transport.ts +25 -14
  46. package/dist/lib/browser/chunk-KEN4UCZF.mjs.map +0 -7
  47. package/dist/lib/node/chunk-5D3NBEP2.cjs.map +0 -7
@@ -6,146 +6,196 @@ import { Duplex } from 'stream';
6
6
 
7
7
  import { Event, Trigger, synchronized } from '@dxos/async';
8
8
  import { ErrorStream } from '@dxos/debug';
9
+ import { invariant } from '@dxos/invariant';
9
10
  import { log } from '@dxos/log';
10
11
  import { type Signal } from '@dxos/protocols/proto/dxos/mesh/swarm';
11
12
 
12
- import { type Transport, type TransportFactory, type TransportStats } from './transport';
13
-
14
- export type LibDataChannelTransportParams = {
15
- initiator: boolean;
16
- stream: NodeJS.ReadWriteStream;
17
- webrtcConfig?: RTCConfiguration;
18
- sendSignal: (signal: Signal) => Promise<void>;
19
- };
13
+ import { type Transport, type TransportFactory, type TransportOptions, type TransportStats } from './transport';
20
14
 
21
15
  const DATACHANNEL_LABEL = 'dxos.mesh.transport';
22
16
  const MAX_BUFFERED_AMOUNT = 64 * 1024;
23
17
 
24
- // https://viblast.com/blog/2015/2/5/webrtc-data-channel-message-size/
18
+ // https://viblast.com/blog/2015/2/5/webrtc-data-channel-message-size
25
19
  const MAX_MESSAGE_SIZE = 64 * 1024;
26
20
 
21
+ export type LibDataChannelTransportOptions = TransportOptions & {
22
+ webrtcConfig?: RTCConfiguration;
23
+ };
24
+
25
+ export const createLibDataChannelTransportFactory = (webrtcConfig?: any): TransportFactory => ({
26
+ createTransport: (options) => new LibDataChannelTransport({ ...options, webrtcConfig }),
27
+ });
28
+
27
29
  /**
28
30
  * Transport
29
31
  */
32
+ // TODO(burdon): Purpose (e.g., platform).
30
33
  export class LibDataChannelTransport implements Transport {
31
34
  private static _instanceCount = 0;
35
+
36
+ private _peer?: RTCPeerConnection;
37
+ private _channel!: RTCDataChannel;
38
+ private _stream!: Duplex;
39
+
32
40
  private _closed = false;
33
- readonly closed = new Event();
34
41
  private _connected = false;
42
+
43
+ private _writeCallback: (() => void) | null = null;
44
+ private readonly _readyForCandidates = new Trigger();
45
+
46
+ readonly closed = new Event();
35
47
  readonly connected = new Event();
36
48
  readonly errors = new ErrorStream();
37
- private readonly _peer: Promise<RTCPeerConnection>;
38
- private _channel!: RTCDataChannel;
39
- private _stream!: Duplex;
40
49
 
41
- private readonly _readyForCandidates = new Trigger();
42
- private _writeCallback: (() => void) | null = null;
50
+ constructor(private readonly _options: LibDataChannelTransportOptions) {}
43
51
 
44
- constructor(private readonly params: LibDataChannelTransportParams) {
45
- this._peer = (async () => {
46
- /* eslint-disable @typescript-eslint/consistent-type-imports */
47
- const { RTCPeerConnection } = (await importESM('node-datachannel/polyfill'))
48
- .default as typeof import('node-datachannel/polyfill');
49
- /* eslint-enable @typescript-eslint/consistent-type-imports */
50
- if (this._closed) {
51
- this.errors.raise(new Error('connection already closed'));
52
- }
53
- // workaround https://github.com/murat-dogan/node-datachannel/pull/207
54
- if (params.webrtcConfig) {
55
- params.webrtcConfig.iceServers = params.webrtcConfig.iceServers ?? [];
56
- } else {
57
- params.webrtcConfig = { iceServers: [] };
58
- }
59
- const peer = new RTCPeerConnection(params.webrtcConfig);
60
- LibDataChannelTransport._instanceCount++;
52
+ get isOpen() {
53
+ return !!this._peer && !this._closed;
54
+ }
61
55
 
62
- peer.onicecandidateerror = (event) => {
63
- log.error('peer.onicecandidateerror', { event });
64
- };
56
+ async open() {
57
+ if (this._closed) {
58
+ // TODO(burdon): Make idempotent?
59
+ this.errors.raise(new Error('connection already closed'));
60
+ }
65
61
 
66
- peer.onconnectionstatechange = (event) => {
67
- log.debug('peer.onconnectionstatechange', {
68
- event,
69
- peerConnectionState: peer.connectionState,
70
- transportConnectionState: this._connected,
71
- });
72
- // TODO(nf): throw error if datachannel does not connect after some time?
73
- };
62
+ // TODO(burdon): Move to factory?
63
+ /* eslint-disable @typescript-eslint/consistent-type-imports */
64
+ const { RTCPeerConnection } = (await importESM('node-datachannel/polyfill'))
65
+ .default as typeof import('node-datachannel/polyfill');
74
66
 
75
- peer.onicecandidate = async (event) => {
76
- log.debug('peer.onicecandidate', { event });
77
- if (event.candidate) {
78
- try {
79
- await params.sendSignal({
80
- payload: {
81
- data: {
82
- type: 'candidate',
83
- candidate: {
84
- candidate: event.candidate.candidate,
85
- // these fields never seem to be not null, but connecting to Chrome doesn't work if they are
86
- sdpMLineIndex: event.candidate.sdpMLineIndex ?? 0,
87
- sdpMid: event.candidate.sdpMid ?? 0,
88
- },
67
+ // workaround https://github.com/murat-dogan/node-datachannel/pull/207
68
+ if (this._options.webrtcConfig) {
69
+ this._options.webrtcConfig.iceServers = this._options.webrtcConfig.iceServers ?? [];
70
+ } else {
71
+ this._options.webrtcConfig = { iceServers: [] };
72
+ }
73
+
74
+ this._peer = new RTCPeerConnection(this._options.webrtcConfig);
75
+
76
+ this._peer.onicecandidateerror = (event) => {
77
+ log.error('peer.onicecandidateerror', { event });
78
+ };
79
+
80
+ this._peer.onconnectionstatechange = (event) => {
81
+ log.debug('peer.onconnectionstatechange', {
82
+ event,
83
+ peerConnectionState: this._peer?.connectionState,
84
+ transportConnectionState: this._connected,
85
+ });
86
+ // TODO(nf): throw error if datachannel does not connect after some time?
87
+ // TODO(burdon): Restart ICE.
88
+ };
89
+
90
+ this._peer.onicecandidate = async (event) => {
91
+ log.debug('peer.onicecandidate', { event });
92
+ if (event.candidate) {
93
+ try {
94
+ await this._options.sendSignal({
95
+ payload: {
96
+ data: {
97
+ type: 'candidate',
98
+ candidate: {
99
+ candidate: event.candidate.candidate,
100
+ // These fields never seem to be not null, but connecting to Chrome doesn't work if they are.
101
+ sdpMLineIndex: event.candidate.sdpMLineIndex ?? 0,
102
+ sdpMid: event.candidate.sdpMid ?? 0,
89
103
  },
90
104
  },
91
- });
92
- } catch (err) {
93
- log.info('signaling errror', { err });
105
+ },
106
+ });
107
+ } catch (err) {
108
+ log.info('signaling error', { err });
109
+ }
110
+ }
111
+ };
112
+
113
+ if (this._options.initiator) {
114
+ invariant(this._peer, 'not open');
115
+ // TODO(burdon): Deprecated negotiation pattern?
116
+ // https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Perfect_negotiation
117
+ this._peer
118
+ .createOffer()
119
+ .then(async (offer) => {
120
+ if (this._closed) {
121
+ return;
94
122
  }
123
+
124
+ if (this._peer?.connectionState !== 'connecting') {
125
+ log.error('peer not connecting', { peer: this._peer });
126
+ this.errors.raise(new Error('invalid state: peer is initiator, but other peer not in state connecting'));
127
+ }
128
+
129
+ log.debug('creating offer', { peer: this._peer, offer });
130
+ await this._peer!.setLocalDescription(offer);
131
+ await this._options.sendSignal({ payload: { data: { type: offer.type, sdp: offer.sdp } } });
132
+ })
133
+ .catch((err) => {
134
+ this.errors.raise(err);
135
+ });
136
+
137
+ this._handleChannel(this._peer.createDataChannel(DATACHANNEL_LABEL));
138
+
139
+ log.debug('created data channel');
140
+ this._peer.ondatachannel = () => {
141
+ this.errors.raise(new Error('unexpected ondatachannel event for initiator'));
142
+ };
143
+ } else {
144
+ this._peer.ondatachannel = (event) => {
145
+ log.debug('peer.ondatachannel (non-initiator)', { event });
146
+ // TODO(nf): should the label contain some identifier?
147
+ if (event.channel.label !== DATACHANNEL_LABEL) {
148
+ this.errors.raise(new Error(`unexpected channel label ${event.channel.label}`));
95
149
  }
150
+
151
+ this._handleChannel(event.channel);
96
152
  };
153
+ }
97
154
 
98
- if (params.initiator) {
99
- peer
100
- .createOffer()
101
- .then(async (offer) => {
102
- if (this._closed) {
103
- return;
104
- }
105
- if (peer.connectionState !== 'connecting') {
106
- log.error('i am initiator but peer not in state connecting', { peer });
107
- this.errors.raise(new Error('invalid state: peer is initiator, but other peer not in state connecting'));
108
- }
109
- log.debug(`im the initiator, creating offer, peer is in state ${peer.connectionState}`, { offer });
110
- await peer.setLocalDescription(offer);
111
- await params.sendSignal({ payload: { data: { type: offer.type, sdp: offer.sdp } } });
112
- return offer;
113
- })
114
- .catch((err) => {
115
- this.errors.raise(err);
116
- });
117
- this.handleChannel(peer.createDataChannel(DATACHANNEL_LABEL));
118
- log.debug('created data channel');
119
- peer.ondatachannel = (event) => {
120
- this.errors.raise(new Error('got ondatachannel when i am the initiator?'));
121
- };
122
- } else {
123
- peer.ondatachannel = (event) => {
124
- log.debug('peer.ondatachannel (non-initiator)', { event });
125
- // TODO(nf): should the label contain some identifier?
126
- if (event.channel.label !== DATACHANNEL_LABEL) {
127
- this.errors.raise(new Error(`unexpected channel label ${event.channel.label}`));
128
- }
129
- this.handleChannel(event.channel);
130
- };
131
- }
155
+ LibDataChannelTransport._instanceCount++;
156
+ }
132
157
 
133
- return peer;
134
- })();
158
+ async close() {
159
+ await this._close();
160
+ if (--LibDataChannelTransport._instanceCount === 0) {
161
+ (await importESM('node-datachannel')).cleanup();
162
+ }
135
163
  }
136
164
 
137
- private handleChannel(dataChannel: RTCDataChannel) {
165
+ @synchronized
166
+ private async _close() {
167
+ if (this._closed) {
168
+ return;
169
+ }
170
+ await this._disconnectStreams();
171
+
172
+ try {
173
+ this._peer?.close();
174
+ } catch (err: any) {
175
+ this.errors.raise(err);
176
+ }
177
+
178
+ this._peer = undefined;
179
+ this._closed = true;
180
+ this.closed.emit();
181
+ }
182
+
183
+ /**
184
+ * Handle data channel events.
185
+ */
186
+ private _handleChannel(dataChannel: RTCDataChannel) {
138
187
  this._channel = dataChannel;
188
+
139
189
  this._channel.onopen = () => {
140
- log.debug('dataChannel.onopen');
190
+ log.debug('channel.onopen');
141
191
  const duplex = new Duplex({
142
192
  read: () => {},
143
193
  write: async (chunk, encoding, callback) => {
144
- // todo wait to open
145
-
194
+ // TODO(nf): Wait to open.
146
195
  if (chunk.length > MAX_MESSAGE_SIZE) {
147
196
  this.errors.raise(new Error(`message too large: ${chunk.length} > ${MAX_MESSAGE_SIZE}`));
148
197
  }
198
+
149
199
  try {
150
200
  dataChannel.send(chunk);
151
201
  } catch (err: any) {
@@ -154,7 +204,7 @@ export class LibDataChannelTransport implements Transport {
154
204
  }
155
205
  if (this._channel.bufferedAmount > MAX_BUFFERED_AMOUNT) {
156
206
  if (this._writeCallback !== null) {
157
- log.error("consumer trying to write before we're ready for more data");
207
+ log.error('consumer trying to write before we are ready for more data');
158
208
  }
159
209
  this._writeCallback = callback;
160
210
  } else {
@@ -163,98 +213,86 @@ export class LibDataChannelTransport implements Transport {
163
213
  },
164
214
  });
165
215
 
166
- duplex.pipe(this.params.stream).pipe(duplex);
216
+ duplex.pipe(this._options.stream).pipe(duplex);
167
217
  this._stream = duplex;
168
218
  this._connected = true;
169
219
  this.connected.emit();
170
220
  };
171
221
 
222
+ this._channel.onclose = async (err) => {
223
+ log.info('channel.onclose', { err });
224
+ await this._close();
225
+ };
226
+
172
227
  this._channel.onerror = async (err) => {
173
228
  this.errors.raise(new Error('channel error: ' + err.toString()));
174
229
  await this._close();
175
230
  };
176
- this._channel.onclose = async (err) => {
177
- log.info('channel onclose', { err });
178
- await this._close();
231
+
232
+ this._channel.onbufferedamountlow = () => {
233
+ const cb = this._writeCallback;
234
+ this._writeCallback = null;
235
+ cb?.();
179
236
  };
237
+
180
238
  this._channel.onmessage = (event) => {
181
239
  let data = event.data;
182
240
  if (data instanceof ArrayBuffer) {
183
241
  data = Buffer.from(data);
184
242
  }
185
- this._stream.push(data);
186
- };
187
243
 
188
- this._channel.onbufferedamountlow = () => {
189
- const cb = this._writeCallback;
190
- this._writeCallback = null;
191
- cb?.();
244
+ this._stream.push(data);
192
245
  };
193
246
  }
194
247
 
195
- @synchronized
196
- private async _close() {
197
- if (this._closed) {
198
- return;
199
- }
200
- await this._disconnectStreams();
201
- const peer = await this._peer;
202
- try {
203
- peer.close();
204
- } catch (err: any) {
205
- this.errors.raise(err);
206
- }
207
- this._closed = true;
208
- this.closed.emit();
209
- }
248
+ async onSignal(signal: Signal) {
249
+ invariant(this._peer, 'not open');
210
250
 
211
- signal(signal: Signal): void {
212
- this._peer
213
- .then(async (peer) => {
214
- const data = signal.payload.data;
215
- switch (data.type) {
216
- case 'offer': {
217
- if ((await this._peer).connectionState !== 'new') {
218
- log.error('received offer but peer not in state new', { peer });
219
- this.errors.raise(new Error('invalid signalling state: received offer when peer is not in state new'));
220
- break;
221
- }
222
- try {
223
- await peer.setRemoteDescription({ type: data.type, sdp: data.sdp });
224
- const answer = await peer.createAnswer();
225
- await peer.setLocalDescription(answer);
226
- await this.params.sendSignal({ payload: { data: { type: answer.type, sdp: answer.sdp } } });
227
- this._readyForCandidates.wake();
228
- } catch (err) {
229
- log.error("can't handle offer from signalling server", { err });
230
- this.errors.raise(new Error('error handling offer'));
231
- }
251
+ try {
252
+ const data = signal.payload.data;
253
+ switch (data.type) {
254
+ case 'offer': {
255
+ if (this._peer.connectionState !== 'new') {
256
+ log.error('received offer but peer not in state new', { peer: this._peer });
257
+ this.errors.raise(new Error('invalid signalling state: received offer when peer is not in state new'));
232
258
  break;
233
259
  }
234
260
 
235
- case 'answer':
236
- try {
237
- await peer.setRemoteDescription({ type: data.type, sdp: data.sdp });
238
- this._readyForCandidates.wake();
239
- } catch (err) {
240
- log.error("can't handle answer from signalling server", { err });
241
- this.errors.raise(new Error('error handling answer'));
242
- }
243
- break;
261
+ try {
262
+ await this._peer.setRemoteDescription({ type: data.type, sdp: data.sdp });
263
+ const answer = await this._peer.createAnswer();
264
+ await this._peer.setLocalDescription(answer);
265
+ await this._options.sendSignal({ payload: { data: { type: answer.type, sdp: answer.sdp } } });
266
+ this._readyForCandidates.wake();
267
+ } catch (err) {
268
+ log.error('cannot handle offer from signalling server', { err });
269
+ this.errors.raise(new Error('error handling offer'));
270
+ }
271
+ break;
272
+ }
244
273
 
245
- case 'candidate':
246
- await this._readyForCandidates.wait();
247
- await peer.addIceCandidate({ candidate: data.candidate.candidate });
248
- break;
274
+ case 'answer':
275
+ try {
276
+ await this._peer.setRemoteDescription({ type: data.type, sdp: data.sdp });
277
+ this._readyForCandidates.wake();
278
+ } catch (err) {
279
+ log.error('cannot handle answer from signalling server', { err });
280
+ this.errors.raise(new Error('error handling answer'));
281
+ }
282
+ break;
249
283
 
250
- default:
251
- log.error('unhandled signal type', { type: data.type, signal });
252
- this.errors.raise(new Error(`unhandled signal type ${data.type}`));
253
- }
254
- })
255
- .catch((err) => {
256
- log.catch(err);
257
- });
284
+ case 'candidate':
285
+ await this._readyForCandidates.wait();
286
+ await this._peer.addIceCandidate({ candidate: data.candidate.candidate });
287
+ break;
288
+
289
+ default:
290
+ log.error('unhandled signal type', { type: data.type, signal });
291
+ this.errors.raise(new Error(`unhandled signal type ${data.type}`));
292
+ }
293
+ } catch (err) {
294
+ log.catch(err);
295
+ }
258
296
  }
259
297
 
260
298
  async getDetails(): Promise<string> {
@@ -267,30 +305,8 @@ export class LibDataChannelTransport implements Transport {
267
305
  if (rc.candidateType === 'relay') {
268
306
  return `${rc.ip}:${rc.port} relay for ${rc.relatedAddress}:${rc.relatedPort}`;
269
307
  }
270
- return `${rc.ip}:${rc.port} ${rc.candidateType}`;
271
- }
272
-
273
- async _getStats(): Promise<any> {
274
- return this._peer.then(async (peer) => {
275
- const stats = await peer.getStats();
276
-
277
- const statsEntries = Array.from((stats as any).entries() as any[]);
278
- const transport = statsEntries.filter((s) => s[1].type === 'transport')[0][1];
279
- const candidatePair = statsEntries.filter((s: any) => s[0] === transport.selectedCandidatePairId);
280
- let selectedCandidatePair: any;
281
- let remoteCandidate: any;
282
- if (candidatePair.length > 0) {
283
- selectedCandidatePair = candidatePair[0][1];
284
- remoteCandidate = statsEntries.filter((s: any) => s[0] === selectedCandidatePair.remoteCandidateId)[0][1];
285
- }
286
308
 
287
- return {
288
- transport,
289
- selectedCandidatePair,
290
- remoteCandidate,
291
- raw: Object.fromEntries(stats as any),
292
- };
293
- });
309
+ return `${rc.ip}:${rc.port} ${rc.candidateType}`;
294
310
  }
295
311
 
296
312
  async getStats(): Promise<TransportStats> {
@@ -314,25 +330,31 @@ export class LibDataChannelTransport implements Transport {
314
330
  };
315
331
  }
316
332
 
317
- async destroy(): Promise<void> {
318
- await this._close();
319
- if (--LibDataChannelTransport._instanceCount === 0) {
320
- (await importESM('node-datachannel')).cleanup();
333
+ async _getStats(): Promise<any> {
334
+ invariant(this._peer, 'not open');
335
+ const stats = await this._peer.getStats();
336
+ const statsEntries = Array.from((stats as any).entries() as any[]);
337
+ const transport = statsEntries.filter((s) => s[1].type === 'transport')[0][1];
338
+ const candidatePair = statsEntries.filter((s: any) => s[0] === transport.selectedCandidatePairId);
339
+ let selectedCandidatePair: any;
340
+ let remoteCandidate: any;
341
+ if (candidatePair.length > 0) {
342
+ selectedCandidatePair = candidatePair[0][1];
343
+ remoteCandidate = statsEntries.filter((s: any) => s[0] === selectedCandidatePair.remoteCandidateId)[0][1];
321
344
  }
345
+
346
+ return {
347
+ transport,
348
+ selectedCandidatePair,
349
+ remoteCandidate,
350
+ raw: Object.fromEntries(stats as any),
351
+ };
322
352
  }
323
353
 
324
354
  private async _disconnectStreams() {
325
- this.params.stream.unpipe?.(this._stream)?.unpipe?.(this.params.stream);
355
+ this._options.stream.unpipe?.(this._stream)?.unpipe?.(this._options.stream);
326
356
  }
327
357
  }
328
358
 
329
- export const createLibDataChannelTransportFactory = (webrtcConfig?: any): TransportFactory => ({
330
- createTransport: (params) =>
331
- new LibDataChannelTransport({
332
- ...params,
333
- webrtcConfig,
334
- }),
335
- });
336
-
337
359
  // eslint-disable-next-line no-new-func
338
360
  const importESM = Function('path', 'return import(path)');
@@ -14,7 +14,7 @@ import { MemoryTransport } from './memory-transport';
14
14
  // Attempted to log "Ignoring unsupported ICE candidate.".
15
15
 
16
16
  // TODO(burdon): Move to TestBuilder.
17
- const createPair = () => {
17
+ const createPair = async () => {
18
18
  const topic = PublicKey.random();
19
19
  const peer1Id = PublicKey.random();
20
20
  const peer2Id = PublicKey.random();
@@ -23,26 +23,29 @@ const createPair = () => {
23
23
  const connection1 = new MemoryTransport({
24
24
  stream: stream1,
25
25
  sendSignal: async (signal) => {
26
- await connection2.signal(signal);
26
+ await connection2.onSignal(signal);
27
27
  },
28
28
  initiator: true,
29
29
  });
30
30
 
31
- afterTest(() => connection1.destroy());
31
+ afterTest(() => connection1.close());
32
32
  afterTest(() => connection1.errors.assertNoUnhandledErrors());
33
33
 
34
34
  const stream2 = new TestStream();
35
35
  const connection2 = new MemoryTransport({
36
36
  stream: stream2,
37
37
  sendSignal: async (signal) => {
38
- await connection1.signal(signal);
38
+ await connection1.onSignal(signal);
39
39
  },
40
40
  initiator: false,
41
41
  });
42
42
 
43
- afterTest(() => connection2.destroy());
43
+ afterTest(() => connection2.close());
44
44
  afterTest(() => connection2.errors.assertNoUnhandledErrors());
45
45
 
46
+ await connection1.open();
47
+ await connection2.open();
48
+
46
49
  return {
47
50
  connection1,
48
51
  connection2,
@@ -56,14 +59,14 @@ const createPair = () => {
56
59
 
57
60
  describe('MemoryTransport', () => {
58
61
  test('establish connection and send data through with protocol', async () => {
59
- const { stream1, stream2 } = createPair();
62
+ const { stream1, stream2 } = await createPair();
60
63
  await TestStream.assertConnectivity(stream1, stream2);
61
64
  });
62
65
 
63
66
  test('10 pairs of peers connecting at the same time', async () => {
64
67
  await Promise.all(
65
68
  range(10).map(async () => {
66
- const { stream1, stream2 } = createPair();
69
+ const { stream1, stream2 } = await createPair();
67
70
  await TestStream.assertConnectivity(stream1, stream2);
68
71
  }),
69
72
  );