@styris-ame/y-engineio 1.1.0

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.
@@ -0,0 +1,591 @@
1
+ 'use strict';
2
+
3
+ require('yjs');
4
+ var bc = require('lib0/broadcastchannel');
5
+ var time = require('lib0/time');
6
+ var encoding = require('lib0/encoding');
7
+ var decoding = require('lib0/decoding');
8
+ var syncProtocol = require('y-protocols/sync');
9
+ var authProtocol = require('y-protocols/auth');
10
+ var awarenessProtocol = require('y-protocols/awareness');
11
+ var observable = require('lib0/observable');
12
+ var math = require('lib0/math');
13
+ var url = require('lib0/url');
14
+ var env = require('lib0/environment');
15
+ var engine_ioClient = require('engine.io-client');
16
+
17
+ function _interopNamespaceDefault(e) {
18
+ var n = Object.create(null);
19
+ if (e) {
20
+ Object.keys(e).forEach(function (k) {
21
+ if (k !== 'default') {
22
+ var d = Object.getOwnPropertyDescriptor(e, k);
23
+ Object.defineProperty(n, k, d.get ? d : {
24
+ enumerable: true,
25
+ get: function () { return e[k]; }
26
+ });
27
+ }
28
+ });
29
+ }
30
+ n.default = e;
31
+ return Object.freeze(n);
32
+ }
33
+
34
+ var bc__namespace = /*#__PURE__*/_interopNamespaceDefault(bc);
35
+ var time__namespace = /*#__PURE__*/_interopNamespaceDefault(time);
36
+ var encoding__namespace = /*#__PURE__*/_interopNamespaceDefault(encoding);
37
+ var decoding__namespace = /*#__PURE__*/_interopNamespaceDefault(decoding);
38
+ var syncProtocol__namespace = /*#__PURE__*/_interopNamespaceDefault(syncProtocol);
39
+ var authProtocol__namespace = /*#__PURE__*/_interopNamespaceDefault(authProtocol);
40
+ var awarenessProtocol__namespace = /*#__PURE__*/_interopNamespaceDefault(awarenessProtocol);
41
+ var math__namespace = /*#__PURE__*/_interopNamespaceDefault(math);
42
+ var url__namespace = /*#__PURE__*/_interopNamespaceDefault(url);
43
+ var env__namespace = /*#__PURE__*/_interopNamespaceDefault(env);
44
+
45
+ /**
46
+ * @module provider/engineio
47
+ */
48
+
49
+
50
+ const messageSync = 0;
51
+ const messageQueryAwareness = 3;
52
+ const messageAwareness = 1;
53
+ const messageAuth = 2;
54
+
55
+ /**
56
+ * encoder, decoder, provider, emitSynced, messageType
57
+ * @type {Array<function(encoding.Encoder, decoding.Decoder, EngineIOProvider, boolean, number):void>}
58
+ */
59
+ const messageHandlers = [];
60
+
61
+ messageHandlers[messageSync] = (
62
+ encoder,
63
+ decoder,
64
+ provider,
65
+ emitSynced,
66
+ _messageType
67
+ ) => {
68
+ encoding__namespace.writeVarUint(encoder, messageSync);
69
+ const syncMessageType = syncProtocol__namespace.readSyncMessage(
70
+ decoder,
71
+ encoder,
72
+ provider.doc,
73
+ provider
74
+ );
75
+ if (
76
+ emitSynced && syncMessageType === syncProtocol__namespace.messageYjsSyncStep2 &&
77
+ !provider.synced
78
+ ) {
79
+ provider.synced = true;
80
+ }
81
+ };
82
+
83
+ messageHandlers[messageQueryAwareness] = (
84
+ encoder,
85
+ _decoder,
86
+ provider,
87
+ _emitSynced,
88
+ _messageType
89
+ ) => {
90
+ encoding__namespace.writeVarUint(encoder, messageAwareness);
91
+ encoding__namespace.writeVarUint8Array(
92
+ encoder,
93
+ awarenessProtocol__namespace.encodeAwarenessUpdate(
94
+ provider.awareness,
95
+ Array.from(provider.awareness.getStates().keys())
96
+ )
97
+ );
98
+ };
99
+
100
+ messageHandlers[messageAwareness] = (
101
+ _encoder,
102
+ decoder,
103
+ provider,
104
+ _emitSynced,
105
+ _messageType
106
+ ) => {
107
+ awarenessProtocol__namespace.applyAwarenessUpdate(
108
+ provider.awareness,
109
+ decoding__namespace.readVarUint8Array(decoder),
110
+ provider
111
+ );
112
+ };
113
+
114
+ messageHandlers[messageAuth] = (
115
+ _encoder,
116
+ decoder,
117
+ provider,
118
+ _emitSynced,
119
+ _messageType
120
+ ) => {
121
+ authProtocol__namespace.readAuthMessage(
122
+ decoder,
123
+ provider.doc,
124
+ (_ydoc, reason) => permissionDeniedHandler(provider, reason)
125
+ );
126
+ };
127
+
128
+ const messageReconnectTimeout = 30000;
129
+
130
+ /**
131
+ * @param {EngineIOProvider} provider
132
+ * @param {string} reason
133
+ */
134
+ const permissionDeniedHandler = (provider, reason) =>
135
+ console.warn(`Permission denied to access ${provider.url}.\n${reason}`);
136
+
137
+ /**
138
+ * @param {ArrayBuffer | ArrayBufferView} data
139
+ * @return {Uint8Array}
140
+ */
141
+ const toUint8Array = (data) =>
142
+ data instanceof ArrayBuffer
143
+ ? new Uint8Array(data)
144
+ : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
145
+
146
+ /**
147
+ * @param {EngineIOProvider} provider
148
+ * @param {Uint8Array} buf
149
+ * @param {boolean} emitSynced
150
+ * @return {encoding.Encoder}
151
+ */
152
+ const readMessage = (provider, buf, emitSynced) => {
153
+ const decoder = decoding__namespace.createDecoder(buf);
154
+ const encoder = encoding__namespace.createEncoder();
155
+ const messageType = decoding__namespace.readVarUint(decoder);
156
+ const messageHandler = provider.messageHandlers[messageType];
157
+ if (/** @type {any} */ (messageHandler)) {
158
+ messageHandler(encoder, decoder, provider, emitSynced, messageType);
159
+ }
160
+ return encoder
161
+ };
162
+
163
+ /**
164
+ * Outsource this function so that a new engine.io connection is created immediately.
165
+ * I suspect that the `close` event is not always fired if there are network issues.
166
+ *
167
+ * @param {EngineIOProvider} provider
168
+ * @param {Engine} engine
169
+ * @param {any} event
170
+ */
171
+ const closeEngineConnection = (provider, engine, event) => {
172
+ if (engine === provider.engine) {
173
+ provider.emit('connection-close', [event, provider]);
174
+ provider.engine = null;
175
+ const anyEngine = /** @type {any} */ (engine);
176
+ if (anyEngine._yUnsubscribe) {
177
+ anyEngine._yUnsubscribe();
178
+ }
179
+ engine.close();
180
+ provider.connecting = false;
181
+ if (provider.connected) {
182
+ provider.connected = false;
183
+ provider.synced = false;
184
+ // update awareness (all users except local left)
185
+ awarenessProtocol__namespace.removeAwarenessStates(
186
+ provider.awareness,
187
+ Array.from(provider.awareness.getStates().keys()).filter((client) =>
188
+ client !== provider.doc.clientID
189
+ ),
190
+ provider
191
+ );
192
+ provider.emit('status', [{
193
+ status: 'disconnected'
194
+ }]);
195
+ } else {
196
+ provider.unsuccessfulReconnects++;
197
+ }
198
+ // Start with no reconnect timeout and increase timeout by
199
+ // using exponential backoff starting with 100ms
200
+ setTimeout(
201
+ setupEngine,
202
+ math__namespace.min(
203
+ math__namespace.pow(2, provider.unsuccessfulReconnects) * 100,
204
+ provider.maxBackoffTime
205
+ ),
206
+ provider
207
+ );
208
+ }
209
+ };
210
+
211
+ /**
212
+ * @param {EngineIOProvider} provider
213
+ */
214
+ const setupEngine = (provider) => {
215
+ if (provider.shouldConnect && provider.engine === null) {
216
+ const engine = new provider._Engine(provider.serverUrl, {
217
+ ...provider.engineOptions,
218
+ query: { ...provider.params, room: provider.roomname }
219
+ });
220
+ engine.binaryType = 'arraybuffer';
221
+ provider.engine = engine;
222
+ provider.connecting = true;
223
+ provider.connected = false;
224
+ provider.synced = false;
225
+
226
+ const onMessage = (/** @type {any} */ data) => {
227
+ if (provider.engine !== engine) return
228
+ if (typeof data === 'string') return
229
+ provider.lastMessageReceived = time__namespace.getUnixTime();
230
+ const encoder = readMessage(provider, toUint8Array(data), true);
231
+ if (encoding__namespace.length(encoder) > 1) {
232
+ engine.send(encoding__namespace.toUint8Array(encoder));
233
+ }
234
+ };
235
+ const onError = (/** @type {any} */ event) => {
236
+ if (provider.engine !== engine) return
237
+ provider.emit('connection-error', [event, provider]);
238
+ };
239
+ const onPing = () => {
240
+ if (provider.engine !== engine) return
241
+ provider.lastMessageReceived = time__namespace.getUnixTime();
242
+ };
243
+ const onClose = (/** @type {any} */ reason, /** @type {any} */ description) => {
244
+ closeEngineConnection(provider, engine, { reason, description });
245
+ };
246
+ const onOpen = () => {
247
+ if (provider.engine !== engine) return
248
+ provider.lastMessageReceived = time__namespace.getUnixTime();
249
+ provider.connecting = false;
250
+ provider.connected = true;
251
+ provider.unsuccessfulReconnects = 0;
252
+ provider.emit('status', [{
253
+ status: 'connected'
254
+ }]);
255
+ // always send sync step 1 when connected
256
+ const encoder = encoding__namespace.createEncoder();
257
+ encoding__namespace.writeVarUint(encoder, messageSync);
258
+ syncProtocol__namespace.writeSyncStep1(encoder, provider.doc);
259
+ engine.send(encoding__namespace.toUint8Array(encoder));
260
+ // broadcast local awareness state
261
+ if (provider.awareness.getLocalState() !== null) {
262
+ const encoderAwarenessState = encoding__namespace.createEncoder();
263
+ encoding__namespace.writeVarUint(encoderAwarenessState, messageAwareness);
264
+ encoding__namespace.writeVarUint8Array(
265
+ encoderAwarenessState,
266
+ awarenessProtocol__namespace.encodeAwarenessUpdate(provider.awareness, [
267
+ provider.doc.clientID
268
+ ])
269
+ );
270
+ engine.send(encoding__namespace.toUint8Array(encoderAwarenessState));
271
+ }
272
+ };
273
+ engine.on('message', onMessage);
274
+ engine.on('error', onError);
275
+ engine.on('ping', onPing);
276
+ engine.on('close', onClose);
277
+ engine.on('open', onOpen);
278
+ const anyEngine = /** @type {any} */ (engine);
279
+ anyEngine._yUnsubscribe = () => {
280
+ engine.off('message', onMessage);
281
+ engine.off('error', onError);
282
+ engine.off('ping', onPing);
283
+ engine.off('close', onClose);
284
+ engine.off('open', onOpen);
285
+ };
286
+ provider.emit('status', [{
287
+ status: 'connecting'
288
+ }]);
289
+ }
290
+ };
291
+
292
+ /**
293
+ * @param {EngineIOProvider} provider
294
+ * @param {Uint8Array} buf
295
+ */
296
+ const broadcastMessage = (provider, buf) => {
297
+ const engine = provider.engine;
298
+ if (provider.connected && engine && engine.readyState === 'open') {
299
+ engine.send(buf);
300
+ }
301
+ if (provider.bcconnected) {
302
+ bc__namespace.publish(provider.bcChannel, buf, provider);
303
+ }
304
+ };
305
+
306
+ /**
307
+ * Engine.IO Provider for Yjs. Creates an engine.io connection to sync the shared
308
+ * document. Unlike a raw WebSocket, engine.io connects to a single endpoint and
309
+ * has no document name in the URL, so the room name is sent as the `room`
310
+ * handshake query parameter, letting the server accept or reject the connection
311
+ * before any sync frames are exchanged.
312
+ *
313
+ * @example
314
+ * import * as Y from 'yjs'
315
+ * import { EngineIOProvider } from '@styris-ame/y-engineio'
316
+ * const doc = new Y.Doc()
317
+ * const provider = new EngineIOProvider('http://localhost:1234', 'my-document-name', doc)
318
+ *
319
+ * @extends {ObservableV2<{ 'connection-close': (event: any, provider: EngineIOProvider) => any, 'status': (event: { status: 'connected' | 'disconnected' | 'connecting' }) => any, 'connection-error': (event: any, provider: EngineIOProvider) => any, 'sync': (state: boolean) => any, 'synced': (state: boolean) => any }>}
320
+ */
321
+ class EngineIOProvider extends observable.ObservableV2 {
322
+ /**
323
+ * @param {string} serverUrl engine.io server origin, e.g. 'http://localhost:1234'
324
+ * @param {string} roomname
325
+ * @param {Y.Doc} doc
326
+ * @param {object} opts
327
+ * @param {boolean} [opts.connect]
328
+ * @param {awarenessProtocol.Awareness} [opts.awareness]
329
+ * @param {Object<string,string>} [opts.params] url query params, passed to engine.io as `query`
330
+ * @param {object} [opts.engineOptions] options forwarded to the engine.io-client `Socket` (e.g. `path`, `transports`, `withCredentials`, `extraHeaders`)
331
+ * @param {typeof Engine} [opts.EngineClass] override the engine.io `Socket` constructor (e.g. for testing)
332
+ * @param {number} [opts.resyncInterval] Request server state every `resyncInterval` milliseconds
333
+ * @param {number} [opts.maxBackoffTime] Maximum amount of time to wait before trying to reconnect (we try to reconnect using exponential backoff)
334
+ * @param {boolean} [opts.disableBc] Disable cross-tab BroadcastChannel communication
335
+ */
336
+ constructor (serverUrl, roomname, doc, {
337
+ connect = true,
338
+ awareness = new awarenessProtocol__namespace.Awareness(doc),
339
+ params = {},
340
+ engineOptions = {},
341
+ EngineClass = engine_ioClient.Socket,
342
+ resyncInterval = -1,
343
+ maxBackoffTime = 2500,
344
+ disableBc = false
345
+ } = {}) {
346
+ super();
347
+ // ensure that serverUrl does not end with /
348
+ while (serverUrl[serverUrl.length - 1] === '/') {
349
+ serverUrl = serverUrl.slice(0, serverUrl.length - 1);
350
+ }
351
+ this.serverUrl = serverUrl;
352
+ this.bcChannel = serverUrl + '/' + roomname;
353
+ this.maxBackoffTime = maxBackoffTime;
354
+ /**
355
+ * The specified url parameters. This can be safely updated. The changed parameters will be used
356
+ * when a new connection is established.
357
+ * @type {Object<string,string>}
358
+ */
359
+ this.params = params;
360
+ /**
361
+ * Options forwarded verbatim to the engine.io-client `Socket`.
362
+ * @type {object}
363
+ */
364
+ this.engineOptions = engineOptions;
365
+ this.roomname = roomname;
366
+ this.doc = doc;
367
+ this._Engine = EngineClass;
368
+ this.awareness = awareness;
369
+ this.connected = false;
370
+ this.connecting = false;
371
+ this.bcconnected = false;
372
+ this.disableBc = disableBc;
373
+ this.unsuccessfulReconnects = 0;
374
+ this.messageHandlers = messageHandlers.slice();
375
+ /**
376
+ * @type {boolean}
377
+ */
378
+ this._synced = false;
379
+ /**
380
+ * The engine.io-client `Socket`, or null when disconnected.
381
+ * @type {Engine?}
382
+ */
383
+ this.engine = null;
384
+ this.lastMessageReceived = 0;
385
+ /**
386
+ * Whether to connect to other peers or not
387
+ * @type {boolean}
388
+ */
389
+ this.shouldConnect = connect;
390
+
391
+ /**
392
+ * @type {number}
393
+ */
394
+ this._resyncInterval = 0;
395
+ if (resyncInterval > 0) {
396
+ this._resyncInterval = /** @type {any} */ (setInterval(() => {
397
+ if (this.engine && this.engine.readyState === 'open') {
398
+ // resend sync step 1
399
+ const encoder = encoding__namespace.createEncoder();
400
+ encoding__namespace.writeVarUint(encoder, messageSync);
401
+ syncProtocol__namespace.writeSyncStep1(encoder, doc);
402
+ this.engine.send(encoding__namespace.toUint8Array(encoder));
403
+ }
404
+ }, resyncInterval));
405
+ }
406
+
407
+ /**
408
+ * @param {ArrayBuffer} data
409
+ * @param {any} origin
410
+ */
411
+ this._bcSubscriber = (data, origin) => {
412
+ if (origin !== this) {
413
+ const encoder = readMessage(this, new Uint8Array(data), false);
414
+ if (encoding__namespace.length(encoder) > 1) {
415
+ bc__namespace.publish(this.bcChannel, encoding__namespace.toUint8Array(encoder), this);
416
+ }
417
+ }
418
+ };
419
+ /**
420
+ * Listens to Yjs updates and sends them to remote peers (engine.io and broadcastchannel)
421
+ * @param {Uint8Array} update
422
+ * @param {any} origin
423
+ */
424
+ this._updateHandler = (update, origin) => {
425
+ if (origin !== this) {
426
+ const encoder = encoding__namespace.createEncoder();
427
+ encoding__namespace.writeVarUint(encoder, messageSync);
428
+ syncProtocol__namespace.writeUpdate(encoder, update);
429
+ broadcastMessage(this, encoding__namespace.toUint8Array(encoder));
430
+ }
431
+ };
432
+ this.doc.on('update', this._updateHandler);
433
+ /**
434
+ * @param {any} changed
435
+ * @param {any} _origin
436
+ */
437
+ this._awarenessUpdateHandler = ({ added, updated, removed }, _origin) => {
438
+ const changedClients = added.concat(updated).concat(removed);
439
+ const encoder = encoding__namespace.createEncoder();
440
+ encoding__namespace.writeVarUint(encoder, messageAwareness);
441
+ encoding__namespace.writeVarUint8Array(
442
+ encoder,
443
+ awarenessProtocol__namespace.encodeAwarenessUpdate(awareness, changedClients)
444
+ );
445
+ broadcastMessage(this, encoding__namespace.toUint8Array(encoder));
446
+ };
447
+ this._exitHandler = () => {
448
+ awarenessProtocol__namespace.removeAwarenessStates(
449
+ this.awareness,
450
+ [doc.clientID],
451
+ 'app closed'
452
+ );
453
+ };
454
+ if (env__namespace.isNode && typeof process !== 'undefined') {
455
+ process.on('exit', this._exitHandler);
456
+ }
457
+ awareness.on('update', this._awarenessUpdateHandler);
458
+ this._checkInterval = /** @type {any} */ (setInterval(() => {
459
+ if (
460
+ this.connected &&
461
+ messageReconnectTimeout <
462
+ time__namespace.getUnixTime() - this.lastMessageReceived
463
+ ) {
464
+ // no message received in a long time - not even your own awareness
465
+ // updates (which are updated every 15 seconds)
466
+ closeEngineConnection(this, /** @type {Engine} */ (this.engine), null);
467
+ }
468
+ }, messageReconnectTimeout / 10));
469
+ if (connect) {
470
+ this.connect();
471
+ }
472
+ }
473
+
474
+ get url () {
475
+ const encodedParams = url__namespace.encodeQueryParams({ ...this.params, room: this.roomname });
476
+ return this.serverUrl + (encodedParams.length === 0 ? '' : '?' + encodedParams)
477
+ }
478
+
479
+ /**
480
+ * @type {boolean}
481
+ */
482
+ get synced () {
483
+ return this._synced
484
+ }
485
+
486
+ set synced (state) {
487
+ if (this._synced !== state) {
488
+ this._synced = state;
489
+ // @ts-ignore
490
+ this.emit('synced', [state]);
491
+ this.emit('sync', [state]);
492
+ }
493
+ }
494
+
495
+ destroy () {
496
+ if (this._resyncInterval !== 0) {
497
+ clearInterval(this._resyncInterval);
498
+ }
499
+ clearInterval(this._checkInterval);
500
+ this.disconnect();
501
+ if (env__namespace.isNode && typeof process !== 'undefined') {
502
+ process.off('exit', this._exitHandler);
503
+ }
504
+ this.awareness.off('update', this._awarenessUpdateHandler);
505
+ this.doc.off('update', this._updateHandler);
506
+ super.destroy();
507
+ }
508
+
509
+ connectBc () {
510
+ if (this.disableBc) {
511
+ return
512
+ }
513
+ if (!this.bcconnected) {
514
+ bc__namespace.subscribe(this.bcChannel, this._bcSubscriber);
515
+ this.bcconnected = true;
516
+ }
517
+ // send sync step1 to bc
518
+ // write sync step 1
519
+ const encoderSync = encoding__namespace.createEncoder();
520
+ encoding__namespace.writeVarUint(encoderSync, messageSync);
521
+ syncProtocol__namespace.writeSyncStep1(encoderSync, this.doc);
522
+ bc__namespace.publish(this.bcChannel, encoding__namespace.toUint8Array(encoderSync), this);
523
+ // broadcast local state
524
+ const encoderState = encoding__namespace.createEncoder();
525
+ encoding__namespace.writeVarUint(encoderState, messageSync);
526
+ syncProtocol__namespace.writeSyncStep2(encoderState, this.doc);
527
+ bc__namespace.publish(this.bcChannel, encoding__namespace.toUint8Array(encoderState), this);
528
+ // write queryAwareness
529
+ const encoderAwarenessQuery = encoding__namespace.createEncoder();
530
+ encoding__namespace.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
531
+ bc__namespace.publish(
532
+ this.bcChannel,
533
+ encoding__namespace.toUint8Array(encoderAwarenessQuery),
534
+ this
535
+ );
536
+ // broadcast local awareness state
537
+ const encoderAwarenessState = encoding__namespace.createEncoder();
538
+ encoding__namespace.writeVarUint(encoderAwarenessState, messageAwareness);
539
+ encoding__namespace.writeVarUint8Array(
540
+ encoderAwarenessState,
541
+ awarenessProtocol__namespace.encodeAwarenessUpdate(this.awareness, [
542
+ this.doc.clientID
543
+ ])
544
+ );
545
+ bc__namespace.publish(
546
+ this.bcChannel,
547
+ encoding__namespace.toUint8Array(encoderAwarenessState),
548
+ this
549
+ );
550
+ }
551
+
552
+ disconnectBc () {
553
+ // broadcast message with local awareness state set to null (indicating disconnect)
554
+ const encoder = encoding__namespace.createEncoder();
555
+ encoding__namespace.writeVarUint(encoder, messageAwareness);
556
+ encoding__namespace.writeVarUint8Array(
557
+ encoder,
558
+ awarenessProtocol__namespace.encodeAwarenessUpdate(this.awareness, [
559
+ this.doc.clientID
560
+ ], new Map())
561
+ );
562
+ broadcastMessage(this, encoding__namespace.toUint8Array(encoder));
563
+ if (this.bcconnected) {
564
+ bc__namespace.unsubscribe(this.bcChannel, this._bcSubscriber);
565
+ this.bcconnected = false;
566
+ }
567
+ }
568
+
569
+ disconnect () {
570
+ this.shouldConnect = false;
571
+ this.disconnectBc();
572
+ if (this.engine !== null) {
573
+ closeEngineConnection(this, this.engine, null);
574
+ }
575
+ }
576
+
577
+ connect () {
578
+ this.shouldConnect = true;
579
+ if (!this.connected && this.engine === null) {
580
+ setupEngine(this);
581
+ this.connectBc();
582
+ }
583
+ }
584
+ }
585
+
586
+ exports.EngineIOProvider = EngineIOProvider;
587
+ exports.messageAuth = messageAuth;
588
+ exports.messageAwareness = messageAwareness;
589
+ exports.messageQueryAwareness = messageQueryAwareness;
590
+ exports.messageSync = messageSync;
591
+ //# sourceMappingURL=y-engineio.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"y-engineio.cjs","sources":["../src/y-engineio.js"],"sourcesContent":["/**\n * @module provider/engineio\n */\n\n/* eslint-env browser */\nimport * as Y from 'yjs' // eslint-disable-line\nimport * as bc from 'lib0/broadcastchannel'\nimport * as time from 'lib0/time'\nimport * as encoding from 'lib0/encoding'\nimport * as decoding from 'lib0/decoding'\nimport * as syncProtocol from 'y-protocols/sync'\nimport * as authProtocol from 'y-protocols/auth'\nimport * as awarenessProtocol from 'y-protocols/awareness'\nimport { ObservableV2 } from 'lib0/observable'\nimport * as math from 'lib0/math'\nimport * as url from 'lib0/url'\nimport * as env from 'lib0/environment'\nimport { Socket as Engine } from 'engine.io-client'\n\nexport const messageSync = 0\nexport const messageQueryAwareness = 3\nexport const messageAwareness = 1\nexport const messageAuth = 2\n\n/**\n * encoder, decoder, provider, emitSynced, messageType\n * @type {Array<function(encoding.Encoder, decoding.Decoder, EngineIOProvider, boolean, number):void>}\n */\nconst messageHandlers = []\n\nmessageHandlers[messageSync] = (\n encoder,\n decoder,\n provider,\n emitSynced,\n _messageType\n) => {\n encoding.writeVarUint(encoder, messageSync)\n const syncMessageType = syncProtocol.readSyncMessage(\n decoder,\n encoder,\n provider.doc,\n provider\n )\n if (\n emitSynced && syncMessageType === syncProtocol.messageYjsSyncStep2 &&\n !provider.synced\n ) {\n provider.synced = true\n }\n}\n\nmessageHandlers[messageQueryAwareness] = (\n encoder,\n _decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n encoding.writeVarUint(encoder, messageAwareness)\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n provider.awareness,\n Array.from(provider.awareness.getStates().keys())\n )\n )\n}\n\nmessageHandlers[messageAwareness] = (\n _encoder,\n decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n awarenessProtocol.applyAwarenessUpdate(\n provider.awareness,\n decoding.readVarUint8Array(decoder),\n provider\n )\n}\n\nmessageHandlers[messageAuth] = (\n _encoder,\n decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n authProtocol.readAuthMessage(\n decoder,\n provider.doc,\n (_ydoc, reason) => permissionDeniedHandler(provider, reason)\n )\n}\n\nconst messageReconnectTimeout = 30000\n\n/**\n * @param {EngineIOProvider} provider\n * @param {string} reason\n */\nconst permissionDeniedHandler = (provider, reason) =>\n console.warn(`Permission denied to access ${provider.url}.\\n${reason}`)\n\n/**\n * @param {ArrayBuffer | ArrayBufferView} data\n * @return {Uint8Array}\n */\nconst toUint8Array = (data) =>\n data instanceof ArrayBuffer\n ? new Uint8Array(data)\n : new Uint8Array(data.buffer, data.byteOffset, data.byteLength)\n\n/**\n * @param {EngineIOProvider} provider\n * @param {Uint8Array} buf\n * @param {boolean} emitSynced\n * @return {encoding.Encoder}\n */\nconst readMessage = (provider, buf, emitSynced) => {\n const decoder = decoding.createDecoder(buf)\n const encoder = encoding.createEncoder()\n const messageType = decoding.readVarUint(decoder)\n const messageHandler = provider.messageHandlers[messageType]\n if (/** @type {any} */ (messageHandler)) {\n messageHandler(encoder, decoder, provider, emitSynced, messageType)\n }\n return encoder\n}\n\n/**\n * Outsource this function so that a new engine.io connection is created immediately.\n * I suspect that the `close` event is not always fired if there are network issues.\n *\n * @param {EngineIOProvider} provider\n * @param {Engine} engine\n * @param {any} event\n */\nconst closeEngineConnection = (provider, engine, event) => {\n if (engine === provider.engine) {\n provider.emit('connection-close', [event, provider])\n provider.engine = null\n const anyEngine = /** @type {any} */ (engine)\n if (anyEngine._yUnsubscribe) {\n anyEngine._yUnsubscribe()\n }\n engine.close()\n provider.connecting = false\n if (provider.connected) {\n provider.connected = false\n provider.synced = false\n // update awareness (all users except local left)\n awarenessProtocol.removeAwarenessStates(\n provider.awareness,\n Array.from(provider.awareness.getStates().keys()).filter((client) =>\n client !== provider.doc.clientID\n ),\n provider\n )\n provider.emit('status', [{\n status: 'disconnected'\n }])\n } else {\n provider.unsuccessfulReconnects++\n }\n // Start with no reconnect timeout and increase timeout by\n // using exponential backoff starting with 100ms\n setTimeout(\n setupEngine,\n math.min(\n math.pow(2, provider.unsuccessfulReconnects) * 100,\n provider.maxBackoffTime\n ),\n provider\n )\n }\n}\n\n/**\n * @param {EngineIOProvider} provider\n */\nconst setupEngine = (provider) => {\n if (provider.shouldConnect && provider.engine === null) {\n const engine = new provider._Engine(provider.serverUrl, {\n ...provider.engineOptions,\n query: { ...provider.params, room: provider.roomname }\n })\n engine.binaryType = 'arraybuffer'\n provider.engine = engine\n provider.connecting = true\n provider.connected = false\n provider.synced = false\n\n const onMessage = (/** @type {any} */ data) => {\n if (provider.engine !== engine) return\n if (typeof data === 'string') return\n provider.lastMessageReceived = time.getUnixTime()\n const encoder = readMessage(provider, toUint8Array(data), true)\n if (encoding.length(encoder) > 1) {\n engine.send(encoding.toUint8Array(encoder))\n }\n }\n const onError = (/** @type {any} */ event) => {\n if (provider.engine !== engine) return\n provider.emit('connection-error', [event, provider])\n }\n const onPing = () => {\n if (provider.engine !== engine) return\n provider.lastMessageReceived = time.getUnixTime()\n }\n const onClose = (/** @type {any} */ reason, /** @type {any} */ description) => {\n closeEngineConnection(provider, engine, { reason, description })\n }\n const onOpen = () => {\n if (provider.engine !== engine) return\n provider.lastMessageReceived = time.getUnixTime()\n provider.connecting = false\n provider.connected = true\n provider.unsuccessfulReconnects = 0\n provider.emit('status', [{\n status: 'connected'\n }])\n // always send sync step 1 when connected\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageSync)\n syncProtocol.writeSyncStep1(encoder, provider.doc)\n engine.send(encoding.toUint8Array(encoder))\n // broadcast local awareness state\n if (provider.awareness.getLocalState() !== null) {\n const encoderAwarenessState = encoding.createEncoder()\n encoding.writeVarUint(encoderAwarenessState, messageAwareness)\n encoding.writeVarUint8Array(\n encoderAwarenessState,\n awarenessProtocol.encodeAwarenessUpdate(provider.awareness, [\n provider.doc.clientID\n ])\n )\n engine.send(encoding.toUint8Array(encoderAwarenessState))\n }\n }\n engine.on('message', onMessage)\n engine.on('error', onError)\n engine.on('ping', onPing)\n engine.on('close', onClose)\n engine.on('open', onOpen)\n const anyEngine = /** @type {any} */ (engine)\n anyEngine._yUnsubscribe = () => {\n engine.off('message', onMessage)\n engine.off('error', onError)\n engine.off('ping', onPing)\n engine.off('close', onClose)\n engine.off('open', onOpen)\n }\n provider.emit('status', [{\n status: 'connecting'\n }])\n }\n}\n\n/**\n * @param {EngineIOProvider} provider\n * @param {Uint8Array} buf\n */\nconst broadcastMessage = (provider, buf) => {\n const engine = provider.engine\n if (provider.connected && engine && engine.readyState === 'open') {\n engine.send(buf)\n }\n if (provider.bcconnected) {\n bc.publish(provider.bcChannel, buf, provider)\n }\n}\n\n/**\n * Engine.IO Provider for Yjs. Creates an engine.io connection to sync the shared\n * document. Unlike a raw WebSocket, engine.io connects to a single endpoint and\n * has no document name in the URL, so the room name is sent as the `room`\n * handshake query parameter, letting the server accept or reject the connection\n * before any sync frames are exchanged.\n *\n * @example\n * import * as Y from 'yjs'\n * import { EngineIOProvider } from '@styris-ame/y-engineio'\n * const doc = new Y.Doc()\n * const provider = new EngineIOProvider('http://localhost:1234', 'my-document-name', doc)\n *\n * @extends {ObservableV2<{ 'connection-close': (event: any, provider: EngineIOProvider) => any, 'status': (event: { status: 'connected' | 'disconnected' | 'connecting' }) => any, 'connection-error': (event: any, provider: EngineIOProvider) => any, 'sync': (state: boolean) => any, 'synced': (state: boolean) => any }>}\n */\nexport class EngineIOProvider extends ObservableV2 {\n /**\n * @param {string} serverUrl engine.io server origin, e.g. 'http://localhost:1234'\n * @param {string} roomname\n * @param {Y.Doc} doc\n * @param {object} opts\n * @param {boolean} [opts.connect]\n * @param {awarenessProtocol.Awareness} [opts.awareness]\n * @param {Object<string,string>} [opts.params] url query params, passed to engine.io as `query`\n * @param {object} [opts.engineOptions] options forwarded to the engine.io-client `Socket` (e.g. `path`, `transports`, `withCredentials`, `extraHeaders`)\n * @param {typeof Engine} [opts.EngineClass] override the engine.io `Socket` constructor (e.g. for testing)\n * @param {number} [opts.resyncInterval] Request server state every `resyncInterval` milliseconds\n * @param {number} [opts.maxBackoffTime] Maximum amount of time to wait before trying to reconnect (we try to reconnect using exponential backoff)\n * @param {boolean} [opts.disableBc] Disable cross-tab BroadcastChannel communication\n */\n constructor (serverUrl, roomname, doc, {\n connect = true,\n awareness = new awarenessProtocol.Awareness(doc),\n params = {},\n engineOptions = {},\n EngineClass = Engine,\n resyncInterval = -1,\n maxBackoffTime = 2500,\n disableBc = false\n } = {}) {\n super()\n // ensure that serverUrl does not end with /\n while (serverUrl[serverUrl.length - 1] === '/') {\n serverUrl = serverUrl.slice(0, serverUrl.length - 1)\n }\n this.serverUrl = serverUrl\n this.bcChannel = serverUrl + '/' + roomname\n this.maxBackoffTime = maxBackoffTime\n /**\n * The specified url parameters. This can be safely updated. The changed parameters will be used\n * when a new connection is established.\n * @type {Object<string,string>}\n */\n this.params = params\n /**\n * Options forwarded verbatim to the engine.io-client `Socket`.\n * @type {object}\n */\n this.engineOptions = engineOptions\n this.roomname = roomname\n this.doc = doc\n this._Engine = EngineClass\n this.awareness = awareness\n this.connected = false\n this.connecting = false\n this.bcconnected = false\n this.disableBc = disableBc\n this.unsuccessfulReconnects = 0\n this.messageHandlers = messageHandlers.slice()\n /**\n * @type {boolean}\n */\n this._synced = false\n /**\n * The engine.io-client `Socket`, or null when disconnected.\n * @type {Engine?}\n */\n this.engine = null\n this.lastMessageReceived = 0\n /**\n * Whether to connect to other peers or not\n * @type {boolean}\n */\n this.shouldConnect = connect\n\n /**\n * @type {number}\n */\n this._resyncInterval = 0\n if (resyncInterval > 0) {\n this._resyncInterval = /** @type {any} */ (setInterval(() => {\n if (this.engine && this.engine.readyState === 'open') {\n // resend sync step 1\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageSync)\n syncProtocol.writeSyncStep1(encoder, doc)\n this.engine.send(encoding.toUint8Array(encoder))\n }\n }, resyncInterval))\n }\n\n /**\n * @param {ArrayBuffer} data\n * @param {any} origin\n */\n this._bcSubscriber = (data, origin) => {\n if (origin !== this) {\n const encoder = readMessage(this, new Uint8Array(data), false)\n if (encoding.length(encoder) > 1) {\n bc.publish(this.bcChannel, encoding.toUint8Array(encoder), this)\n }\n }\n }\n /**\n * Listens to Yjs updates and sends them to remote peers (engine.io and broadcastchannel)\n * @param {Uint8Array} update\n * @param {any} origin\n */\n this._updateHandler = (update, origin) => {\n if (origin !== this) {\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageSync)\n syncProtocol.writeUpdate(encoder, update)\n broadcastMessage(this, encoding.toUint8Array(encoder))\n }\n }\n this.doc.on('update', this._updateHandler)\n /**\n * @param {any} changed\n * @param {any} _origin\n */\n this._awarenessUpdateHandler = ({ added, updated, removed }, _origin) => {\n const changedClients = added.concat(updated).concat(removed)\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageAwareness)\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(awareness, changedClients)\n )\n broadcastMessage(this, encoding.toUint8Array(encoder))\n }\n this._exitHandler = () => {\n awarenessProtocol.removeAwarenessStates(\n this.awareness,\n [doc.clientID],\n 'app closed'\n )\n }\n if (env.isNode && typeof process !== 'undefined') {\n process.on('exit', this._exitHandler)\n }\n awareness.on('update', this._awarenessUpdateHandler)\n this._checkInterval = /** @type {any} */ (setInterval(() => {\n if (\n this.connected &&\n messageReconnectTimeout <\n time.getUnixTime() - this.lastMessageReceived\n ) {\n // no message received in a long time - not even your own awareness\n // updates (which are updated every 15 seconds)\n closeEngineConnection(this, /** @type {Engine} */ (this.engine), null)\n }\n }, messageReconnectTimeout / 10))\n if (connect) {\n this.connect()\n }\n }\n\n get url () {\n const encodedParams = url.encodeQueryParams({ ...this.params, room: this.roomname })\n return this.serverUrl + (encodedParams.length === 0 ? '' : '?' + encodedParams)\n }\n\n /**\n * @type {boolean}\n */\n get synced () {\n return this._synced\n }\n\n set synced (state) {\n if (this._synced !== state) {\n this._synced = state\n // @ts-ignore\n this.emit('synced', [state])\n this.emit('sync', [state])\n }\n }\n\n destroy () {\n if (this._resyncInterval !== 0) {\n clearInterval(this._resyncInterval)\n }\n clearInterval(this._checkInterval)\n this.disconnect()\n if (env.isNode && typeof process !== 'undefined') {\n process.off('exit', this._exitHandler)\n }\n this.awareness.off('update', this._awarenessUpdateHandler)\n this.doc.off('update', this._updateHandler)\n super.destroy()\n }\n\n connectBc () {\n if (this.disableBc) {\n return\n }\n if (!this.bcconnected) {\n bc.subscribe(this.bcChannel, this._bcSubscriber)\n this.bcconnected = true\n }\n // send sync step1 to bc\n // write sync step 1\n const encoderSync = encoding.createEncoder()\n encoding.writeVarUint(encoderSync, messageSync)\n syncProtocol.writeSyncStep1(encoderSync, this.doc)\n bc.publish(this.bcChannel, encoding.toUint8Array(encoderSync), this)\n // broadcast local state\n const encoderState = encoding.createEncoder()\n encoding.writeVarUint(encoderState, messageSync)\n syncProtocol.writeSyncStep2(encoderState, this.doc)\n bc.publish(this.bcChannel, encoding.toUint8Array(encoderState), this)\n // write queryAwareness\n const encoderAwarenessQuery = encoding.createEncoder()\n encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness)\n bc.publish(\n this.bcChannel,\n encoding.toUint8Array(encoderAwarenessQuery),\n this\n )\n // broadcast local awareness state\n const encoderAwarenessState = encoding.createEncoder()\n encoding.writeVarUint(encoderAwarenessState, messageAwareness)\n encoding.writeVarUint8Array(\n encoderAwarenessState,\n awarenessProtocol.encodeAwarenessUpdate(this.awareness, [\n this.doc.clientID\n ])\n )\n bc.publish(\n this.bcChannel,\n encoding.toUint8Array(encoderAwarenessState),\n this\n )\n }\n\n disconnectBc () {\n // broadcast message with local awareness state set to null (indicating disconnect)\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageAwareness)\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(this.awareness, [\n this.doc.clientID\n ], new Map())\n )\n broadcastMessage(this, encoding.toUint8Array(encoder))\n if (this.bcconnected) {\n bc.unsubscribe(this.bcChannel, this._bcSubscriber)\n this.bcconnected = false\n }\n }\n\n disconnect () {\n this.shouldConnect = false\n this.disconnectBc()\n if (this.engine !== null) {\n closeEngineConnection(this, this.engine, null)\n }\n }\n\n connect () {\n this.shouldConnect = true\n if (!this.connected && this.engine === null) {\n setupEngine(this)\n this.connectBc()\n }\n }\n}\n"],"names":["encoding","syncProtocol","awarenessProtocol","decoding","authProtocol","math","time","bc","ObservableV2","Engine","env","url"],"mappings":"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"}