@webqit/port-plus 0.1.14 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  ],
15
15
  "homepage": "https://port-plus.netlify.app/",
16
16
  "icon": "https://webqit.io/icon.svg",
17
- "version": "0.1.14",
17
+ "version": "0.1.15",
18
18
  "license": "MIT",
19
19
  "repository": {
20
20
  "type": "git",
@@ -38,10 +38,10 @@
38
38
  "@webqit/util": "^0.8.16"
39
39
  },
40
40
  "peerDependencies": {
41
- "@webqit/observer": "^3.8.17"
41
+ "@webqit/observer": "^3.8.19"
42
42
  },
43
43
  "devDependencies": {
44
- "@webqit/observer": "^3.8.17",
44
+ "@webqit/observer": "^3.8.19",
45
45
  "chai": "^4.3.4",
46
46
  "chai-as-promised": "^7.1.1",
47
47
  "esbuild": "^0.20.2",
@@ -4,19 +4,29 @@ import {
4
4
  } from './MessagePortPlus.js';
5
5
 
6
6
  export class BroadcastChannelPlus extends MessagePortPlusMockPortsMixin(BroadcastChannel) {
7
- constructor(name, { autoStart = true, postAwaitsOpen = false, clientServerMode = null, autoClose = true } = {}) {
7
+ constructor(name, { handshake = 0, postAwaitsOpen = false, clientServerMode = null, autoClose = false } = {}) {
8
8
  super(name);
9
9
 
10
10
  const portPlusMeta = _meta(this);
11
11
 
12
+ if (typeof handshake !== 'number') {
13
+ throw new Error('handshake must be a number');
14
+ }
15
+ if (handshake < 0 || handshake > 2) {
16
+ throw new Error('handshake must be between 0 and 2');
17
+ }
18
+
12
19
  if (clientServerMode
13
20
  && !['server', 'client'].includes(clientServerMode)) {
14
21
  throw new Error('clientServerMode must be "server" or "client"');
15
22
  }
16
- portPlusMeta.set('options', { autoStart, postAwaitsOpen, clientServerMode, autoClose });
23
+
24
+ portPlusMeta.set('options', { handshake, postAwaitsOpen, clientServerMode, autoClose });
17
25
  // Must come before upgradeEvents()
18
26
 
19
27
  this.constructor/* IMPORTANT */.upgradeEvents(this);
28
+
29
+ if (handshake === 0) this.start();
20
30
  }
21
31
 
22
32
  __postMessage(payload, portOptions) {
@@ -2,10 +2,10 @@ import { MessagePortPlus } from './MessagePortPlus.js';
2
2
 
3
3
  export class MessageChannelPlus extends MessageChannel {
4
4
 
5
- constructor({ autoStart = true, postAwaitsOpen = false } = {}) {
5
+ constructor({ handshake = 0, postAwaitsOpen = false } = {}) {
6
6
  super();
7
7
  [this.port1, this.port2].forEach((port, i) => {
8
- MessagePortPlus.upgradeInPlace(port, { autoStart, postAwaitsOpen });
8
+ MessagePortPlus.upgradeInPlace(port, { handshake, postAwaitsOpen });
9
9
  });
10
10
  }
11
11
  }
@@ -50,8 +50,7 @@ export class MessageEventPlus extends MessageEvent {
50
50
  this.#honourDoneMutationFlags = honourDoneMutationFlags;
51
51
 
52
52
  this.#ports = ports;
53
- const options = this.#originalTarget && _options(this.#originalTarget) || {};
54
- this.#ports.forEach((port) => MessagePortPlus.upgradeInPlace(port, { autoStart: options.autoStart, postAwaitsOpen: options.postAwaitsOpen }));
53
+ this.#ports.forEach((port) => MessagePortPlus.upgradeInPlace(port));
55
54
 
56
55
  if (_isTypeObject(this.#data) && this.#live) {
57
56
  if (typeof eventID !== 'string') {
@@ -29,10 +29,18 @@ const portPlusProps = [
29
29
 
30
30
  export class MessagePortPlus extends MessagePortPlusMixin(EventTarget) {
31
31
 
32
- constructor(options = {}) {
32
+ constructor({ handshake = 0, postAwaitsOpen = false, ...options } = {}) {
33
+ if (typeof handshake !== 'number') {
34
+ throw new Error('handshake must be a number');
35
+ }
36
+ if (handshake < 0 || handshake > 2) {
37
+ throw new Error('handshake must be between 0 and 2');
38
+ }
39
+
33
40
  super();
41
+
34
42
  const portPlusMeta = _wq(this, 'meta');
35
- portPlusMeta.set('options', options);
43
+ portPlusMeta.set('options', { handshake, postAwaitsOpen, ...options });
36
44
  }
37
45
 
38
46
  static [Symbol.hasInstance](instance) {
@@ -47,11 +55,18 @@ export class MessagePortPlus extends MessagePortPlusMixin(EventTarget) {
47
55
  export function MessagePortPlusMixin(superClass) {
48
56
  return class extends superClass {
49
57
 
50
- static upgradeInPlace(port, options = {}) {
58
+ static upgradeInPlace(port, { handshake = 0, postAwaitsOpen = false } = {}) {
51
59
  if (port instanceof MessagePortPlus) {
52
60
  return port;
53
61
  }
54
62
 
63
+ if (typeof handshake !== 'number') {
64
+ throw new Error('handshake must be a number');
65
+ }
66
+ if (handshake < 0 || handshake > 2) {
67
+ throw new Error('handshake must be between 0 and 2');
68
+ }
69
+
55
70
  const proto = this.prototype;
56
71
 
57
72
  for (const prop of portPlusMethods.concat('_autoStart')) {
@@ -71,9 +86,12 @@ export function MessagePortPlusMixin(superClass) {
71
86
  }
72
87
 
73
88
  const portPlusMeta = _wq(port, 'meta');
74
- portPlusMeta.set('options', options);
89
+ portPlusMeta.set('options', { handshake, postAwaitsOpen });
75
90
 
76
91
  this.upgradeEvents(port);
92
+
93
+ if (handshake === 0) port.start();
94
+
77
95
  return port;
78
96
  }
79
97
 
@@ -115,28 +133,34 @@ export function MessagePortPlusMixin(superClass) {
115
133
 
116
134
  if (e.data.ping === 'connect'
117
135
  && typeof e.data?.['.wq']?.eventID === 'string'
118
- && (!(port instanceof WebSocket) || !options.naturalOpen)) {
136
+ && (!(port instanceof WebSocket) || options.handshake)) {
119
137
  // This is a special ping from a MessagePort or BroadcastChannel instance
120
138
  // that helps us simulate an "open" event
121
- // If !options.naturalOpen, WebSockets too
139
+ // If options.handshake !== 0, WebSockets too
122
140
 
123
- let reply = true;
141
+ const nowOpen = options.handshake === 0
142
+ || portPlusMeta.get('start.called');
143
+
144
+ const reply = { isOpen: nowOpen };
124
145
 
125
146
  if (port instanceof BroadcastChannel) {
126
147
  if (options.clientServerMode === 'server'
127
148
  && typeof e.data.id === 'string') {
128
149
  portPlusMeta.get('clients').add(e.data.id);
129
- reply = 'server';
150
+ reply.id = 'server';
130
151
  } else if (e.data.id === 'server'
131
152
  && portPlusMeta.has('client_id')) {
132
- reply = portPlusMeta.get('client_id');
153
+ reply.id = portPlusMeta.get('client_id');
133
154
  }
134
155
  }
135
156
 
136
157
  e.ports?.forEach((p) => p.postMessage(reply));
137
158
 
138
- portPlusMeta.set('remote.start.called', true);
139
- portPlus.start();
159
+ if (nowOpen) {
160
+ portPlusMeta.set('remote.open.called', true);
161
+ portPlus.start();
162
+ }
163
+
140
164
  return;
141
165
  }
142
166
 
@@ -195,46 +219,19 @@ export function MessagePortPlusMixin(superClass) {
195
219
  portPlus.dispatchEvent(eventPlus);
196
220
  };
197
221
 
198
- // ------------- OPEN
199
-
200
- const openHandler = (e) => {
201
- // Native "open" event fired by WebSocket
202
- if (port instanceof WebSocket
203
- && options.naturalOpen
204
- && !(e instanceof MessageEventPlus)) {
205
- portPlusMeta.set('remote.start.called', true);
206
- portPlus.start();
207
- }
208
- };
209
-
210
- // ------------- CLOSE
211
-
212
- const closeHandler = (e) => {
213
- // Native "close" events fired by MessagePort and WebSocket
214
- if ((port instanceof WebSocket || port instanceof MessagePort)
215
- && !(e instanceof MessageEventPlus)) {
216
- portPlusMeta.set('remote.close.called', true);
217
- portPlus.close();
218
- }
219
- };
220
-
221
222
  rawPortMeta.set('internal_call', true);
222
223
  port.addEventListener('message', messageHandler);
223
224
  port.addEventListener('error', messageHandler);
224
- port.addEventListener('open', openHandler);
225
- port.addEventListener('close', closeHandler);
226
225
  rawPortMeta.delete('internal_call');
227
226
 
228
- rawPortMeta.set('events+', true);
229
-
230
227
  garbageCollection.add(() => {
231
228
  port.removeEventListener('message', messageHandler);
232
229
  port.removeEventListener('error', messageHandler);
233
- port.removeEventListener('open', openHandler);
234
- port.removeEventListener('close', closeHandler);
235
230
 
236
231
  rawPortMeta.set('events+', false);
237
232
  });
233
+
234
+ rawPortMeta.set('events+', true);
238
235
  }
239
236
 
240
237
  get options() { return { ..._options(this) }; }
@@ -282,11 +279,9 @@ export function MessagePortPlusMixin(superClass) {
282
279
  }
283
280
 
284
281
  set onmessage(v) {
285
- // Auto-start?
286
- this._autoStart();
287
-
288
282
  if (typeof super.onmessage !== 'undefined') {
289
283
  super.onmessage = v;
284
+ this._autoStart();
290
285
  return;
291
286
  }
292
287
 
@@ -296,18 +291,17 @@ export function MessagePortPlusMixin(superClass) {
296
291
 
297
292
  if (Object.getOwnPropertyDescriptor(this, '_onmessage')?.set) {
298
293
  this._onmessage = v;
294
+ this._autoStart();
299
295
  return;
300
296
  }
301
297
 
302
298
  if (this._onmessage) this.removeEventListener('message', this._onmessage);
303
299
  this.addEventListener('message', v);
304
300
  this._onmessage = v;
301
+ this._autoStart();
305
302
  }
306
303
 
307
304
  addEventListener(...args) {
308
- // Auto-start?
309
- this._autoStart();
310
-
311
305
  // Add to registry
312
306
  const garbageCollection = getGarbageCollection.call(this);
313
307
  garbageCollection.add(() => {
@@ -317,9 +311,11 @@ export function MessagePortPlusMixin(superClass) {
317
311
  });
318
312
 
319
313
  // Execute addEventListener()
320
- return this._addEventListener
314
+ const returnValue = this._addEventListener
321
315
  ? this._addEventListener(...args)
322
316
  : super.addEventListener(...args);
317
+ this._autoStart();
318
+ return returnValue;
323
319
  }
324
320
 
325
321
  dispatchEvent(event) {
@@ -334,7 +330,6 @@ export function MessagePortPlusMixin(superClass) {
334
330
  }
335
331
 
336
332
  postMessage(message, transferOrOptions = {}) {
337
- // Auto-start?
338
333
  this._autoStart();
339
334
 
340
335
  // Update readyState
@@ -455,21 +450,21 @@ export function MessagePortPlusMixin(superClass) {
455
450
  };
456
451
  }
457
452
 
458
- channel(channelSpec, resolveMessage = null) {
453
+ channel(channelSpec, resolveMessage = null, { handshake = 0, postAwaitsOpen = false } = {}) {
459
454
  const channel = new MessageChannel;
460
455
 
461
- MessagePortPlus.upgradeInPlace(channel.port1, { autoStart: this.options.autoStart, postAwaitsOpen: this.options.postAwaitsOpen });
462
- MessagePortPlus.upgradeInPlace(channel.port2, { autoStart: this.options.autoStart, postAwaitsOpen: this.options.postAwaitsOpen });
456
+ MessagePortPlus.upgradeInPlace(channel.port1, { handshake, postAwaitsOpen });
457
+ MessagePortPlus.upgradeInPlace(channel.port2, { handshake, postAwaitsOpen });
463
458
 
464
459
  const garbageCollection = getGarbageCollection.call(this);
465
- garbageCollection.add(this.relay({ channel: channelSpec, to: channel.port1, bidirectional: true, resolveMessage }));
460
+ garbageCollection.add(this.relay({ channel: channelSpec, to: channel.port2, bidirectional: true, resolveMessage }));
466
461
 
467
- channel.port1.start();
462
+ channel.port2.start();
468
463
  this.readyStateChange('close').then(() => {
469
- channel.port1.close();
464
+ channel.port2.close();
470
465
  });
471
466
 
472
- return channel.port2;
467
+ return channel.port1;
473
468
  }
474
469
 
475
470
  projectMutations({ from, to, ...options }) {
@@ -509,7 +504,7 @@ export function MessagePortPlusMixin(superClass) {
509
504
  const portPlusMeta = _meta(this);
510
505
  const options = _options(this);
511
506
  if (!portPlusMeta.get('internal_call')
512
- && options.autoStart) {
507
+ && options.handshake === 1) {
513
508
  this.start();
514
509
  }
515
510
  }
@@ -518,30 +513,29 @@ export function MessagePortPlusMixin(superClass) {
518
513
  const readyStateInternals = getReadyStateInternals.call(this);
519
514
  if (readyStateInternals.open.state) return;
520
515
 
521
- let messageChannel;
522
-
523
- const readyStateOpen = () => {
524
- if (readyStateInternals.open.state) return;
525
- readyStateInternals.open.state = true;
526
- readyStateInternals.open.resolve(this);
527
-
528
- const openEvent = new MessageEventPlus(null, { type: 'open' });
529
- this._dispatchEvent
530
- ? this._dispatchEvent(openEvent)
531
- : super.dispatchEvent(openEvent);
532
-
533
- messageChannel?.port1.close();
534
- messageChannel?.port2.close();
535
- };
536
-
537
516
  const portPlusMeta = _meta(this);
538
517
  const options = _options(this);
539
518
 
540
- if (portPlusMeta.get('remote.start.called')) {
541
- readyStateOpen();
519
+ const readyStateOpen = (nowOpen) => {
520
+ if (nowOpen) {
521
+ readyStateInternals.open.state = true;
522
+ readyStateInternals.open.resolve(this);
523
+ }
524
+ const handshakeChannel = portPlusMeta.get('handshake_channel');
525
+ setTimeout(() => {
526
+ handshakeChannel?.port1.close();
527
+ handshakeChannel?.port2.close();
528
+ portPlusMeta.delete('handshake_channel');
529
+ }, 100);
530
+ };
531
+
532
+ // A peer ping triggered us to open
533
+ if (portPlusMeta.get('remote.open.called')) {
534
+ readyStateOpen(true);
542
535
  return;
543
536
  }
544
537
 
538
+ // Start was explicitly called
545
539
  if (portPlusMeta.get('start.called')) return;
546
540
  portPlusMeta.set('start.called', true);
547
541
 
@@ -549,16 +543,26 @@ export function MessagePortPlusMixin(superClass) {
549
543
  ? this._start()
550
544
  : super.start?.();
551
545
 
552
- messageChannel = new MessageChannel;
546
+ // No handshake?
547
+ if (options.handshake === 0) {
548
+ readyStateOpen(true);
549
+ return;
550
+ }
551
+
552
+ const handshakeChannel = new MessageChannel;
553
+ portPlusMeta.set('handshake_channel', handshakeChannel);
553
554
 
554
- messageChannel.port1.onmessage = (e) => {
555
+ handshakeChannel.port1.onmessage = (e) => {
555
556
  if (this instanceof BroadcastChannel
556
557
  && options.clientServerMode === 'server'
557
- && typeof e.data === 'string') {
558
+ && typeof e.data?.id === 'string') {
558
559
  // Register clients that replied
559
- portPlusMeta.get('clients').add(e.data);
560
+ portPlusMeta.get('clients').add(e.data.id);
560
561
  }
561
- readyStateOpen();
562
+ if (typeof e.data?.isOpen) {
563
+ // This peer is ready to start messaging
564
+ readyStateOpen(true);
565
+ } else readyStateOpen(false);
562
566
  };
563
567
 
564
568
  const { wqOptions } = preProcessPostMessage.call(this);
@@ -567,8 +571,8 @@ export function MessagePortPlusMixin(superClass) {
567
571
  const pingData = { ['.wq']: wqOptions, ping: 'connect', id };
568
572
 
569
573
  this._postMessage
570
- ? this._postMessage(pingData, { transfer: [messageChannel.port2] })
571
- : super.postMessage(pingData, { transfer: [messageChannel.port2] });
574
+ ? this._postMessage(pingData, { transfer: [handshakeChannel.port2] })
575
+ : super.postMessage(pingData, { transfer: [handshakeChannel.port2] });
572
576
  }
573
577
 
574
578
  close(...args) {
@@ -580,7 +584,8 @@ export function MessagePortPlusMixin(superClass) {
580
584
  const portPlusMeta = _meta(this);
581
585
  const options = _options(this);
582
586
 
583
- if (!portPlusMeta.get('remote.close.called')
587
+ if (options.handshake > 0
588
+ && !portPlusMeta.get('remote.close.called')
584
589
  && (this instanceof BroadcastChannel || this instanceof MessagePort)) {
585
590
 
586
591
  const { wqOptions } = preProcessPostMessage.call(this);
@@ -604,11 +609,6 @@ export function MessagePortPlusMixin(superClass) {
604
609
 
605
610
  readyStateInternals.close.resolve(this);
606
611
 
607
- const openEvent = new MessageEventPlus(null, { type: 'close' });
608
- this._dispatchEvent
609
- ? this._dispatchEvent(openEvent)
610
- : super.dispatchEvent(openEvent);
611
-
612
612
  garbageCollect.call(this);
613
613
  }
614
614
  };
@@ -832,6 +832,7 @@ export function publishMutations(message, eventID, { signal, withArrayMethodDesc
832
832
  if (mutationsDone) dispose.abort();
833
833
  };
834
834
 
835
+
835
836
  const dispose = Observer.observe(message, Observer.subtree(), mutationHandler, { signal, withArrayMethodDescriptors });
836
837
  const garbageCollection = getGarbageCollection.call(this);
837
838
  garbageCollection.add(dispose);
package/src/StarPort.js CHANGED
@@ -8,13 +8,16 @@ import {
8
8
  export class StarPort extends MessagePortPlus {
9
9
 
10
10
  #ports = new Set;
11
+ #startCalled = false;
12
+ #closeCalled = false;
11
13
 
12
14
  get length() { return this.#ports.size; }
13
15
 
14
16
  [Symbol.iterator]() { return this.#ports[Symbol.iterator](); }
15
17
 
16
- constructor({ autoStart = true, postAwaitsOpen = false, autoClose = true } = {}) {
17
- super({ autoStart, postAwaitsOpen, autoClose });
18
+ constructor({ handshake = 0, postAwaitsOpen = false, autoClose = false } = {}) {
19
+ super({ handshake, postAwaitsOpen, autoClose });
20
+ if (handshake === 0) this.start();
18
21
  }
19
22
 
20
23
  addPort(portPlus, { enableBubbling = true } = {}) {
@@ -24,7 +27,7 @@ export class StarPort extends MessagePortPlus {
24
27
 
25
28
  const readyStateInternals = getReadyStateInternals.call(this);
26
29
 
27
- if (readyStateInternals.close.state) {
30
+ if (this.#closeCalled || readyStateInternals.close.state) {
28
31
  const starPortName = this.constructor.name;
29
32
  throw new Error(`Cannot add port to ${starPortName}. ${starPortName} is closed.`);
30
33
  }
@@ -41,8 +44,17 @@ export class StarPort extends MessagePortPlus {
41
44
  portPlusMeta.set('parentNode', this); // @ORDER: 2
42
45
  }
43
46
 
44
- portPlus.readyStateChange('open').then(() => this.start());
45
- portPlus.readyStateChange('close').then(cleanup);
47
+ if (this.options.handshake) {
48
+ portPlus.readyStateChange('open').then(() => {
49
+ readyStateInternals.open.state = true;
50
+ readyStateInternals.open.resolve(this);
51
+ });
52
+ portPlus.readyStateChange('close').then(() => cleanup());
53
+ }
54
+
55
+ if (this.#startCalled || readyStateInternals.open.state) {
56
+ portPlus.start();
57
+ }
46
58
 
47
59
  const cleanup = () => {
48
60
  if (!this.#ports.has(portPlus)) return;
@@ -56,7 +68,8 @@ export class StarPort extends MessagePortPlus {
56
68
 
57
69
  if (this.#ports.size === 0
58
70
  && _options(this).autoClose) {
59
- this.close();
71
+ readyStateInternals.close.state = true;
72
+ readyStateInternals.close.resolve(this);
60
73
  }
61
74
  };
62
75
 
@@ -78,33 +91,33 @@ export class StarPort extends MessagePortPlus {
78
91
  }
79
92
  }
80
93
 
81
- _autoStart() { } // Must be present to do nothing
82
-
83
94
  start() {
84
- const readyStateInternals = getReadyStateInternals.call(this);
85
-
86
- if (readyStateInternals.open.state) return;
87
- readyStateInternals.open.state = true;
95
+ if (this.#startCalled) return;
96
+ this.#startCalled = true;
88
97
 
89
- readyStateInternals.open.resolve(this);
98
+ for (const portPlus of this.#ports) {
99
+ portPlus.start();
100
+ }
90
101
 
91
- const openEvent = new MessageEventPlus(null, { type: 'open' });
92
- super.dispatchEvent(openEvent);
102
+ if (!this.options.handshake) {
103
+ const readyStateInternals = getReadyStateInternals.call(this);
104
+ readyStateInternals.open.state = true;
105
+ readyStateInternals.open.resolve(this);
106
+ }
93
107
  }
94
108
 
95
109
  close(...args) {
96
- const readyStateInternals = getReadyStateInternals.call(this);
97
-
98
- if (readyStateInternals.close.state) return;
99
- readyStateInternals.close.state = true;
110
+ if (this.#closeCalled) return;
111
+ this.#closeCalled = true;
100
112
 
101
113
  for (const portPlus of this.#ports) {
102
- portPlus.close?.(...args);
114
+ portPlus.close(...args);
103
115
  }
104
116
 
105
- readyStateInternals.close.resolve(this);
106
-
107
- const closeEvent = new MessageEventPlus(null, { type: 'close' });
108
- super.dispatchEvent(closeEvent);
117
+ if (!this.options.handshake) {
118
+ const readyStateInternals = getReadyStateInternals.call(this);
119
+ readyStateInternals.close.state = true;
120
+ readyStateInternals.close.resolve(this);
121
+ }
109
122
  }
110
123
  }
@@ -9,30 +9,42 @@ export class WebSocketPort extends MessagePortPlusMockPortsMixin(EventTarget) {
9
9
  #ws;
10
10
  #wsReady;
11
11
 
12
- constructor(ws, { autoStart = true, naturalOpen = true, postAwaitsOpen = false } = {}) {
12
+ constructor(ws, { handshake = 0, postAwaitsOpen = false } = {}) {
13
13
  super();
14
- this.#ws = typeof ws === 'string' ? new WebSocket(ws) : ws;
15
-
14
+
15
+ if (typeof handshake !== 'number') {
16
+ throw new Error('handshake must be a number');
17
+ }
18
+ if (handshake < 0 || handshake > 2) {
19
+ throw new Error('handshake must be between 0 and 2');
20
+ }
21
+
16
22
  const portPlusMeta = _meta(this);
17
- portPlusMeta.set('options', { autoStart, naturalOpen, postAwaitsOpen });
23
+ portPlusMeta.set('options', { handshake, postAwaitsOpen });
18
24
  // Must come before upgradeEvents()
19
25
 
26
+ this.#ws = typeof ws === 'string' ? new WebSocket(ws) : ws;
27
+
20
28
  this.constructor/* IMPORTANT */.upgradeEvents(this.#ws, this);
21
29
 
22
- if (naturalOpen
23
- && autoStart
24
- && this.#ws.readyState === WebSocket.OPEN) {
25
- this.start();
26
- }
27
30
  this.#wsReady = new Promise((resolve) => {
28
31
  if (this.#ws.readyState === WebSocket.OPEN) {
29
32
  resolve();
30
33
  } else {
31
- this.#ws.addEventListener('open', resolve);
34
+ this.#ws.addEventListener('open', () => resolve(), { once: true });
32
35
  }
33
36
  });
37
+
38
+ if (handshake === 0) {
39
+ this.#wsReady.then(() => this.start());
40
+ }
41
+
34
42
  if (this.#ws.readyState === WebSocket.CLOSED) {
35
- try { this.close(); } catch(e) {}
43
+ try { this.close(); } catch (e) { }
44
+ } else {
45
+ this.#ws.addEventListener('close', () => {
46
+ try { this.close(); } catch (e) { }
47
+ }, { once: true });
36
48
  }
37
49
  }
38
50
 
@@ -45,7 +57,7 @@ export class WebSocketPort extends MessagePortPlusMockPortsMixin(EventTarget) {
45
57
  Object.defineProperty(event, 'data', { value: data, configurable: true });
46
58
  return super._hydrateMessage(portPlus, event);
47
59
  }
48
- } catch (e) {}
60
+ } catch (e) { }
49
61
  return event;
50
62
  }
51
63