kritzel-stencil 0.1.88 → 0.1.90

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 (53) hide show
  1. package/dist/cjs/index.cjs.js +216 -3020
  2. package/dist/cjs/kritzel-active-users_42.cjs.entry.js +19 -16
  3. package/dist/cjs/loader.cjs.js +1 -1
  4. package/dist/cjs/stencil.cjs.js +1 -1
  5. package/dist/cjs/{workspace.migrations-6IqGagXh.js → workspace.migrations-MMHzd-RY.js} +2948 -85
  6. package/dist/collection/classes/core/core.class.js +1 -1
  7. package/dist/collection/classes/{assets → providers/assets}/asset-resolver.class.js +17 -0
  8. package/dist/collection/classes/{assets → providers/assets}/http-asset-provider.class.js +6 -1
  9. package/dist/collection/classes/{assets → providers/assets}/indexeddb-asset-provider.class.js +8 -0
  10. package/dist/collection/classes/{assets → providers/assets}/presigned-asset-provider.class.js +6 -1
  11. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +34 -6
  12. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +9 -9
  13. package/dist/collection/configs/default-asset-storage.config.js +1 -1
  14. package/dist/collection/configs/default-sync.config.js +1 -1
  15. package/dist/collection/constants/version.js +1 -1
  16. package/dist/collection/index.js +8 -8
  17. package/dist/components/index.js +1 -1
  18. package/dist/components/kritzel-editor.js +1 -1
  19. package/dist/components/kritzel-engine.js +1 -1
  20. package/dist/components/kritzel-settings.js +1 -1
  21. package/dist/components/{p-BxIC2o6G.js → p-DNAGxoqB.js} +2 -2
  22. package/dist/components/{p-Br9ky8bs.js → p-GQ2svYqq.js} +1 -1
  23. package/dist/esm/index.js +214 -3018
  24. package/dist/esm/kritzel-active-users_42.entry.js +19 -16
  25. package/dist/esm/loader.js +1 -1
  26. package/dist/esm/stencil.js +1 -1
  27. package/dist/esm/{workspace.migrations-Dviv45Qv.js → workspace.migrations-CptkdL-N.js} +2845 -5
  28. package/dist/stencil/index.esm.js +1 -1
  29. package/dist/stencil/p-6dd05fe7.entry.js +9 -0
  30. package/dist/stencil/p-CptkdL-N.js +1 -0
  31. package/dist/stencil/stencil.esm.js +1 -1
  32. package/dist/types/classes/core/core.class.d.ts +1 -1
  33. package/dist/types/classes/{assets → providers/assets}/asset-resolver.class.d.ts +4 -3
  34. package/dist/types/classes/{assets → providers/assets}/http-asset-provider.class.d.ts +6 -2
  35. package/dist/types/classes/{assets → providers/assets}/indexeddb-asset-provider.class.d.ts +7 -2
  36. package/dist/types/classes/{assets → providers/assets}/presigned-asset-provider.class.d.ts +6 -2
  37. package/dist/types/classes/providers/{broadcast-sync-provider.class.d.ts → sync/broadcast-sync-provider.class.d.ts} +1 -1
  38. package/dist/types/classes/providers/{hocuspocus-sync-provider.class.d.ts → sync/hocuspocus-sync-provider.class.d.ts} +1 -1
  39. package/dist/types/classes/providers/{indexeddb-sync-provider.class.d.ts → sync/indexeddb-sync-provider.class.d.ts} +1 -1
  40. package/dist/types/classes/providers/{websocket-sync-provider.class.d.ts → sync/websocket-sync-provider.class.d.ts} +1 -1
  41. package/dist/types/components/core/kritzel-editor/kritzel-editor.d.ts +2 -0
  42. package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +2 -2
  43. package/dist/types/components.d.ts +12 -4
  44. package/dist/types/constants/version.d.ts +1 -1
  45. package/dist/types/index.d.ts +8 -8
  46. package/dist/types/interfaces/asset-storage-config.interface.d.ts +4 -0
  47. package/package.json +1 -1
  48. package/dist/stencil/p-1620740b.entry.js +0 -9
  49. package/dist/stencil/p-Dviv45Qv.js +0 -1
  50. /package/dist/collection/classes/providers/{broadcast-sync-provider.class.js → sync/broadcast-sync-provider.class.js} +0 -0
  51. /package/dist/collection/classes/providers/{hocuspocus-sync-provider.class.js → sync/hocuspocus-sync-provider.class.js} +0 -0
  52. /package/dist/collection/classes/providers/{indexeddb-sync-provider.class.js → sync/indexeddb-sync-provider.class.js} +0 -0
  53. /package/dist/collection/classes/providers/{websocket-sync-provider.class.js → sync/websocket-sync-provider.class.js} +0 -0
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var workspace_migrations = require('./workspace.migrations-6IqGagXh.js');
3
+ var workspace_migrations = require('./workspace.migrations-MMHzd-RY.js');
4
4
  var Y = require('yjs');
5
5
  var yWebsocket = require('y-websocket');
6
6
  require('y-indexeddb');
@@ -31,7 +31,7 @@ var Y__namespace = /*#__PURE__*/_interopNamespace(Y);
31
31
  * @module math
32
32
  */
33
33
 
34
- const floor$2 = Math.floor;
34
+ const floor = Math.floor;
35
35
 
36
36
  /**
37
37
  * @function
@@ -39,7 +39,7 @@ const floor$2 = Math.floor;
39
39
  * @param {number} b
40
40
  * @return {number} The smaller element of a and b
41
41
  */
42
- const min$2 = (a, b) => a < b ? a : b;
42
+ const min = (a, b) => a < b ? a : b;
43
43
 
44
44
  /**
45
45
  * @function
@@ -47,12 +47,12 @@ const min$2 = (a, b) => a < b ? a : b;
47
47
  * @param {number} b
48
48
  * @return {number} The bigger element of a and b
49
49
  */
50
- const max$2 = (a, b) => a > b ? a : b;
50
+ const max = (a, b) => a > b ? a : b;
51
51
 
52
52
  /* eslint-env browser */
53
53
 
54
- const BIT8$2 = 128;
55
- const BITS7$2 = 127;
54
+ const BIT8 = 128;
55
+ const BITS7 = 127;
56
56
 
57
57
  /**
58
58
  * Utility helpers for working with numbers.
@@ -61,7 +61,7 @@ const BITS7$2 = 127;
61
61
  */
62
62
 
63
63
 
64
- const MAX_SAFE_INTEGER$2 = Number.MAX_SAFE_INTEGER;
64
+ const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER;
65
65
 
66
66
  /**
67
67
  * Efficient schema-less binary encoding with support for variable length encoding.
@@ -95,7 +95,7 @@ const MAX_SAFE_INTEGER$2 = Number.MAX_SAFE_INTEGER;
95
95
  /**
96
96
  * A BinaryEncoder handles the encoding to an Uint8Array.
97
97
  */
98
- let Encoder$1 = class Encoder {
98
+ class Encoder {
99
99
  constructor () {
100
100
  this.cpos = 0;
101
101
  this.cbuf = new Uint8Array(100);
@@ -104,13 +104,13 @@ let Encoder$1 = class Encoder {
104
104
  */
105
105
  this.bufs = [];
106
106
  }
107
- };
107
+ }
108
108
 
109
109
  /**
110
110
  * @function
111
111
  * @return {Encoder}
112
112
  */
113
- const createEncoder$1 = () => new Encoder$1();
113
+ const createEncoder = () => new Encoder();
114
114
 
115
115
  /**
116
116
  * The current length of the encoded data.
@@ -119,7 +119,7 @@ const createEncoder$1 = () => new Encoder$1();
119
119
  * @param {Encoder} encoder
120
120
  * @return {number}
121
121
  */
122
- const length$2 = encoder => {
122
+ const length = encoder => {
123
123
  let len = encoder.cpos;
124
124
  for (let i = 0; i < encoder.bufs.length; i++) {
125
125
  len += encoder.bufs[i].length;
@@ -134,8 +134,8 @@ const length$2 = encoder => {
134
134
  * @param {Encoder} encoder
135
135
  * @return {Uint8Array<ArrayBuffer>} The created ArrayBuffer.
136
136
  */
137
- const toUint8Array$1 = encoder => {
138
- const uint8arr = new Uint8Array(length$2(encoder));
137
+ const toUint8Array = encoder => {
138
+ const uint8arr = new Uint8Array(length(encoder));
139
139
  let curPos = 0;
140
140
  for (let i = 0; i < encoder.bufs.length; i++) {
141
141
  const d = encoder.bufs[i];
@@ -153,7 +153,7 @@ const toUint8Array$1 = encoder => {
153
153
  * @param {Encoder} encoder
154
154
  * @param {number} num The byte that is to be encoded.
155
155
  */
156
- const write$2 = (encoder, num) => {
156
+ const write = (encoder, num) => {
157
157
  const bufferLen = encoder.cbuf.length;
158
158
  if (encoder.cpos === bufferLen) {
159
159
  encoder.bufs.push(encoder.cbuf);
@@ -170,12 +170,12 @@ const write$2 = (encoder, num) => {
170
170
  * @param {Encoder} encoder
171
171
  * @param {number} num The number that is to be encoded.
172
172
  */
173
- const writeVarUint$2 = (encoder, num) => {
174
- while (num > BITS7$2) {
175
- write$2(encoder, BIT8$2 | (BITS7$2 & num));
176
- num = floor$2(num / 128); // shift >>> 7
173
+ const writeVarUint = (encoder, num) => {
174
+ while (num > BITS7) {
175
+ write(encoder, BIT8 | (BITS7 & num));
176
+ num = floor(num / 128); // shift >>> 7
177
177
  }
178
- write$2(encoder, BITS7$2 & num);
178
+ write(encoder, BITS7 & num);
179
179
  };
180
180
 
181
181
  /**
@@ -185,10 +185,10 @@ const writeVarUint$2 = (encoder, num) => {
185
185
  * @param {Encoder} encoder
186
186
  * @param {Uint8Array} uint8Array
187
187
  */
188
- const writeUint8Array$2 = (encoder, uint8Array) => {
188
+ const writeUint8Array = (encoder, uint8Array) => {
189
189
  const bufferLen = encoder.cbuf.length;
190
190
  const cpos = encoder.cpos;
191
- const leftCopyLen = min$2(bufferLen - cpos, uint8Array.length);
191
+ const leftCopyLen = min(bufferLen - cpos, uint8Array.length);
192
192
  const rightCopyLen = uint8Array.length - leftCopyLen;
193
193
  encoder.cbuf.set(uint8Array.subarray(0, leftCopyLen), cpos);
194
194
  encoder.cpos += leftCopyLen;
@@ -197,7 +197,7 @@ const writeUint8Array$2 = (encoder, uint8Array) => {
197
197
  // Append new buffer
198
198
  encoder.bufs.push(encoder.cbuf);
199
199
  // must have at least size of remaining buffer
200
- encoder.cbuf = new Uint8Array(max$2(bufferLen * 2, rightCopyLen));
200
+ encoder.cbuf = new Uint8Array(max(bufferLen * 2, rightCopyLen));
201
201
  // copy array
202
202
  encoder.cbuf.set(uint8Array.subarray(leftCopyLen));
203
203
  encoder.cpos = rightCopyLen;
@@ -211,9 +211,9 @@ const writeUint8Array$2 = (encoder, uint8Array) => {
211
211
  * @param {Encoder} encoder
212
212
  * @param {Uint8Array} uint8Array
213
213
  */
214
- const writeVarUint8Array$2 = (encoder, uint8Array) => {
215
- writeVarUint$2(encoder, uint8Array.byteLength);
216
- writeUint8Array$2(encoder, uint8Array);
214
+ const writeVarUint8Array = (encoder, uint8Array) => {
215
+ writeVarUint(encoder, uint8Array.byteLength);
216
+ writeUint8Array(encoder, uint8Array);
217
217
  };
218
218
 
219
219
  /**
@@ -227,7 +227,7 @@ const writeVarUint8Array$2 = (encoder, uint8Array) => {
227
227
  * @return {Error}
228
228
  */
229
229
  /* c8 ignore next */
230
- const create$4 = s => new Error(s);
230
+ const create = s => new Error(s);
231
231
 
232
232
  /**
233
233
  * Efficient schema-less binary decoding with support for variable length encoding.
@@ -258,14 +258,14 @@ const create$4 = s => new Error(s);
258
258
  */
259
259
 
260
260
 
261
- const errorUnexpectedEndOfArray$2 = create$4('Unexpected end of array');
262
- const errorIntegerOutOfRange$2 = create$4('Integer out of Range');
261
+ const errorUnexpectedEndOfArray = create('Unexpected end of array');
262
+ const errorIntegerOutOfRange = create('Integer out of Range');
263
263
 
264
264
  /**
265
265
  * A Decoder handles the decoding of an Uint8Array.
266
266
  * @template {ArrayBufferLike} [Buf=ArrayBufferLike]
267
267
  */
268
- let Decoder$1 = class Decoder {
268
+ class Decoder {
269
269
  /**
270
270
  * @param {Uint8Array<Buf>} uint8Array Binary data to decode
271
271
  */
@@ -283,7 +283,7 @@ let Decoder$1 = class Decoder {
283
283
  */
284
284
  this.pos = 0;
285
285
  }
286
- };
286
+ }
287
287
 
288
288
  /**
289
289
  * @function
@@ -291,7 +291,7 @@ let Decoder$1 = class Decoder {
291
291
  * @param {Uint8Array<Buf>} uint8Array
292
292
  * @return {Decoder<Buf>}
293
293
  */
294
- const createDecoder$1 = uint8Array => new Decoder$1(uint8Array);
294
+ const createDecoder = uint8Array => new Decoder(uint8Array);
295
295
 
296
296
  /**
297
297
  * Create an Uint8Array view of the next `len` bytes and advance the position by `len`.
@@ -305,7 +305,7 @@ const createDecoder$1 = uint8Array => new Decoder$1(uint8Array);
305
305
  * @param {number} len The length of bytes to read
306
306
  * @return {Uint8Array<Buf>}
307
307
  */
308
- const readUint8Array$2 = (decoder, len) => {
308
+ const readUint8Array = (decoder, len) => {
309
309
  const view = new Uint8Array(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len);
310
310
  decoder.pos += len;
311
311
  return view
@@ -322,7 +322,7 @@ const readUint8Array$2 = (decoder, len) => {
322
322
  * @param {Decoder<Buf>} decoder
323
323
  * @return {Uint8Array<Buf>}
324
324
  */
325
- const readVarUint8Array$2 = decoder => readUint8Array$2(decoder, readVarUint$2(decoder));
325
+ const readVarUint8Array = decoder => readUint8Array(decoder, readVarUint(decoder));
326
326
 
327
327
  /**
328
328
  * Read unsigned integer (32bit) with variable length.
@@ -334,3030 +334,226 @@ const readVarUint8Array$2 = decoder => readUint8Array$2(decoder, readVarUint$2(d
334
334
  * @param {Decoder} decoder
335
335
  * @return {number} An unsigned integer.length
336
336
  */
337
- const readVarUint$2 = decoder => {
337
+ const readVarUint = decoder => {
338
338
  let num = 0;
339
339
  let mult = 1;
340
340
  const len = decoder.arr.length;
341
341
  while (decoder.pos < len) {
342
342
  const r = decoder.arr[decoder.pos++];
343
343
  // num = num | ((r & binary.BITS7) << len)
344
- num = num + (r & BITS7$2) * mult; // shift $r << (7*#iterations) and add it to num
344
+ num = num + (r & BITS7) * mult; // shift $r << (7*#iterations) and add it to num
345
345
  mult *= 128; // next iteration, shift 7 "more" to the left
346
- if (r < BIT8$2) {
346
+ if (r < BIT8) {
347
347
  return num
348
348
  }
349
349
  /* c8 ignore start */
350
- if (num > MAX_SAFE_INTEGER$2) {
351
- throw errorIntegerOutOfRange$2
350
+ if (num > MAX_SAFE_INTEGER) {
351
+ throw errorIntegerOutOfRange
352
352
  }
353
353
  /* c8 ignore stop */
354
354
  }
355
- throw errorUnexpectedEndOfArray$2
355
+ throw errorUnexpectedEndOfArray
356
356
  };
357
357
 
358
358
  /**
359
359
  * BroadcastChannel sync provider for cross-tab synchronization
360
360
  * This is a lightweight alternative to y-webrtc for browser-tab-only sync
361
361
  */
362
- class BroadcastSyncProvider {
363
- type = 'local';
364
- doc;
365
- channel;
366
- _synced = false;
367
- constructor(docName, doc, _options) {
368
- this.doc = doc;
369
- this.channel = new BroadcastChannel(docName);
370
- // Handle incoming messages from other tabs
371
- this.channel.onmessage = (event) => {
372
- this.handleMessage(event.data);
373
- };
374
- // Listen to document updates and broadcast them
375
- this.doc.on('update', this.handleDocUpdate);
376
- // Send initial sync request
377
- this.broadcastSync();
378
- // Mark as synced after a short delay (to receive any pending updates)
379
- setTimeout(() => {
380
- this._synced = true;
381
- }, 100);
382
- if (!_options?.quiet) {
383
- console.info(`BroadcastChannel Provider initialized: ${docName}`);
384
- }
385
- }
386
- handleDocUpdate = (update, origin) => {
387
- // Don't broadcast updates that came from other tabs (to prevent loops)
388
- if (origin !== this) {
389
- const encoder = createEncoder$1();
390
- writeVarUint$2(encoder, 0); // Message type: sync update
391
- writeVarUint8Array$2(encoder, update);
392
- this.channel.postMessage(toUint8Array$1(encoder));
393
- }
394
- };
395
- handleMessage(message) {
396
- const decoder = createDecoder$1(new Uint8Array(message));
397
- const messageType = readVarUint$2(decoder);
398
- switch (messageType) {
399
- case 0: // Sync update
400
- const update = readVarUint8Array$2(decoder);
401
- Y__namespace.applyUpdate(this.doc, update, this);
402
- break;
403
- case 1: // Sync request
404
- this.broadcastSync();
405
- break;
406
- case 2: // Sync response
407
- const stateVector = readVarUint8Array$2(decoder);
408
- const updateResponse = Y__namespace.encodeStateAsUpdate(this.doc, stateVector);
409
- if (updateResponse.length > 0) {
410
- const encoder = createEncoder$1();
411
- writeVarUint$2(encoder, 0); // Send as regular update
412
- writeVarUint8Array$2(encoder, updateResponse);
413
- this.channel.postMessage(toUint8Array$1(encoder));
414
- }
415
- break;
416
- }
417
- }
418
- broadcastSync() {
419
- // Broadcast our current state vector to request missing updates
420
- const encoder = createEncoder$1();
421
- writeVarUint$2(encoder, 2); // Message type: sync response
422
- writeVarUint8Array$2(encoder, Y__namespace.encodeStateVector(this.doc));
423
- this.channel.postMessage(toUint8Array$1(encoder));
424
- }
425
- async connect() {
426
- // Wait for initial sync to complete
427
- if (this._synced) {
428
- return;
429
- }
430
- return new Promise((resolve) => {
431
- const checkSync = () => {
432
- if (this._synced) {
433
- resolve();
434
- }
435
- else {
436
- setTimeout(checkSync, 50);
437
- }
438
- };
439
- checkSync();
440
- });
441
- }
442
- disconnect() {
443
- // BroadcastChannel doesn't have explicit disconnect
444
- }
445
- async reconnect() {
446
- this.disconnect();
447
- return this.connect();
448
- }
449
- destroy() {
450
- this.doc.off('update', this.handleDocUpdate);
451
- this.channel.close();
452
- }
453
- }
454
-
455
- /**
456
- * WebSocket sync provider for real-time collaboration
457
- */
458
- class WebSocketSyncProvider {
459
- type = 'network';
460
- provider;
461
- isConnected = false;
462
- _quiet = false;
463
- get awareness() {
464
- return this.provider.awareness;
465
- }
466
- constructor(docName, doc, options) {
467
- const url = options?.url || 'ws://localhost:1234';
468
- const roomName = options?.roomName || docName;
469
- this.provider = new yWebsocket.WebsocketProvider(url, roomName, doc, {
470
- params: options?.params,
471
- protocols: options?.protocols,
472
- WebSocketPolyfill: options?.WebSocketPolyfill,
473
- awareness: options?.awareness,
474
- maxBackoffTime: options?.maxBackoffTime,
475
- disableBc: true,
476
- });
477
- this._quiet = options?.quiet ?? false;
478
- this.setupEventListeners();
479
- if (!this._quiet) {
480
- console.info(`WebSocket Provider initialized: ${url}/${roomName}`);
481
- }
482
- }
483
- /**
484
- * Static factory method for creating WebSocketSyncProvider with configuration options
485
- * Returns a ProviderFactory that can be used in sync configuration
486
- */
487
- static with(options) {
488
- return {
489
- create: (docName, doc, runtimeOptions) => {
490
- const mergedOptions = runtimeOptions ? { ...options, ...runtimeOptions } : options;
491
- return new WebSocketSyncProvider(docName, doc, mergedOptions);
492
- },
493
- };
494
- }
495
- setupEventListeners() {
496
- this.provider.on('status', ({ status }) => {
497
- if (status === 'connected') {
498
- this.isConnected = true;
499
- if (!this._quiet) {
500
- console.info('WebSocket connected');
501
- }
502
- }
503
- else if (status === 'disconnected') {
504
- this.isConnected = false;
505
- if (!this._quiet) {
506
- console.info('WebSocket disconnected');
507
- }
508
- }
509
- });
510
- this.provider.on('sync', (synced) => {
511
- if (synced && !this._quiet) {
512
- console.info('WebSocket synced');
513
- }
514
- });
515
- }
516
- async connect() {
517
- if (this.isConnected) {
518
- return;
519
- }
520
- return new Promise((resolve, reject) => {
521
- const timeout = setTimeout(() => {
522
- reject(new Error('WebSocket connection timeout'));
523
- }, 10000); // 10 second timeout
524
- const statusHandler = ({ status }) => {
525
- if (status === 'connected') {
526
- clearTimeout(timeout);
527
- this.provider.off('status', statusHandler);
528
- this.isConnected = true;
529
- resolve();
530
- }
531
- };
532
- this.provider.on('status', statusHandler);
533
- // If already connected, resolve immediately
534
- if (this.provider.wsconnected) {
535
- clearTimeout(timeout);
536
- this.provider.off('status', statusHandler);
537
- this.isConnected = true;
538
- resolve();
539
- }
540
- });
541
- }
542
- disconnect() {
543
- if (this.provider) {
544
- this.provider.disconnect();
545
- }
546
- this.isConnected = false;
547
- }
548
- async reconnect() {
549
- this.disconnect();
550
- return this.connect();
551
- }
552
- destroy() {
553
- if (this.provider) {
554
- this.provider.destroy();
555
- }
556
- this.isConnected = false;
557
- }
558
- }
559
-
560
- /**
561
- * Common Math expressions.
562
- *
563
- * @module math
564
- */
565
-
566
- const floor$1 = Math.floor;
567
-
568
- /**
569
- * @function
570
- * @param {number} a
571
- * @param {number} b
572
- * @return {number} The smaller element of a and b
573
- */
574
- const min$1 = (a, b) => a < b ? a : b;
575
-
576
- /**
577
- * @function
578
- * @param {number} a
579
- * @param {number} b
580
- * @return {number} The bigger element of a and b
581
- */
582
- const max$1 = (a, b) => a > b ? a : b;
583
-
584
- /* eslint-env browser */
585
-
586
- const BIT8$1 = 128;
587
- const BITS7$1 = 127;
588
-
589
- /**
590
- * Utility helpers for working with numbers.
591
- *
592
- * @module number
593
- */
594
-
595
-
596
- const MAX_SAFE_INTEGER$1 = Number.MAX_SAFE_INTEGER;
597
-
598
- /**
599
- * @param {string} str
600
- * @return {Uint8Array}
601
- */
602
- const _encodeUtf8Polyfill$1 = str => {
603
- const encodedString = unescape(encodeURIComponent(str));
604
- const len = encodedString.length;
605
- const buf = new Uint8Array(len);
606
- for (let i = 0; i < len; i++) {
607
- buf[i] = /** @type {number} */ (encodedString.codePointAt(i));
608
- }
609
- return buf
610
- };
611
-
612
- /* c8 ignore next */
613
- const utf8TextEncoder$1 = /** @type {TextEncoder} */ (typeof TextEncoder !== 'undefined' ? new TextEncoder() : null);
614
-
615
- /**
616
- * @param {string} str
617
- * @return {Uint8Array}
618
- */
619
- const _encodeUtf8Native$1 = str => utf8TextEncoder$1.encode(str);
620
-
621
- /**
622
- * @param {string} str
623
- * @return {Uint8Array}
624
- */
625
- /* c8 ignore next */
626
- const encodeUtf8$1 = utf8TextEncoder$1 ? _encodeUtf8Native$1 : _encodeUtf8Polyfill$1;
627
-
628
- /* c8 ignore next */
629
- let utf8TextDecoder$1 = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });
630
-
631
- /* c8 ignore start */
632
- if (utf8TextDecoder$1 && utf8TextDecoder$1.decode(new Uint8Array()).length === 1) {
633
- // Safari doesn't handle BOM correctly.
634
- // This fixes a bug in Safari 13.0.5 where it produces a BOM the first time it is called.
635
- // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the first call and
636
- // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the second call
637
- // Another issue is that from then on no BOM chars are recognized anymore
638
- /* c8 ignore next */
639
- utf8TextDecoder$1 = null;
640
- }
641
-
642
- /**
643
- * Efficient schema-less binary encoding with support for variable length encoding.
644
- *
645
- * Use [lib0/encoding] with [lib0/decoding]. Every encoding function has a corresponding decoding function.
646
- *
647
- * Encodes numbers in little-endian order (least to most significant byte order)
648
- * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
649
- * which is also used in Protocol Buffers.
650
- *
651
- * ```js
652
- * // encoding step
653
- * const encoder = encoding.createEncoder()
654
- * encoding.writeVarUint(encoder, 256)
655
- * encoding.writeVarString(encoder, 'Hello world!')
656
- * const buf = encoding.toUint8Array(encoder)
657
- * ```
658
- *
659
- * ```js
660
- * // decoding step
661
- * const decoder = decoding.createDecoder(buf)
662
- * decoding.readVarUint(decoder) // => 256
663
- * decoding.readVarString(decoder) // => 'Hello world!'
664
- * decoding.hasContent(decoder) // => false - all data is read
665
- * ```
666
- *
667
- * @module encoding
668
- */
669
-
670
-
671
- /**
672
- * Write one byte to the encoder.
673
- *
674
- * @function
675
- * @param {Encoder} encoder
676
- * @param {number} num The byte that is to be encoded.
677
- */
678
- const write$1 = (encoder, num) => {
679
- const bufferLen = encoder.cbuf.length;
680
- if (encoder.cpos === bufferLen) {
681
- encoder.bufs.push(encoder.cbuf);
682
- encoder.cbuf = new Uint8Array(bufferLen * 2);
683
- encoder.cpos = 0;
684
- }
685
- encoder.cbuf[encoder.cpos++] = num;
686
- };
687
-
688
- /**
689
- * Write a variable length unsigned integer. Max encodable integer is 2^53.
690
- *
691
- * @function
692
- * @param {Encoder} encoder
693
- * @param {number} num The number that is to be encoded.
694
- */
695
- const writeVarUint$1 = (encoder, num) => {
696
- while (num > BITS7$1) {
697
- write$1(encoder, BIT8$1 | (BITS7$1 & num));
698
- num = floor$1(num / 128); // shift >>> 7
699
- }
700
- write$1(encoder, BITS7$1 & num);
701
- };
702
-
703
- /**
704
- * A cache to store strings temporarily
705
- */
706
- const _strBuffer$1 = new Uint8Array(30000);
707
- const _maxStrBSize$1 = _strBuffer$1.length / 3;
708
-
709
- /**
710
- * Write a variable length string.
711
- *
712
- * @function
713
- * @param {Encoder} encoder
714
- * @param {String} str The string that is to be encoded.
715
- */
716
- const _writeVarStringNative$1 = (encoder, str) => {
717
- if (str.length < _maxStrBSize$1) {
718
- // We can encode the string into the existing buffer
719
- /* c8 ignore next */
720
- const written = utf8TextEncoder$1.encodeInto(str, _strBuffer$1).written || 0;
721
- writeVarUint$1(encoder, written);
722
- for (let i = 0; i < written; i++) {
723
- write$1(encoder, _strBuffer$1[i]);
724
- }
725
- } else {
726
- writeVarUint8Array$1(encoder, encodeUtf8$1(str));
727
- }
728
- };
729
-
730
- /**
731
- * Write a variable length string.
732
- *
733
- * @function
734
- * @param {Encoder} encoder
735
- * @param {String} str The string that is to be encoded.
736
- */
737
- const _writeVarStringPolyfill$1 = (encoder, str) => {
738
- const encodedString = unescape(encodeURIComponent(str));
739
- const len = encodedString.length;
740
- writeVarUint$1(encoder, len);
741
- for (let i = 0; i < len; i++) {
742
- write$1(encoder, /** @type {number} */ (encodedString.codePointAt(i)));
743
- }
744
- };
745
-
746
- /**
747
- * Write a variable length string.
748
- *
749
- * @function
750
- * @param {Encoder} encoder
751
- * @param {String} str The string that is to be encoded.
752
- */
753
- /* c8 ignore next */
754
- const writeVarString$1 = (utf8TextEncoder$1 && /** @type {any} */ (utf8TextEncoder$1).encodeInto) ? _writeVarStringNative$1 : _writeVarStringPolyfill$1;
755
-
756
- /**
757
- * Append fixed-length Uint8Array to the encoder.
758
- *
759
- * @function
760
- * @param {Encoder} encoder
761
- * @param {Uint8Array} uint8Array
762
- */
763
- const writeUint8Array$1 = (encoder, uint8Array) => {
764
- const bufferLen = encoder.cbuf.length;
765
- const cpos = encoder.cpos;
766
- const leftCopyLen = min$1(bufferLen - cpos, uint8Array.length);
767
- const rightCopyLen = uint8Array.length - leftCopyLen;
768
- encoder.cbuf.set(uint8Array.subarray(0, leftCopyLen), cpos);
769
- encoder.cpos += leftCopyLen;
770
- if (rightCopyLen > 0) {
771
- // Still something to write, write right half..
772
- // Append new buffer
773
- encoder.bufs.push(encoder.cbuf);
774
- // must have at least size of remaining buffer
775
- encoder.cbuf = new Uint8Array(max$1(bufferLen * 2, rightCopyLen));
776
- // copy array
777
- encoder.cbuf.set(uint8Array.subarray(leftCopyLen));
778
- encoder.cpos = rightCopyLen;
779
- }
780
- };
781
-
782
- /**
783
- * Append an Uint8Array to Encoder.
784
- *
785
- * @function
786
- * @param {Encoder} encoder
787
- * @param {Uint8Array} uint8Array
788
- */
789
- const writeVarUint8Array$1 = (encoder, uint8Array) => {
790
- writeVarUint$1(encoder, uint8Array.byteLength);
791
- writeUint8Array$1(encoder, uint8Array);
792
- };
793
-
794
- /**
795
- * Error helpers.
796
- *
797
- * @module error
798
- */
799
-
800
- /**
801
- * @param {string} s
802
- * @return {Error}
803
- */
804
- /* c8 ignore next */
805
- const create$3 = s => new Error(s);
806
-
807
- /**
808
- * Efficient schema-less binary decoding with support for variable length encoding.
809
- *
810
- * Use [lib0/decoding] with [lib0/encoding]. Every encoding function has a corresponding decoding function.
811
- *
812
- * Encodes numbers in little-endian order (least to most significant byte order)
813
- * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
814
- * which is also used in Protocol Buffers.
815
- *
816
- * ```js
817
- * // encoding step
818
- * const encoder = encoding.createEncoder()
819
- * encoding.writeVarUint(encoder, 256)
820
- * encoding.writeVarString(encoder, 'Hello world!')
821
- * const buf = encoding.toUint8Array(encoder)
822
- * ```
823
- *
824
- * ```js
825
- * // decoding step
826
- * const decoder = decoding.createDecoder(buf)
827
- * decoding.readVarUint(decoder) // => 256
828
- * decoding.readVarString(decoder) // => 'Hello world!'
829
- * decoding.hasContent(decoder) // => false - all data is read
830
- * ```
831
- *
832
- * @module decoding
833
- */
834
-
835
-
836
- const errorUnexpectedEndOfArray$1 = create$3('Unexpected end of array');
837
- const errorIntegerOutOfRange$1 = create$3('Integer out of Range');
838
-
839
- /**
840
- * Create an Uint8Array view of the next `len` bytes and advance the position by `len`.
841
- *
842
- * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
843
- * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
844
- *
845
- * @function
846
- * @param {Decoder} decoder The decoder instance
847
- * @param {number} len The length of bytes to read
848
- * @return {Uint8Array}
849
- */
850
- const readUint8Array$1 = (decoder, len) => {
851
- const view = new Uint8Array(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len);
852
- decoder.pos += len;
853
- return view
854
- };
855
-
856
- /**
857
- * Read variable length Uint8Array.
858
- *
859
- * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
860
- * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
861
- *
862
- * @function
863
- * @param {Decoder} decoder
864
- * @return {Uint8Array}
865
- */
866
- const readVarUint8Array$1 = decoder => readUint8Array$1(decoder, readVarUint$1(decoder));
867
-
868
- /**
869
- * Read one byte as unsigned integer.
870
- * @function
871
- * @param {Decoder} decoder The decoder instance
872
- * @return {number} Unsigned 8-bit integer
873
- */
874
- const readUint8$1 = decoder => decoder.arr[decoder.pos++];
875
-
876
- /**
877
- * Read unsigned integer (32bit) with variable length.
878
- * 1/8th of the storage is used as encoding overhead.
879
- * * numbers < 2^7 is stored in one bytlength
880
- * * numbers < 2^14 is stored in two bylength
881
- *
882
- * @function
883
- * @param {Decoder} decoder
884
- * @return {number} An unsigned integer.length
885
- */
886
- const readVarUint$1 = decoder => {
887
- let num = 0;
888
- let mult = 1;
889
- const len = decoder.arr.length;
890
- while (decoder.pos < len) {
891
- const r = decoder.arr[decoder.pos++];
892
- // num = num | ((r & binary.BITS7) << len)
893
- num = num + (r & BITS7$1) * mult; // shift $r << (7*#iterations) and add it to num
894
- mult *= 128; // next iteration, shift 7 "more" to the left
895
- if (r < BIT8$1) {
896
- return num
897
- }
898
- /* c8 ignore start */
899
- if (num > MAX_SAFE_INTEGER$1) {
900
- throw errorIntegerOutOfRange$1
901
- }
902
- /* c8 ignore stop */
903
- }
904
- throw errorUnexpectedEndOfArray$1
905
- };
906
-
907
- /**
908
- * We don't test this function anymore as we use native decoding/encoding by default now.
909
- * Better not modify this anymore..
910
- *
911
- * Transforming utf8 to a string is pretty expensive. The code performs 10x better
912
- * when String.fromCodePoint is fed with all characters as arguments.
913
- * But most environments have a maximum number of arguments per functions.
914
- * For effiency reasons we apply a maximum of 10000 characters at once.
915
- *
916
- * @function
917
- * @param {Decoder} decoder
918
- * @return {String} The read String.
919
- */
920
- /* c8 ignore start */
921
- const _readVarStringPolyfill$1 = decoder => {
922
- let remainingLen = readVarUint$1(decoder);
923
- if (remainingLen === 0) {
924
- return ''
925
- } else {
926
- let encodedString = String.fromCodePoint(readUint8$1(decoder)); // remember to decrease remainingLen
927
- if (--remainingLen < 100) { // do not create a Uint8Array for small strings
928
- while (remainingLen--) {
929
- encodedString += String.fromCodePoint(readUint8$1(decoder));
930
- }
931
- } else {
932
- while (remainingLen > 0) {
933
- const nextLen = remainingLen < 10000 ? remainingLen : 10000;
934
- // this is dangerous, we create a fresh array view from the existing buffer
935
- const bytes = decoder.arr.subarray(decoder.pos, decoder.pos + nextLen);
936
- decoder.pos += nextLen;
937
- // Starting with ES5.1 we can supply a generic array-like object as arguments
938
- encodedString += String.fromCodePoint.apply(null, /** @type {any} */ (bytes));
939
- remainingLen -= nextLen;
940
- }
941
- }
942
- return decodeURIComponent(escape(encodedString))
943
- }
944
- };
945
- /* c8 ignore stop */
946
-
947
- /**
948
- * @function
949
- * @param {Decoder} decoder
950
- * @return {String} The read String
951
- */
952
- const _readVarStringNative$1 = decoder =>
953
- /** @type any */ (utf8TextDecoder$1).decode(readVarUint8Array$1(decoder));
954
-
955
- /**
956
- * Read string of variable length
957
- * * varUint is used to store the length of the string
958
- *
959
- * @function
960
- * @param {Decoder} decoder
961
- * @return {String} The read String
962
- *
963
- */
964
- /* c8 ignore next */
965
- const readVarString$1 = utf8TextDecoder$1 ? _readVarStringNative$1 : _readVarStringPolyfill$1;
966
-
967
- var AuthMessageType;
968
- (function (AuthMessageType) {
969
- AuthMessageType[AuthMessageType["Token"] = 0] = "Token";
970
- AuthMessageType[AuthMessageType["PermissionDenied"] = 1] = "PermissionDenied";
971
- AuthMessageType[AuthMessageType["Authenticated"] = 2] = "Authenticated";
972
- })(AuthMessageType || (AuthMessageType = {}));
973
- const writeAuthentication = (encoder, auth) => {
974
- writeVarUint$1(encoder, AuthMessageType.Token);
975
- writeVarString$1(encoder, auth);
976
- };
977
- const readAuthMessage = (decoder, sendToken, permissionDeniedHandler, authenticatedHandler) => {
978
- switch (readVarUint$1(decoder)) {
979
- case AuthMessageType.Token: {
980
- sendToken();
981
- break;
982
- }
983
- case AuthMessageType.PermissionDenied: {
984
- permissionDeniedHandler(readVarString$1(decoder));
985
- break;
986
- }
987
- case AuthMessageType.Authenticated: {
988
- authenticatedHandler(readVarString$1(decoder));
989
- break;
990
- }
991
- }
992
- };
993
-
994
- const awarenessStatesToArray = (states) => {
995
- return Array.from(states.entries()).map(([key, value]) => {
996
- return {
997
- clientId: key,
998
- ...value,
999
- };
1000
- });
1001
- };
1002
-
1003
- /**
1004
- * State of the WebSocket connection.
1005
- * https://developer.mozilla.org/de/docs/Web/API/WebSocket/readyState
1006
- */
1007
- var WsReadyStates;
1008
- (function (WsReadyStates) {
1009
- WsReadyStates[WsReadyStates["Connecting"] = 0] = "Connecting";
1010
- WsReadyStates[WsReadyStates["Open"] = 1] = "Open";
1011
- WsReadyStates[WsReadyStates["Closing"] = 2] = "Closing";
1012
- WsReadyStates[WsReadyStates["Closed"] = 3] = "Closed";
1013
- })(WsReadyStates || (WsReadyStates = {}));
1014
-
1015
- function applyDefaults(options) {
1016
- if (!options) {
1017
- options = {};
1018
- }
1019
- return {
1020
- delay: (options.delay === undefined) ? 200 : options.delay,
1021
- initialDelay: (options.initialDelay === undefined) ? 0 : options.initialDelay,
1022
- minDelay: (options.minDelay === undefined) ? 0 : options.minDelay,
1023
- maxDelay: (options.maxDelay === undefined) ? 0 : options.maxDelay,
1024
- factor: (options.factor === undefined) ? 0 : options.factor,
1025
- maxAttempts: (options.maxAttempts === undefined) ? 3 : options.maxAttempts,
1026
- timeout: (options.timeout === undefined) ? 0 : options.timeout,
1027
- jitter: (options.jitter === true),
1028
- initialJitter: (options.initialJitter === true),
1029
- handleError: (options.handleError === undefined) ? null : options.handleError,
1030
- handleTimeout: (options.handleTimeout === undefined) ? null : options.handleTimeout,
1031
- beforeAttempt: (options.beforeAttempt === undefined) ? null : options.beforeAttempt,
1032
- calculateDelay: (options.calculateDelay === undefined) ? null : options.calculateDelay
1033
- };
1034
- }
1035
- async function sleep(delay) {
1036
- return new Promise((resolve) => setTimeout(resolve, delay));
1037
- }
1038
- function defaultCalculateDelay(context, options) {
1039
- let delay = options.delay;
1040
- if (delay === 0) {
1041
- // no delay between attempts
1042
- return 0;
1043
- }
1044
- if (options.factor) {
1045
- delay *= Math.pow(options.factor, context.attemptNum - 1);
1046
- if (options.maxDelay !== 0) {
1047
- delay = Math.min(delay, options.maxDelay);
1048
- }
1049
- }
1050
- if (options.jitter) {
1051
- // Jitter will result in a random value between `minDelay` and
1052
- // calculated delay for a given attempt.
1053
- // See https://www.awsarchitectureblog.com/2015/03/backoff.html
1054
- // We're using the "full jitter" strategy.
1055
- const min = Math.ceil(options.minDelay);
1056
- const max = Math.floor(delay);
1057
- delay = Math.floor(Math.random() * (max - min + 1)) + min;
1058
- }
1059
- return Math.round(delay);
1060
- }
1061
- async function retry(attemptFunc, attemptOptions) {
1062
- const options = applyDefaults(attemptOptions);
1063
- for (const prop of [
1064
- 'delay',
1065
- 'initialDelay',
1066
- 'minDelay',
1067
- 'maxDelay',
1068
- 'maxAttempts',
1069
- 'timeout'
1070
- ]) {
1071
- const value = options[prop];
1072
- if (!Number.isInteger(value) || (value < 0)) {
1073
- throw new Error(`Value for ${prop} must be an integer greater than or equal to 0`);
1074
- }
1075
- }
1076
- if ((options.factor.constructor !== Number) || (options.factor < 0)) {
1077
- throw new Error(`Value for factor must be a number greater than or equal to 0`);
1078
- }
1079
- if (options.delay < options.minDelay) {
1080
- throw new Error(`delay cannot be less than minDelay (delay: ${options.delay}, minDelay: ${options.minDelay}`);
1081
- }
1082
- const context = {
1083
- attemptNum: 0,
1084
- attemptsRemaining: options.maxAttempts ? options.maxAttempts : -1,
1085
- aborted: false,
1086
- abort() {
1087
- context.aborted = true;
1088
- }
1089
- };
1090
- const calculateDelay = options.calculateDelay || defaultCalculateDelay;
1091
- async function makeAttempt() {
1092
- if (options.beforeAttempt) {
1093
- options.beforeAttempt(context, options);
1094
- }
1095
- if (context.aborted) {
1096
- const err = new Error(`Attempt aborted`);
1097
- err.code = 'ATTEMPT_ABORTED';
1098
- throw err;
1099
- }
1100
- const onError = async (err) => {
1101
- if (options.handleError) {
1102
- await options.handleError(err, context, options);
1103
- }
1104
- if (context.aborted || (context.attemptsRemaining === 0)) {
1105
- throw err;
1106
- }
1107
- // We are about to try again so increment attempt number
1108
- context.attemptNum++;
1109
- const delay = calculateDelay(context, options);
1110
- if (delay) {
1111
- await sleep(delay);
1112
- }
1113
- return makeAttempt();
1114
- };
1115
- if (context.attemptsRemaining > 0) {
1116
- context.attemptsRemaining--;
1117
- }
1118
- if (options.timeout) {
1119
- return new Promise((resolve, reject) => {
1120
- const timer = setTimeout(() => {
1121
- if (options.handleTimeout) {
1122
- // If calling handleTimeout throws an error that is not wrapped in a promise
1123
- // we want to catch the error and reject.
1124
- try {
1125
- resolve(options.handleTimeout(context, options));
1126
- }
1127
- catch (e) {
1128
- reject(e);
1129
- }
1130
- }
1131
- else {
1132
- const err = new Error(`Retry timeout (attemptNum: ${context.attemptNum}, timeout: ${options.timeout})`);
1133
- err.code = 'ATTEMPT_TIMEOUT';
1134
- reject(err);
1135
- }
1136
- }, options.timeout);
1137
- attemptFunc(context, options).then((result) => {
1138
- clearTimeout(timer);
1139
- resolve(result);
1140
- }).catch((err) => {
1141
- clearTimeout(timer);
1142
- // Calling resolve with a Promise that rejects here will result
1143
- // in an unhandled rejection. Calling `reject` with errors
1144
- // does not result in an unhandled rejection
1145
- onError(err).then(resolve).catch(reject);
1146
- });
1147
- });
1148
- }
1149
- else {
1150
- // No timeout provided so wait indefinitely for the returned promise
1151
- // to be resolved.
1152
- return attemptFunc(context, options).catch(onError);
1153
- }
1154
- }
1155
- const initialDelay = options.calculateDelay
1156
- ? options.calculateDelay(context, options)
1157
- : options.initialDelay;
1158
- if (initialDelay) {
1159
- await sleep(initialDelay);
1160
- }
1161
- if (context.attemptNum < 1 && options.initialJitter) {
1162
- const delay = calculateDelay(context, options);
1163
- if (delay) {
1164
- await sleep(delay);
1165
- }
1166
- }
1167
- return makeAttempt();
1168
- }
1169
-
1170
- /**
1171
- * Common Math expressions.
1172
- *
1173
- * @module math
1174
- */
1175
-
1176
- const floor = Math.floor;
1177
-
1178
- /**
1179
- * @function
1180
- * @param {number} a
1181
- * @param {number} b
1182
- * @return {number} The smaller element of a and b
1183
- */
1184
- const min = (a, b) => a < b ? a : b;
1185
-
1186
- /**
1187
- * @function
1188
- * @param {number} a
1189
- * @param {number} b
1190
- * @return {number} The bigger element of a and b
1191
- */
1192
- const max = (a, b) => a > b ? a : b;
1193
-
1194
- /* eslint-env browser */
1195
-
1196
- const BIT7 = 64;
1197
- const BIT8 = 128;
1198
- const BITS6 = 63;
1199
- const BITS7 = 127;
1200
-
1201
- /**
1202
- * Utility helpers for working with numbers.
1203
- *
1204
- * @module number
1205
- */
1206
-
1207
-
1208
- const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER;
1209
-
1210
- /**
1211
- * Utility module to work with sets.
1212
- *
1213
- * @module set
1214
- */
1215
-
1216
- const create$2 = () => new Set();
1217
-
1218
- /**
1219
- * Utility module to work with Arrays.
1220
- *
1221
- * @module array
1222
- */
1223
-
1224
-
1225
- /**
1226
- * Transforms something array-like to an actual Array.
1227
- *
1228
- * @function
1229
- * @template T
1230
- * @param {ArrayLike<T>|Iterable<T>} arraylike
1231
- * @return {T}
1232
- */
1233
- const from = Array.from;
1234
-
1235
- /**
1236
- * @param {string} str
1237
- * @return {Uint8Array}
1238
- */
1239
- const _encodeUtf8Polyfill = str => {
1240
- const encodedString = unescape(encodeURIComponent(str));
1241
- const len = encodedString.length;
1242
- const buf = new Uint8Array(len);
1243
- for (let i = 0; i < len; i++) {
1244
- buf[i] = /** @type {number} */ (encodedString.codePointAt(i));
1245
- }
1246
- return buf
1247
- };
1248
-
1249
- /* c8 ignore next */
1250
- const utf8TextEncoder = /** @type {TextEncoder} */ (typeof TextEncoder !== 'undefined' ? new TextEncoder() : null);
1251
-
1252
- /**
1253
- * @param {string} str
1254
- * @return {Uint8Array}
1255
- */
1256
- const _encodeUtf8Native = str => utf8TextEncoder.encode(str);
1257
-
1258
- /**
1259
- * @param {string} str
1260
- * @return {Uint8Array}
1261
- */
1262
- /* c8 ignore next */
1263
- const encodeUtf8 = utf8TextEncoder ? _encodeUtf8Native : _encodeUtf8Polyfill;
1264
-
1265
- /* c8 ignore next */
1266
- let utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });
1267
-
1268
- /* c8 ignore start */
1269
- if (utf8TextDecoder && utf8TextDecoder.decode(new Uint8Array()).length === 1) {
1270
- // Safari doesn't handle BOM correctly.
1271
- // This fixes a bug in Safari 13.0.5 where it produces a BOM the first time it is called.
1272
- // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the first call and
1273
- // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the second call
1274
- // Another issue is that from then on no BOM chars are recognized anymore
1275
- /* c8 ignore next */
1276
- utf8TextDecoder = null;
1277
- }
1278
-
1279
- /**
1280
- * Efficient schema-less binary encoding with support for variable length encoding.
1281
- *
1282
- * Use [lib0/encoding] with [lib0/decoding]. Every encoding function has a corresponding decoding function.
1283
- *
1284
- * Encodes numbers in little-endian order (least to most significant byte order)
1285
- * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
1286
- * which is also used in Protocol Buffers.
1287
- *
1288
- * ```js
1289
- * // encoding step
1290
- * const encoder = encoding.createEncoder()
1291
- * encoding.writeVarUint(encoder, 256)
1292
- * encoding.writeVarString(encoder, 'Hello world!')
1293
- * const buf = encoding.toUint8Array(encoder)
1294
- * ```
1295
- *
1296
- * ```js
1297
- * // decoding step
1298
- * const decoder = decoding.createDecoder(buf)
1299
- * decoding.readVarUint(decoder) // => 256
1300
- * decoding.readVarString(decoder) // => 'Hello world!'
1301
- * decoding.hasContent(decoder) // => false - all data is read
1302
- * ```
1303
- *
1304
- * @module encoding
1305
- */
1306
-
1307
-
1308
- /**
1309
- * A BinaryEncoder handles the encoding to an Uint8Array.
1310
- */
1311
- class Encoder {
1312
- constructor () {
1313
- this.cpos = 0;
1314
- this.cbuf = new Uint8Array(100);
1315
- /**
1316
- * @type {Array<Uint8Array>}
1317
- */
1318
- this.bufs = [];
1319
- }
1320
- }
1321
-
1322
- /**
1323
- * @function
1324
- * @return {Encoder}
1325
- */
1326
- const createEncoder = () => new Encoder();
1327
-
1328
- /**
1329
- * The current length of the encoded data.
1330
- *
1331
- * @function
1332
- * @param {Encoder} encoder
1333
- * @return {number}
1334
- */
1335
- const length$1 = encoder => {
1336
- let len = encoder.cpos;
1337
- for (let i = 0; i < encoder.bufs.length; i++) {
1338
- len += encoder.bufs[i].length;
1339
- }
1340
- return len
1341
- };
1342
-
1343
- /**
1344
- * Transform to Uint8Array.
1345
- *
1346
- * @function
1347
- * @param {Encoder} encoder
1348
- * @return {Uint8Array} The created ArrayBuffer.
1349
- */
1350
- const toUint8Array = encoder => {
1351
- const uint8arr = new Uint8Array(length$1(encoder));
1352
- let curPos = 0;
1353
- for (let i = 0; i < encoder.bufs.length; i++) {
1354
- const d = encoder.bufs[i];
1355
- uint8arr.set(d, curPos);
1356
- curPos += d.length;
1357
- }
1358
- uint8arr.set(new Uint8Array(encoder.cbuf.buffer, 0, encoder.cpos), curPos);
1359
- return uint8arr
1360
- };
1361
-
1362
- /**
1363
- * Write one byte to the encoder.
1364
- *
1365
- * @function
1366
- * @param {Encoder} encoder
1367
- * @param {number} num The byte that is to be encoded.
1368
- */
1369
- const write = (encoder, num) => {
1370
- const bufferLen = encoder.cbuf.length;
1371
- if (encoder.cpos === bufferLen) {
1372
- encoder.bufs.push(encoder.cbuf);
1373
- encoder.cbuf = new Uint8Array(bufferLen * 2);
1374
- encoder.cpos = 0;
1375
- }
1376
- encoder.cbuf[encoder.cpos++] = num;
1377
- };
1378
-
1379
- /**
1380
- * Write a variable length unsigned integer. Max encodable integer is 2^53.
1381
- *
1382
- * @function
1383
- * @param {Encoder} encoder
1384
- * @param {number} num The number that is to be encoded.
1385
- */
1386
- const writeVarUint = (encoder, num) => {
1387
- while (num > BITS7) {
1388
- write(encoder, BIT8 | (BITS7 & num));
1389
- num = floor(num / 128); // shift >>> 7
1390
- }
1391
- write(encoder, BITS7 & num);
1392
- };
1393
-
1394
- /**
1395
- * A cache to store strings temporarily
1396
- */
1397
- const _strBuffer = new Uint8Array(30000);
1398
- const _maxStrBSize = _strBuffer.length / 3;
1399
-
1400
- /**
1401
- * Write a variable length string.
1402
- *
1403
- * @function
1404
- * @param {Encoder} encoder
1405
- * @param {String} str The string that is to be encoded.
1406
- */
1407
- const _writeVarStringNative = (encoder, str) => {
1408
- if (str.length < _maxStrBSize) {
1409
- // We can encode the string into the existing buffer
1410
- /* c8 ignore next */
1411
- const written = utf8TextEncoder.encodeInto(str, _strBuffer).written || 0;
1412
- writeVarUint(encoder, written);
1413
- for (let i = 0; i < written; i++) {
1414
- write(encoder, _strBuffer[i]);
1415
- }
1416
- } else {
1417
- writeVarUint8Array(encoder, encodeUtf8(str));
1418
- }
1419
- };
1420
-
1421
- /**
1422
- * Write a variable length string.
1423
- *
1424
- * @function
1425
- * @param {Encoder} encoder
1426
- * @param {String} str The string that is to be encoded.
1427
- */
1428
- const _writeVarStringPolyfill = (encoder, str) => {
1429
- const encodedString = unescape(encodeURIComponent(str));
1430
- const len = encodedString.length;
1431
- writeVarUint(encoder, len);
1432
- for (let i = 0; i < len; i++) {
1433
- write(encoder, /** @type {number} */ (encodedString.codePointAt(i)));
1434
- }
1435
- };
1436
-
1437
- /**
1438
- * Write a variable length string.
1439
- *
1440
- * @function
1441
- * @param {Encoder} encoder
1442
- * @param {String} str The string that is to be encoded.
1443
- */
1444
- /* c8 ignore next */
1445
- const writeVarString = (utf8TextEncoder && /** @type {any} */ (utf8TextEncoder).encodeInto) ? _writeVarStringNative : _writeVarStringPolyfill;
1446
-
1447
- /**
1448
- * Append fixed-length Uint8Array to the encoder.
1449
- *
1450
- * @function
1451
- * @param {Encoder} encoder
1452
- * @param {Uint8Array} uint8Array
1453
- */
1454
- const writeUint8Array = (encoder, uint8Array) => {
1455
- const bufferLen = encoder.cbuf.length;
1456
- const cpos = encoder.cpos;
1457
- const leftCopyLen = min(bufferLen - cpos, uint8Array.length);
1458
- const rightCopyLen = uint8Array.length - leftCopyLen;
1459
- encoder.cbuf.set(uint8Array.subarray(0, leftCopyLen), cpos);
1460
- encoder.cpos += leftCopyLen;
1461
- if (rightCopyLen > 0) {
1462
- // Still something to write, write right half..
1463
- // Append new buffer
1464
- encoder.bufs.push(encoder.cbuf);
1465
- // must have at least size of remaining buffer
1466
- encoder.cbuf = new Uint8Array(max(bufferLen * 2, rightCopyLen));
1467
- // copy array
1468
- encoder.cbuf.set(uint8Array.subarray(leftCopyLen));
1469
- encoder.cpos = rightCopyLen;
1470
- }
1471
- };
1472
-
1473
- /**
1474
- * Append an Uint8Array to Encoder.
1475
- *
1476
- * @function
1477
- * @param {Encoder} encoder
1478
- * @param {Uint8Array} uint8Array
1479
- */
1480
- const writeVarUint8Array = (encoder, uint8Array) => {
1481
- writeVarUint(encoder, uint8Array.byteLength);
1482
- writeUint8Array(encoder, uint8Array);
1483
- };
1484
-
1485
- /**
1486
- * Error helpers.
1487
- *
1488
- * @module error
1489
- */
1490
-
1491
- /**
1492
- * @param {string} s
1493
- * @return {Error}
1494
- */
1495
- /* c8 ignore next */
1496
- const create$1 = s => new Error(s);
1497
-
1498
- /**
1499
- * Efficient schema-less binary decoding with support for variable length encoding.
1500
- *
1501
- * Use [lib0/decoding] with [lib0/encoding]. Every encoding function has a corresponding decoding function.
1502
- *
1503
- * Encodes numbers in little-endian order (least to most significant byte order)
1504
- * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
1505
- * which is also used in Protocol Buffers.
1506
- *
1507
- * ```js
1508
- * // encoding step
1509
- * const encoder = encoding.createEncoder()
1510
- * encoding.writeVarUint(encoder, 256)
1511
- * encoding.writeVarString(encoder, 'Hello world!')
1512
- * const buf = encoding.toUint8Array(encoder)
1513
- * ```
1514
- *
1515
- * ```js
1516
- * // decoding step
1517
- * const decoder = decoding.createDecoder(buf)
1518
- * decoding.readVarUint(decoder) // => 256
1519
- * decoding.readVarString(decoder) // => 'Hello world!'
1520
- * decoding.hasContent(decoder) // => false - all data is read
1521
- * ```
1522
- *
1523
- * @module decoding
1524
- */
1525
-
1526
-
1527
- const errorUnexpectedEndOfArray = create$1('Unexpected end of array');
1528
- const errorIntegerOutOfRange = create$1('Integer out of Range');
1529
-
1530
- /**
1531
- * A Decoder handles the decoding of an Uint8Array.
1532
- */
1533
- class Decoder {
1534
- /**
1535
- * @param {Uint8Array} uint8Array Binary data to decode
1536
- */
1537
- constructor (uint8Array) {
1538
- /**
1539
- * Decoding target.
1540
- *
1541
- * @type {Uint8Array}
1542
- */
1543
- this.arr = uint8Array;
1544
- /**
1545
- * Current decoding position.
1546
- *
1547
- * @type {number}
1548
- */
1549
- this.pos = 0;
1550
- }
1551
- }
1552
-
1553
- /**
1554
- * @function
1555
- * @param {Uint8Array} uint8Array
1556
- * @return {Decoder}
1557
- */
1558
- const createDecoder = uint8Array => new Decoder(uint8Array);
1559
-
1560
- /**
1561
- * Create an Uint8Array view of the next `len` bytes and advance the position by `len`.
1562
- *
1563
- * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
1564
- * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
1565
- *
1566
- * @function
1567
- * @param {Decoder} decoder The decoder instance
1568
- * @param {number} len The length of bytes to read
1569
- * @return {Uint8Array}
1570
- */
1571
- const readUint8Array = (decoder, len) => {
1572
- const view = new Uint8Array(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len);
1573
- decoder.pos += len;
1574
- return view
1575
- };
1576
-
1577
- /**
1578
- * Read variable length Uint8Array.
1579
- *
1580
- * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
1581
- * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
1582
- *
1583
- * @function
1584
- * @param {Decoder} decoder
1585
- * @return {Uint8Array}
1586
- */
1587
- const readVarUint8Array = decoder => readUint8Array(decoder, readVarUint(decoder));
1588
-
1589
- /**
1590
- * Read one byte as unsigned integer.
1591
- * @function
1592
- * @param {Decoder} decoder The decoder instance
1593
- * @return {number} Unsigned 8-bit integer
1594
- */
1595
- const readUint8 = decoder => decoder.arr[decoder.pos++];
1596
-
1597
- /**
1598
- * Read unsigned integer (32bit) with variable length.
1599
- * 1/8th of the storage is used as encoding overhead.
1600
- * * numbers < 2^7 is stored in one bytlength
1601
- * * numbers < 2^14 is stored in two bylength
1602
- *
1603
- * @function
1604
- * @param {Decoder} decoder
1605
- * @return {number} An unsigned integer.length
1606
- */
1607
- const readVarUint = decoder => {
1608
- let num = 0;
1609
- let mult = 1;
1610
- const len = decoder.arr.length;
1611
- while (decoder.pos < len) {
1612
- const r = decoder.arr[decoder.pos++];
1613
- // num = num | ((r & binary.BITS7) << len)
1614
- num = num + (r & BITS7) * mult; // shift $r << (7*#iterations) and add it to num
1615
- mult *= 128; // next iteration, shift 7 "more" to the left
1616
- if (r < BIT8) {
1617
- return num
1618
- }
1619
- /* c8 ignore start */
1620
- if (num > MAX_SAFE_INTEGER) {
1621
- throw errorIntegerOutOfRange
1622
- }
1623
- /* c8 ignore stop */
1624
- }
1625
- throw errorUnexpectedEndOfArray
1626
- };
1627
-
1628
- /**
1629
- * Read signed integer (32bit) with variable length.
1630
- * 1/8th of the storage is used as encoding overhead.
1631
- * * numbers < 2^7 is stored in one bytlength
1632
- * * numbers < 2^14 is stored in two bylength
1633
- * @todo This should probably create the inverse ~num if number is negative - but this would be a breaking change.
1634
- *
1635
- * @function
1636
- * @param {Decoder} decoder
1637
- * @return {number} An unsigned integer.length
1638
- */
1639
- const readVarInt = decoder => {
1640
- let r = decoder.arr[decoder.pos++];
1641
- let num = r & BITS6;
1642
- let mult = 64;
1643
- const sign = (r & BIT7) > 0 ? -1 : 1;
1644
- if ((r & BIT8) === 0) {
1645
- // don't continue reading
1646
- return sign * num
1647
- }
1648
- const len = decoder.arr.length;
1649
- while (decoder.pos < len) {
1650
- r = decoder.arr[decoder.pos++];
1651
- // num = num | ((r & binary.BITS7) << len)
1652
- num = num + (r & BITS7) * mult;
1653
- mult *= 128;
1654
- if (r < BIT8) {
1655
- return sign * num
1656
- }
1657
- /* c8 ignore start */
1658
- if (num > MAX_SAFE_INTEGER) {
1659
- throw errorIntegerOutOfRange
1660
- }
1661
- /* c8 ignore stop */
1662
- }
1663
- throw errorUnexpectedEndOfArray
1664
- };
1665
-
1666
- /**
1667
- * We don't test this function anymore as we use native decoding/encoding by default now.
1668
- * Better not modify this anymore..
1669
- *
1670
- * Transforming utf8 to a string is pretty expensive. The code performs 10x better
1671
- * when String.fromCodePoint is fed with all characters as arguments.
1672
- * But most environments have a maximum number of arguments per functions.
1673
- * For effiency reasons we apply a maximum of 10000 characters at once.
1674
- *
1675
- * @function
1676
- * @param {Decoder} decoder
1677
- * @return {String} The read String.
1678
- */
1679
- /* c8 ignore start */
1680
- const _readVarStringPolyfill = decoder => {
1681
- let remainingLen = readVarUint(decoder);
1682
- if (remainingLen === 0) {
1683
- return ''
1684
- } else {
1685
- let encodedString = String.fromCodePoint(readUint8(decoder)); // remember to decrease remainingLen
1686
- if (--remainingLen < 100) { // do not create a Uint8Array for small strings
1687
- while (remainingLen--) {
1688
- encodedString += String.fromCodePoint(readUint8(decoder));
1689
- }
1690
- } else {
1691
- while (remainingLen > 0) {
1692
- const nextLen = remainingLen < 10000 ? remainingLen : 10000;
1693
- // this is dangerous, we create a fresh array view from the existing buffer
1694
- const bytes = decoder.arr.subarray(decoder.pos, decoder.pos + nextLen);
1695
- decoder.pos += nextLen;
1696
- // Starting with ES5.1 we can supply a generic array-like object as arguments
1697
- encodedString += String.fromCodePoint.apply(null, /** @type {any} */ (bytes));
1698
- remainingLen -= nextLen;
1699
- }
1700
- }
1701
- return decodeURIComponent(escape(encodedString))
1702
- }
1703
- };
1704
- /* c8 ignore stop */
1705
-
1706
- /**
1707
- * @function
1708
- * @param {Decoder} decoder
1709
- * @return {String} The read String
1710
- */
1711
- const _readVarStringNative = decoder =>
1712
- /** @type any */ (utf8TextDecoder).decode(readVarUint8Array(decoder));
1713
-
1714
- /**
1715
- * Read string of variable length
1716
- * * varUint is used to store the length of the string
1717
- *
1718
- * @function
1719
- * @param {Decoder} decoder
1720
- * @return {String} The read String
1721
- *
1722
- */
1723
- /* c8 ignore next */
1724
- const readVarString = utf8TextDecoder ? _readVarStringNative : _readVarStringPolyfill;
1725
-
1726
- /**
1727
- * Look ahead and read varString without incrementing position
1728
- *
1729
- * @function
1730
- * @param {Decoder} decoder
1731
- * @return {string}
1732
- */
1733
- const peekVarString = decoder => {
1734
- const pos = decoder.pos;
1735
- const s = readVarString(decoder);
1736
- decoder.pos = pos;
1737
- return s
1738
- };
1739
-
1740
- /**
1741
- * Utility module to work with time.
1742
- *
1743
- * @module time
1744
- */
1745
-
1746
-
1747
- /**
1748
- * Return current unix time.
1749
- *
1750
- * @return {number}
1751
- */
1752
- const getUnixTime = Date.now;
1753
-
1754
- /**
1755
- * Utility module to work with key-value stores.
1756
- *
1757
- * @module map
1758
- */
1759
-
1760
- /**
1761
- * Creates a new Map instance.
1762
- *
1763
- * @function
1764
- * @return {Map<any, any>}
1765
- *
1766
- * @function
1767
- */
1768
- const create = () => new Map();
1769
-
1770
- /**
1771
- * Get map property. Create T if property is undefined and set T on map.
1772
- *
1773
- * ```js
1774
- * const listeners = map.setIfUndefined(events, 'eventName', set.create)
1775
- * listeners.add(listener)
1776
- * ```
1777
- *
1778
- * @function
1779
- * @template {Map<any, any>} MAP
1780
- * @template {MAP extends Map<any,infer V> ? function():V : unknown} CF
1781
- * @param {MAP} map
1782
- * @param {MAP extends Map<infer K,any> ? K : unknown} key
1783
- * @param {CF} createT
1784
- * @return {ReturnType<CF>}
1785
- */
1786
- const setIfUndefined = (map, key, createT) => {
1787
- let set = map.get(key);
1788
- if (set === undefined) {
1789
- map.set(key, set = createT());
1790
- }
1791
- return set
1792
- };
1793
-
1794
- /**
1795
- * Observable class prototype.
1796
- *
1797
- * @module observable
1798
- */
1799
-
1800
-
1801
- /* c8 ignore start */
1802
- /**
1803
- * Handles named events.
1804
- *
1805
- * @deprecated
1806
- * @template N
1807
- */
1808
- class Observable {
1809
- constructor () {
1810
- /**
1811
- * Some desc.
1812
- * @type {Map<N, any>}
1813
- */
1814
- this._observers = create();
1815
- }
1816
-
1817
- /**
1818
- * @param {N} name
1819
- * @param {function} f
1820
- */
1821
- on (name, f) {
1822
- setIfUndefined(this._observers, name, create$2).add(f);
1823
- }
1824
-
1825
- /**
1826
- * @param {N} name
1827
- * @param {function} f
1828
- */
1829
- once (name, f) {
1830
- /**
1831
- * @param {...any} args
1832
- */
1833
- const _f = (...args) => {
1834
- this.off(name, _f);
1835
- f(...args);
1836
- };
1837
- this.on(name, _f);
1838
- }
1839
-
1840
- /**
1841
- * @param {N} name
1842
- * @param {function} f
1843
- */
1844
- off (name, f) {
1845
- const observers = this._observers.get(name);
1846
- if (observers !== undefined) {
1847
- observers.delete(f);
1848
- if (observers.size === 0) {
1849
- this._observers.delete(name);
1850
- }
1851
- }
1852
- }
1853
-
1854
- /**
1855
- * Emit a named event. All registered event listeners that listen to the
1856
- * specified name will receive the event.
1857
- *
1858
- * @todo This should catch exceptions
1859
- *
1860
- * @param {N} name The event name.
1861
- * @param {Array<any>} args The arguments that are applied to the event listener.
1862
- */
1863
- emit (name, args) {
1864
- // copy all listeners to an array first to make sure that no event is emitted to listeners that are subscribed while the event handler is called.
1865
- return from((this._observers.get(name) || create()).values()).forEach(f => f(...args))
1866
- }
1867
-
1868
- destroy () {
1869
- this._observers = create();
1870
- }
1871
- }
1872
- /* c8 ignore end */
1873
-
1874
- /**
1875
- * Utility functions for working with EcmaScript objects.
1876
- *
1877
- * @module object
1878
- */
1879
-
1880
-
1881
- /**
1882
- * @param {Object<string,any>} obj
1883
- */
1884
- const keys = Object.keys;
1885
-
1886
- /**
1887
- * @deprecated use object.size instead
1888
- * @param {Object<string,any>} obj
1889
- * @return {number}
1890
- */
1891
- const length = obj => keys(obj).length;
1892
-
1893
- /**
1894
- * Calls `Object.prototype.hasOwnProperty`.
1895
- *
1896
- * @param {any} obj
1897
- * @param {string|symbol} key
1898
- * @return {boolean}
1899
- */
1900
- const hasProperty = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
1901
-
1902
- /**
1903
- * Common functions and function call helpers.
1904
- *
1905
- * @module function
1906
- */
1907
-
1908
-
1909
- /**
1910
- * @template T
1911
- *
1912
- * @param {T} a
1913
- * @param {T} b
1914
- * @return {boolean}
1915
- */
1916
- const equalityStrict = (a, b) => a === b;
1917
-
1918
- /* c8 ignore start */
1919
-
1920
- /**
1921
- * @param {any} a
1922
- * @param {any} b
1923
- * @return {boolean}
1924
- */
1925
- const equalityDeep = (a, b) => {
1926
- if (a == null || b == null) {
1927
- return equalityStrict(a, b)
1928
- }
1929
- if (a.constructor !== b.constructor) {
1930
- return false
1931
- }
1932
- if (a === b) {
1933
- return true
1934
- }
1935
- switch (a.constructor) {
1936
- case ArrayBuffer:
1937
- a = new Uint8Array(a);
1938
- b = new Uint8Array(b);
1939
- // eslint-disable-next-line no-fallthrough
1940
- case Uint8Array: {
1941
- if (a.byteLength !== b.byteLength) {
1942
- return false
1943
- }
1944
- for (let i = 0; i < a.length; i++) {
1945
- if (a[i] !== b[i]) {
1946
- return false
1947
- }
1948
- }
1949
- break
1950
- }
1951
- case Set: {
1952
- if (a.size !== b.size) {
1953
- return false
1954
- }
1955
- for (const value of a) {
1956
- if (!b.has(value)) {
1957
- return false
1958
- }
1959
- }
1960
- break
1961
- }
1962
- case Map: {
1963
- if (a.size !== b.size) {
1964
- return false
1965
- }
1966
- for (const key of a.keys()) {
1967
- if (!b.has(key) || !equalityDeep(a.get(key), b.get(key))) {
1968
- return false
1969
- }
1970
- }
1971
- break
1972
- }
1973
- case Object:
1974
- if (length(a) !== length(b)) {
1975
- return false
1976
- }
1977
- for (const key in a) {
1978
- if (!hasProperty(a, key) || !equalityDeep(a[key], b[key])) {
1979
- return false
1980
- }
1981
- }
1982
- break
1983
- case Array:
1984
- if (a.length !== b.length) {
1985
- return false
1986
- }
1987
- for (let i = 0; i < a.length; i++) {
1988
- if (!equalityDeep(a[i], b[i])) {
1989
- return false
1990
- }
1991
- }
1992
- break
1993
- default:
1994
- return false
1995
- }
1996
- return true
1997
- };
1998
-
1999
- /**
2000
- * @module awareness-protocol
2001
- */
2002
-
2003
-
2004
- const outdatedTimeout = 30000;
2005
-
2006
- /**
2007
- * @typedef {Object} MetaClientState
2008
- * @property {number} MetaClientState.clock
2009
- * @property {number} MetaClientState.lastUpdated unix timestamp
2010
- */
2011
-
2012
- /**
2013
- * The Awareness class implements a simple shared state protocol that can be used for non-persistent data like awareness information
2014
- * (cursor, username, status, ..). Each client can update its own local state and listen to state changes of
2015
- * remote clients. Every client may set a state of a remote peer to `null` to mark the client as offline.
2016
- *
2017
- * Each client is identified by a unique client id (something we borrow from `doc.clientID`). A client can override
2018
- * its own state by propagating a message with an increasing timestamp (`clock`). If such a message is received, it is
2019
- * applied if the known state of that client is older than the new state (`clock < newClock`). If a client thinks that
2020
- * a remote client is offline, it may propagate a message with
2021
- * `{ clock: currentClientClock, state: null, client: remoteClient }`. If such a
2022
- * message is received, and the known clock of that client equals the received clock, it will override the state with `null`.
2023
- *
2024
- * Before a client disconnects, it should propagate a `null` state with an updated clock.
2025
- *
2026
- * Awareness states must be updated every 30 seconds. Otherwise the Awareness instance will delete the client state.
2027
- *
2028
- * @extends {Observable<string>}
2029
- */
2030
- class Awareness extends Observable {
2031
- /**
2032
- * @param {Y.Doc} doc
2033
- */
2034
- constructor (doc) {
2035
- super();
2036
- this.doc = doc;
2037
- /**
2038
- * @type {number}
2039
- */
2040
- this.clientID = doc.clientID;
2041
- /**
2042
- * Maps from client id to client state
2043
- * @type {Map<number, Object<string, any>>}
2044
- */
2045
- this.states = new Map();
2046
- /**
2047
- * @type {Map<number, MetaClientState>}
2048
- */
2049
- this.meta = new Map();
2050
- this._checkInterval = /** @type {any} */ (setInterval(() => {
2051
- const now = getUnixTime();
2052
- if (this.getLocalState() !== null && (outdatedTimeout / 2 <= now - /** @type {{lastUpdated:number}} */ (this.meta.get(this.clientID)).lastUpdated)) {
2053
- // renew local clock
2054
- this.setLocalState(this.getLocalState());
2055
- }
2056
- /**
2057
- * @type {Array<number>}
2058
- */
2059
- const remove = [];
2060
- this.meta.forEach((meta, clientid) => {
2061
- if (clientid !== this.clientID && outdatedTimeout <= now - meta.lastUpdated && this.states.has(clientid)) {
2062
- remove.push(clientid);
2063
- }
2064
- });
2065
- if (remove.length > 0) {
2066
- removeAwarenessStates(this, remove, 'timeout');
2067
- }
2068
- }, floor(outdatedTimeout / 10)));
2069
- doc.on('destroy', () => {
2070
- this.destroy();
2071
- });
2072
- this.setLocalState({});
2073
- }
2074
-
2075
- destroy () {
2076
- this.emit('destroy', [this]);
2077
- this.setLocalState(null);
2078
- super.destroy();
2079
- clearInterval(this._checkInterval);
2080
- }
2081
-
2082
- /**
2083
- * @return {Object<string,any>|null}
2084
- */
2085
- getLocalState () {
2086
- return this.states.get(this.clientID) || null
2087
- }
2088
-
2089
- /**
2090
- * @param {Object<string,any>|null} state
2091
- */
2092
- setLocalState (state) {
2093
- const clientID = this.clientID;
2094
- const currLocalMeta = this.meta.get(clientID);
2095
- const clock = currLocalMeta === undefined ? 0 : currLocalMeta.clock + 1;
2096
- const prevState = this.states.get(clientID);
2097
- if (state === null) {
2098
- this.states.delete(clientID);
2099
- } else {
2100
- this.states.set(clientID, state);
2101
- }
2102
- this.meta.set(clientID, {
2103
- clock,
2104
- lastUpdated: getUnixTime()
2105
- });
2106
- const added = [];
2107
- const updated = [];
2108
- const filteredUpdated = [];
2109
- const removed = [];
2110
- if (state === null) {
2111
- removed.push(clientID);
2112
- } else if (prevState == null) {
2113
- if (state != null) {
2114
- added.push(clientID);
2115
- }
2116
- } else {
2117
- updated.push(clientID);
2118
- if (!equalityDeep(prevState, state)) {
2119
- filteredUpdated.push(clientID);
2120
- }
2121
- }
2122
- if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) {
2123
- this.emit('change', [{ added, updated: filteredUpdated, removed }, 'local']);
2124
- }
2125
- this.emit('update', [{ added, updated, removed }, 'local']);
2126
- }
2127
-
2128
- /**
2129
- * @param {string} field
2130
- * @param {any} value
2131
- */
2132
- setLocalStateField (field, value) {
2133
- const state = this.getLocalState();
2134
- if (state !== null) {
2135
- this.setLocalState({
2136
- ...state,
2137
- [field]: value
2138
- });
2139
- }
2140
- }
2141
-
2142
- /**
2143
- * @return {Map<number,Object<string,any>>}
2144
- */
2145
- getStates () {
2146
- return this.states
2147
- }
2148
- }
2149
-
2150
- /**
2151
- * Mark (remote) clients as inactive and remove them from the list of active peers.
2152
- * This change will be propagated to remote clients.
2153
- *
2154
- * @param {Awareness} awareness
2155
- * @param {Array<number>} clients
2156
- * @param {any} origin
2157
- */
2158
- const removeAwarenessStates = (awareness, clients, origin) => {
2159
- const removed = [];
2160
- for (let i = 0; i < clients.length; i++) {
2161
- const clientID = clients[i];
2162
- if (awareness.states.has(clientID)) {
2163
- awareness.states.delete(clientID);
2164
- if (clientID === awareness.clientID) {
2165
- const curMeta = /** @type {MetaClientState} */ (awareness.meta.get(clientID));
2166
- awareness.meta.set(clientID, {
2167
- clock: curMeta.clock + 1,
2168
- lastUpdated: getUnixTime()
2169
- });
2170
- }
2171
- removed.push(clientID);
2172
- }
2173
- }
2174
- if (removed.length > 0) {
2175
- awareness.emit('change', [{ added: [], updated: [], removed }, origin]);
2176
- awareness.emit('update', [{ added: [], updated: [], removed }, origin]);
2177
- }
2178
- };
2179
-
2180
- /**
2181
- * @param {Awareness} awareness
2182
- * @param {Array<number>} clients
2183
- * @return {Uint8Array}
2184
- */
2185
- const encodeAwarenessUpdate = (awareness, clients, states = awareness.states) => {
2186
- const len = clients.length;
2187
- const encoder = createEncoder();
2188
- writeVarUint(encoder, len);
2189
- for (let i = 0; i < len; i++) {
2190
- const clientID = clients[i];
2191
- const state = states.get(clientID) || null;
2192
- const clock = /** @type {MetaClientState} */ (awareness.meta.get(clientID)).clock;
2193
- writeVarUint(encoder, clientID);
2194
- writeVarUint(encoder, clock);
2195
- writeVarString(encoder, JSON.stringify(state));
2196
- }
2197
- return toUint8Array(encoder)
2198
- };
2199
-
2200
- /**
2201
- * @param {Awareness} awareness
2202
- * @param {Uint8Array} update
2203
- * @param {any} origin This will be added to the emitted change event
2204
- */
2205
- const applyAwarenessUpdate = (awareness, update, origin) => {
2206
- const decoder = createDecoder(update);
2207
- const timestamp = getUnixTime();
2208
- const added = [];
2209
- const updated = [];
2210
- const filteredUpdated = [];
2211
- const removed = [];
2212
- const len = readVarUint(decoder);
2213
- for (let i = 0; i < len; i++) {
2214
- const clientID = readVarUint(decoder);
2215
- let clock = readVarUint(decoder);
2216
- const state = JSON.parse(readVarString(decoder));
2217
- const clientMeta = awareness.meta.get(clientID);
2218
- const prevState = awareness.states.get(clientID);
2219
- const currClock = clientMeta === undefined ? 0 : clientMeta.clock;
2220
- if (currClock < clock || (currClock === clock && state === null && awareness.states.has(clientID))) {
2221
- if (state === null) {
2222
- // never let a remote client remove this local state
2223
- if (clientID === awareness.clientID && awareness.getLocalState() != null) {
2224
- // remote client removed the local state. Do not remote state. Broadcast a message indicating
2225
- // that this client still exists by increasing the clock
2226
- clock++;
2227
- } else {
2228
- awareness.states.delete(clientID);
2229
- }
2230
- } else {
2231
- awareness.states.set(clientID, state);
2232
- }
2233
- awareness.meta.set(clientID, {
2234
- clock,
2235
- lastUpdated: timestamp
2236
- });
2237
- if (clientMeta === undefined && state !== null) {
2238
- added.push(clientID);
2239
- } else if (clientMeta !== undefined && state === null) {
2240
- removed.push(clientID);
2241
- } else if (state !== null) {
2242
- if (!equalityDeep(state, prevState)) {
2243
- filteredUpdated.push(clientID);
2244
- }
2245
- updated.push(clientID);
2246
- }
2247
- }
2248
- }
2249
- if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) {
2250
- awareness.emit('change', [{
2251
- added, updated: filteredUpdated, removed
2252
- }, origin]);
2253
- }
2254
- if (added.length > 0 || updated.length > 0 || removed.length > 0) {
2255
- awareness.emit('update', [{
2256
- added, updated, removed
2257
- }, origin]);
2258
- }
2259
- };
2260
-
2261
- class EventEmitter {
2262
- constructor() {
2263
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
2264
- this.callbacks = {};
2265
- }
2266
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
2267
- on(event, fn) {
2268
- if (!this.callbacks[event]) {
2269
- this.callbacks[event] = [];
2270
- }
2271
- this.callbacks[event].push(fn);
2272
- return this;
2273
- }
2274
- emit(event, ...args) {
2275
- const callbacks = this.callbacks[event];
2276
- if (callbacks) {
2277
- callbacks.forEach((callback) => callback.apply(this, args));
2278
- }
2279
- return this;
2280
- }
2281
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
2282
- off(event, fn) {
2283
- const callbacks = this.callbacks[event];
2284
- if (callbacks) {
2285
- if (fn) {
2286
- this.callbacks[event] = callbacks.filter((callback) => callback !== fn);
2287
- }
2288
- else {
2289
- delete this.callbacks[event];
2290
- }
2291
- }
2292
- return this;
2293
- }
2294
- removeAllListeners() {
2295
- this.callbacks = {};
2296
- }
2297
- }
2298
-
2299
- class IncomingMessage {
2300
- constructor(data) {
2301
- this.data = data;
2302
- this.encoder = createEncoder();
2303
- this.decoder = createDecoder(new Uint8Array(this.data));
2304
- }
2305
- peekVarString() {
2306
- return peekVarString(this.decoder);
2307
- }
2308
- readVarUint() {
2309
- return readVarUint(this.decoder);
2310
- }
2311
- readVarString() {
2312
- return readVarString(this.decoder);
2313
- }
2314
- readVarUint8Array() {
2315
- return readVarUint8Array(this.decoder);
2316
- }
2317
- writeVarUint(type) {
2318
- return writeVarUint(this.encoder, type);
2319
- }
2320
- writeVarString(string) {
2321
- return writeVarString(this.encoder, string);
2322
- }
2323
- writeVarUint8Array(data) {
2324
- return writeVarUint8Array(this.encoder, data);
2325
- }
2326
- length() {
2327
- return length$1(this.encoder);
2328
- }
2329
- }
2330
-
2331
- var MessageType;
2332
- (function (MessageType) {
2333
- MessageType[MessageType["Sync"] = 0] = "Sync";
2334
- MessageType[MessageType["Awareness"] = 1] = "Awareness";
2335
- MessageType[MessageType["Auth"] = 2] = "Auth";
2336
- MessageType[MessageType["QueryAwareness"] = 3] = "QueryAwareness";
2337
- MessageType[MessageType["Stateless"] = 5] = "Stateless";
2338
- MessageType[MessageType["CLOSE"] = 7] = "CLOSE";
2339
- MessageType[MessageType["SyncStatus"] = 8] = "SyncStatus";
2340
- })(MessageType || (MessageType = {}));
2341
- var WebSocketStatus;
2342
- (function (WebSocketStatus) {
2343
- WebSocketStatus["Connecting"] = "connecting";
2344
- WebSocketStatus["Connected"] = "connected";
2345
- WebSocketStatus["Disconnected"] = "disconnected";
2346
- })(WebSocketStatus || (WebSocketStatus = {}));
2347
-
2348
- class OutgoingMessage {
2349
- constructor() {
2350
- this.encoder = createEncoder();
2351
- }
2352
- get(args) {
2353
- return args.encoder;
2354
- }
2355
- toUint8Array() {
2356
- return toUint8Array(this.encoder);
2357
- }
2358
- }
2359
-
2360
- class CloseMessage extends OutgoingMessage {
2361
- constructor() {
2362
- super(...arguments);
2363
- this.type = MessageType.CLOSE;
2364
- this.description = "Ask the server to close the connection";
2365
- }
2366
- get(args) {
2367
- writeVarString(this.encoder, args.documentName);
2368
- writeVarUint(this.encoder, this.type);
2369
- return this.encoder;
2370
- }
2371
- }
2372
-
2373
- class HocuspocusProviderWebsocket extends EventEmitter {
2374
- constructor(configuration) {
2375
- super();
2376
- this.messageQueue = [];
2377
- this.configuration = {
2378
- url: "",
2379
- autoConnect: true,
2380
- preserveTrailingSlash: false,
2381
- // @ts-ignore
2382
- document: undefined,
2383
- WebSocketPolyfill: undefined,
2384
- // TODO: this should depend on awareness.outdatedTime
2385
- messageReconnectTimeout: 30000,
2386
- // 1 second
2387
- delay: 1000,
2388
- // instant
2389
- initialDelay: 0,
2390
- // double the delay each time
2391
- factor: 2,
2392
- // unlimited retries
2393
- maxAttempts: 0,
2394
- // wait at least 1 second
2395
- minDelay: 1000,
2396
- // at least every 30 seconds
2397
- maxDelay: 30000,
2398
- // randomize
2399
- jitter: true,
2400
- // retry forever
2401
- timeout: 0,
2402
- onOpen: () => null,
2403
- onConnect: () => null,
2404
- onMessage: () => null,
2405
- onOutgoingMessage: () => null,
2406
- onStatus: () => null,
2407
- onDisconnect: () => null,
2408
- onClose: () => null,
2409
- onDestroy: () => null,
2410
- onAwarenessUpdate: () => null,
2411
- onAwarenessChange: () => null,
2412
- handleTimeout: null,
2413
- providerMap: new Map(),
2414
- };
2415
- this.webSocket = null;
2416
- this.webSocketHandlers = {};
2417
- this.shouldConnect = true;
2418
- this.status = WebSocketStatus.Disconnected;
2419
- this.lastMessageReceived = 0;
2420
- this.identifier = 0;
2421
- this.intervals = {
2422
- connectionChecker: null,
2423
- };
2424
- this.connectionAttempt = null;
2425
- this.receivedOnOpenPayload = undefined;
2426
- this.closeTries = 0;
2427
- this.setConfiguration(configuration);
2428
- this.configuration.WebSocketPolyfill = configuration.WebSocketPolyfill
2429
- ? configuration.WebSocketPolyfill
2430
- : WebSocket;
2431
- this.on("open", this.configuration.onOpen);
2432
- this.on("open", this.onOpen.bind(this));
2433
- this.on("connect", this.configuration.onConnect);
2434
- this.on("message", this.configuration.onMessage);
2435
- this.on("outgoingMessage", this.configuration.onOutgoingMessage);
2436
- this.on("status", this.configuration.onStatus);
2437
- this.on("disconnect", this.configuration.onDisconnect);
2438
- this.on("close", this.configuration.onClose);
2439
- this.on("destroy", this.configuration.onDestroy);
2440
- this.on("awarenessUpdate", this.configuration.onAwarenessUpdate);
2441
- this.on("awarenessChange", this.configuration.onAwarenessChange);
2442
- this.on("close", this.onClose.bind(this));
2443
- this.on("message", this.onMessage.bind(this));
2444
- this.intervals.connectionChecker = setInterval(this.checkConnection.bind(this), this.configuration.messageReconnectTimeout / 10);
2445
- if (this.shouldConnect) {
2446
- this.connect();
2447
- }
2448
- }
2449
- async onOpen(event) {
2450
- this.status = WebSocketStatus.Connected;
2451
- this.emit("status", { status: WebSocketStatus.Connected });
2452
- this.cancelWebsocketRetry = undefined;
2453
- this.receivedOnOpenPayload = event;
2454
- }
2455
- attach(provider) {
2456
- this.configuration.providerMap.set(provider.configuration.name, provider);
2457
- if (this.status === WebSocketStatus.Disconnected && this.shouldConnect) {
2458
- this.connect();
2459
- }
2460
- if (this.receivedOnOpenPayload &&
2461
- this.status === WebSocketStatus.Connected) {
2462
- provider.onOpen(this.receivedOnOpenPayload);
2463
- }
2464
- }
2465
- detach(provider) {
2466
- if (this.configuration.providerMap.has(provider.configuration.name)) {
2467
- provider.send(CloseMessage, {
2468
- documentName: provider.configuration.name,
2469
- });
2470
- this.configuration.providerMap.delete(provider.configuration.name);
2471
- }
2472
- }
2473
- setConfiguration(configuration = {}) {
2474
- this.configuration = { ...this.configuration, ...configuration };
2475
- if (!this.configuration.autoConnect) {
2476
- this.shouldConnect = false;
2477
- }
2478
- }
2479
- async connect() {
2480
- if (this.status === WebSocketStatus.Connected) {
2481
- return;
2482
- }
2483
- // Always cancel any previously initiated connection retryer instances
2484
- if (this.cancelWebsocketRetry) {
2485
- this.cancelWebsocketRetry();
2486
- this.cancelWebsocketRetry = undefined;
2487
- }
2488
- this.receivedOnOpenPayload = undefined;
2489
- this.shouldConnect = true;
2490
- const abortableRetry = () => {
2491
- let cancelAttempt = false;
2492
- const retryPromise = retry(this.createWebSocketConnection.bind(this), {
2493
- delay: this.configuration.delay,
2494
- initialDelay: this.configuration.initialDelay,
2495
- factor: this.configuration.factor,
2496
- maxAttempts: this.configuration.maxAttempts,
2497
- minDelay: this.configuration.minDelay,
2498
- maxDelay: this.configuration.maxDelay,
2499
- jitter: this.configuration.jitter,
2500
- timeout: this.configuration.timeout,
2501
- handleTimeout: this.configuration.handleTimeout,
2502
- beforeAttempt: (context) => {
2503
- if (!this.shouldConnect || cancelAttempt) {
2504
- context.abort();
2505
- }
2506
- },
2507
- }).catch((error) => {
2508
- // If we aborted the connection attempt then don’t throw an error
2509
- // ref: https://github.com/lifeomic/attempt/blob/master/src/index.ts#L136
2510
- if (error && error.code !== "ATTEMPT_ABORTED") {
2511
- throw error;
2512
- }
2513
- });
2514
- return {
2515
- retryPromise,
2516
- cancelFunc: () => {
2517
- cancelAttempt = true;
2518
- },
2519
- };
2520
- };
2521
- const { retryPromise, cancelFunc } = abortableRetry();
2522
- this.cancelWebsocketRetry = cancelFunc;
2523
- return retryPromise;
2524
- }
2525
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
2526
- attachWebSocketListeners(ws, reject) {
2527
- const { identifier } = ws;
2528
- const onMessageHandler = (payload) => this.emit("message", payload);
2529
- const onCloseHandler = (payload) => this.emit("close", { event: payload });
2530
- const onOpenHandler = (payload) => this.emit("open", payload);
2531
- const onErrorHandler = (err) => {
2532
- reject(err);
2533
- };
2534
- this.webSocketHandlers[identifier] = {
2535
- message: onMessageHandler,
2536
- close: onCloseHandler,
2537
- open: onOpenHandler,
2538
- error: onErrorHandler,
2539
- };
2540
- const handlers = this.webSocketHandlers[ws.identifier];
2541
- Object.keys(handlers).forEach((name) => {
2542
- ws.addEventListener(name, handlers[name]);
2543
- });
2544
- }
2545
- cleanupWebSocket() {
2546
- if (!this.webSocket) {
2547
- return;
2548
- }
2549
- const { identifier } = this.webSocket;
2550
- const handlers = this.webSocketHandlers[identifier];
2551
- Object.keys(handlers).forEach((name) => {
2552
- var _a;
2553
- (_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.removeEventListener(name, handlers[name]);
2554
- delete this.webSocketHandlers[identifier];
2555
- });
2556
- this.webSocket.close();
2557
- this.webSocket = null;
2558
- }
2559
- createWebSocketConnection() {
2560
- return new Promise((resolve, reject) => {
2561
- if (this.webSocket) {
2562
- this.messageQueue = [];
2563
- this.cleanupWebSocket();
2564
- }
2565
- this.lastMessageReceived = 0;
2566
- this.identifier += 1;
2567
- // Init the WebSocket connection
2568
- const ws = new this.configuration.WebSocketPolyfill(this.url);
2569
- ws.binaryType = "arraybuffer";
2570
- ws.identifier = this.identifier;
2571
- this.attachWebSocketListeners(ws, reject);
2572
- this.webSocket = ws;
2573
- // Reset the status
2574
- this.status = WebSocketStatus.Connecting;
2575
- this.emit("status", { status: WebSocketStatus.Connecting });
2576
- // Store resolve/reject for later use
2577
- this.connectionAttempt = {
2578
- resolve,
2579
- reject,
2580
- };
2581
- });
2582
- }
2583
- onMessage(event) {
2584
- var _a;
2585
- this.resolveConnectionAttempt();
2586
- this.lastMessageReceived = getUnixTime();
2587
- const message = new IncomingMessage(event.data);
2588
- const documentName = message.peekVarString();
2589
- (_a = this.configuration.providerMap.get(documentName)) === null || _a === void 0 ? void 0 : _a.onMessage(event);
2590
- }
2591
- resolveConnectionAttempt() {
2592
- if (this.connectionAttempt) {
2593
- this.connectionAttempt.resolve();
2594
- this.connectionAttempt = null;
2595
- this.status = WebSocketStatus.Connected;
2596
- this.emit("status", { status: WebSocketStatus.Connected });
2597
- this.emit("connect");
2598
- this.messageQueue.forEach((message) => this.send(message));
2599
- this.messageQueue = [];
2600
- }
2601
- }
2602
- stopConnectionAttempt() {
2603
- this.connectionAttempt = null;
2604
- }
2605
- rejectConnectionAttempt() {
2606
- var _a;
2607
- (_a = this.connectionAttempt) === null || _a === void 0 ? void 0 : _a.reject();
2608
- this.connectionAttempt = null;
2609
- }
2610
- checkConnection() {
2611
- var _a;
2612
- // Don’t check the connection when it’s not even established
2613
- if (this.status !== WebSocketStatus.Connected) {
2614
- return;
2615
- }
2616
- // Don’t close the connection while waiting for the first message
2617
- if (!this.lastMessageReceived) {
2618
- return;
2619
- }
2620
- // Don’t close the connection when a message was received recently
2621
- if (this.configuration.messageReconnectTimeout >=
2622
- getUnixTime() - this.lastMessageReceived) {
2623
- return;
2624
- }
2625
- // No message received in a long time, not even your own
2626
- // Awareness updates, which are updated every 15 seconds
2627
- // if awareness is enabled.
2628
- this.closeTries += 1;
2629
- // https://bugs.webkit.org/show_bug.cgi?id=247943
2630
- if (this.closeTries > 2) {
2631
- this.onClose({
2632
- event: {
2633
- code: 4408,
2634
- reason: "forced",
2635
- },
2636
- });
2637
- this.closeTries = 0;
2638
- }
2639
- else {
2640
- (_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.close();
2641
- this.messageQueue = [];
2642
- }
2643
- }
2644
- get serverUrl() {
2645
- if (this.configuration.preserveTrailingSlash) {
2646
- return this.configuration.url;
2647
- }
2648
- // By default, ensure that the URL never ends with /
2649
- let url = this.configuration.url;
2650
- while (url[url.length - 1] === "/") {
2651
- url = url.slice(0, url.length - 1);
2652
- }
2653
- return url;
2654
- }
2655
- get url() {
2656
- return this.serverUrl;
2657
- }
2658
- disconnect() {
2659
- this.shouldConnect = false;
2660
- if (this.webSocket === null) {
2661
- return;
2662
- }
2663
- try {
2664
- this.webSocket.close();
2665
- this.messageQueue = [];
2666
- }
2667
- catch (e) {
2668
- console.error(e);
2669
- }
2670
- }
2671
- send(message) {
2672
- var _a;
2673
- if (((_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.readyState) === WsReadyStates.Open) {
2674
- this.webSocket.send(message);
2675
- }
2676
- else {
2677
- this.messageQueue.push(message);
2678
- }
2679
- }
2680
- onClose({ event }) {
2681
- this.closeTries = 0;
2682
- this.cleanupWebSocket();
2683
- if (this.connectionAttempt) {
2684
- // That connection attempt failed.
2685
- this.rejectConnectionAttempt();
2686
- }
2687
- // Let’s update the connection status.
2688
- this.status = WebSocketStatus.Disconnected;
2689
- this.emit("status", { status: WebSocketStatus.Disconnected });
2690
- this.emit("disconnect", { event });
2691
- // trigger connect if no retry is running and we want to have a connection
2692
- if (!this.cancelWebsocketRetry && this.shouldConnect) {
2693
- setTimeout(() => {
2694
- this.connect();
2695
- }, this.configuration.delay);
2696
- }
2697
- }
2698
- destroy() {
2699
- this.emit("destroy");
2700
- clearInterval(this.intervals.connectionChecker);
2701
- // If there is still a connection attempt outstanding then we should stop
2702
- // it before calling disconnect, otherwise it will be rejected in the onClose
2703
- // handler and trigger a retry
2704
- this.stopConnectionAttempt();
2705
- this.disconnect();
2706
- this.removeAllListeners();
2707
- this.cleanupWebSocket();
2708
- }
2709
- }
2710
-
2711
- /**
2712
- * @module sync-protocol
2713
- */
2714
-
2715
-
2716
- /**
2717
- * @typedef {Map<number, number>} StateMap
2718
- */
2719
-
2720
- /**
2721
- * Core Yjs defines two message types:
2722
- * • YjsSyncStep1: Includes the State Set of the sending client. When received, the client should reply with YjsSyncStep2.
2723
- * • YjsSyncStep2: Includes all missing structs and the complete delete set. When received, the client is assured that it
2724
- * received all information from the remote client.
2725
- *
2726
- * In a peer-to-peer network, you may want to introduce a SyncDone message type. Both parties should initiate the connection
2727
- * with SyncStep1. When a client received SyncStep2, it should reply with SyncDone. When the local client received both
2728
- * SyncStep2 and SyncDone, it is assured that it is synced to the remote client.
2729
- *
2730
- * In a client-server model, you want to handle this differently: The client should initiate the connection with SyncStep1.
2731
- * When the server receives SyncStep1, it should reply with SyncStep2 immediately followed by SyncStep1. The client replies
2732
- * with SyncStep2 when it receives SyncStep1. Optionally the server may send a SyncDone after it received SyncStep2, so the
2733
- * client knows that the sync is finished. There are two reasons for this more elaborated sync model: 1. This protocol can
2734
- * easily be implemented on top of http and websockets. 2. The server should only reply to requests, and not initiate them.
2735
- * Therefore it is necessary that the client initiates the sync.
2736
- *
2737
- * Construction of a message:
2738
- * [messageType : varUint, message definition..]
2739
- *
2740
- * Note: A message does not include information about the room name. This must to be handled by the upper layer protocol!
2741
- *
2742
- * stringify[messageType] stringifies a message definition (messageType is already read from the bufffer)
2743
- */
2744
-
2745
- const messageYjsSyncStep1 = 0;
2746
- const messageYjsSyncStep2 = 1;
2747
- const messageYjsUpdate = 2;
2748
-
2749
- /**
2750
- * Create a sync step 1 message based on the state of the current shared document.
2751
- *
2752
- * @param {encoding.Encoder} encoder
2753
- * @param {Y.Doc} doc
2754
- */
2755
- const writeSyncStep1 = (encoder, doc) => {
2756
- writeVarUint(encoder, messageYjsSyncStep1);
2757
- const sv = Y__namespace.encodeStateVector(doc);
2758
- writeVarUint8Array(encoder, sv);
2759
- };
2760
-
2761
- /**
2762
- * @param {encoding.Encoder} encoder
2763
- * @param {Y.Doc} doc
2764
- * @param {Uint8Array} [encodedStateVector]
2765
- */
2766
- const writeSyncStep2 = (encoder, doc, encodedStateVector) => {
2767
- writeVarUint(encoder, messageYjsSyncStep2);
2768
- writeVarUint8Array(encoder, Y__namespace.encodeStateAsUpdate(doc, encodedStateVector));
2769
- };
2770
-
2771
- /**
2772
- * Read SyncStep1 message and reply with SyncStep2.
2773
- *
2774
- * @param {decoding.Decoder} decoder The reply to the received message
2775
- * @param {encoding.Encoder} encoder The received message
2776
- * @param {Y.Doc} doc
2777
- */
2778
- const readSyncStep1 = (decoder, encoder, doc) =>
2779
- writeSyncStep2(encoder, doc, readVarUint8Array(decoder));
2780
-
2781
- /**
2782
- * Read and apply Structs and then DeleteStore to a y instance.
2783
- *
2784
- * @param {decoding.Decoder} decoder
2785
- * @param {Y.Doc} doc
2786
- * @param {any} transactionOrigin
2787
- */
2788
- const readSyncStep2 = (decoder, doc, transactionOrigin) => {
2789
- try {
2790
- Y__namespace.applyUpdate(doc, readVarUint8Array(decoder), transactionOrigin);
2791
- } catch (error) {
2792
- // This catches errors that are thrown by event handlers
2793
- console.error('Caught error while handling a Yjs update', error);
2794
- }
2795
- };
2796
-
2797
- /**
2798
- * @param {encoding.Encoder} encoder
2799
- * @param {Uint8Array} update
2800
- */
2801
- const writeUpdate = (encoder, update) => {
2802
- writeVarUint(encoder, messageYjsUpdate);
2803
- writeVarUint8Array(encoder, update);
2804
- };
2805
-
2806
- /**
2807
- * Read and apply Structs and then DeleteStore to a y instance.
2808
- *
2809
- * @param {decoding.Decoder} decoder
2810
- * @param {Y.Doc} doc
2811
- * @param {any} transactionOrigin
2812
- */
2813
- const readUpdate = readSyncStep2;
2814
-
2815
- /**
2816
- * @param {decoding.Decoder} decoder A message received from another client
2817
- * @param {encoding.Encoder} encoder The reply message. Does not need to be sent if empty.
2818
- * @param {Y.Doc} doc
2819
- * @param {any} transactionOrigin
2820
- */
2821
- const readSyncMessage = (decoder, encoder, doc, transactionOrigin) => {
2822
- const messageType = readVarUint(decoder);
2823
- switch (messageType) {
2824
- case messageYjsSyncStep1:
2825
- readSyncStep1(decoder, encoder, doc);
2826
- break
2827
- case messageYjsSyncStep2:
2828
- readSyncStep2(decoder, doc, transactionOrigin);
2829
- break
2830
- case messageYjsUpdate:
2831
- readUpdate(decoder, doc, transactionOrigin);
2832
- break
2833
- default:
2834
- throw new Error('Unknown message type')
2835
- }
2836
- return messageType
2837
- };
2838
-
2839
- class MessageReceiver {
2840
- constructor(message) {
2841
- this.message = message;
362
+ class BroadcastSyncProvider {
363
+ type = 'local';
364
+ doc;
365
+ channel;
366
+ _synced = false;
367
+ constructor(docName, doc, _options) {
368
+ this.doc = doc;
369
+ this.channel = new BroadcastChannel(docName);
370
+ // Handle incoming messages from other tabs
371
+ this.channel.onmessage = (event) => {
372
+ this.handleMessage(event.data);
373
+ };
374
+ // Listen to document updates and broadcast them
375
+ this.doc.on('update', this.handleDocUpdate);
376
+ // Send initial sync request
377
+ this.broadcastSync();
378
+ // Mark as synced after a short delay (to receive any pending updates)
379
+ setTimeout(() => {
380
+ this._synced = true;
381
+ }, 100);
382
+ if (!_options?.quiet) {
383
+ console.info(`BroadcastChannel Provider initialized: ${docName}`);
384
+ }
2842
385
  }
2843
- apply(provider, emitSynced) {
2844
- const { message } = this;
2845
- const type = message.readVarUint();
2846
- const emptyMessageLength = message.length();
2847
- switch (type) {
2848
- case MessageType.Sync:
2849
- this.applySyncMessage(provider, emitSynced);
2850
- break;
2851
- case MessageType.Awareness:
2852
- this.applyAwarenessMessage(provider);
2853
- break;
2854
- case MessageType.Auth:
2855
- this.applyAuthMessage(provider);
2856
- break;
2857
- case MessageType.QueryAwareness:
2858
- this.applyQueryAwarenessMessage(provider);
2859
- break;
2860
- case MessageType.Stateless:
2861
- provider.receiveStateless(readVarString(message.decoder));
386
+ handleDocUpdate = (update, origin) => {
387
+ // Don't broadcast updates that came from other tabs (to prevent loops)
388
+ if (origin !== this) {
389
+ const encoder = createEncoder();
390
+ writeVarUint(encoder, 0); // Message type: sync update
391
+ writeVarUint8Array(encoder, update);
392
+ this.channel.postMessage(toUint8Array(encoder));
393
+ }
394
+ };
395
+ handleMessage(message) {
396
+ const decoder = createDecoder(new Uint8Array(message));
397
+ const messageType = readVarUint(decoder);
398
+ switch (messageType) {
399
+ case 0: // Sync update
400
+ const update = readVarUint8Array(decoder);
401
+ Y__namespace.applyUpdate(this.doc, update, this);
2862
402
  break;
2863
- case MessageType.SyncStatus:
2864
- this.applySyncStatusMessage(provider, readVarInt(message.decoder) === 1);
403
+ case 1: // Sync request
404
+ this.broadcastSync();
2865
405
  break;
2866
- case MessageType.CLOSE:
2867
- // eslint-disable-next-line no-case-declarations
2868
- const event = {
2869
- code: 1000,
2870
- reason: readVarString(message.decoder),
2871
- // @ts-ignore
2872
- target: provider.configuration.websocketProvider.webSocket,
2873
- type: "close",
2874
- };
2875
- provider.onClose();
2876
- provider.configuration.onClose({ event });
2877
- provider.forwardClose({ event });
406
+ case 2: // Sync response
407
+ const stateVector = readVarUint8Array(decoder);
408
+ const updateResponse = Y__namespace.encodeStateAsUpdate(this.doc, stateVector);
409
+ if (updateResponse.length > 0) {
410
+ const encoder = createEncoder();
411
+ writeVarUint(encoder, 0); // Send as regular update
412
+ writeVarUint8Array(encoder, updateResponse);
413
+ this.channel.postMessage(toUint8Array(encoder));
414
+ }
2878
415
  break;
2879
- default:
2880
- throw new Error(`Can’t apply message of unknown type: ${type}`);
2881
- }
2882
- // Reply
2883
- if (message.length() > emptyMessageLength + 1) {
2884
- // length of documentName (considered in emptyMessageLength plus length of yjs sync type, set in applySyncMessage)
2885
- // @ts-ignore
2886
- provider.send(OutgoingMessage, { encoder: message.encoder });
2887
- }
2888
- }
2889
- applySyncMessage(provider, emitSynced) {
2890
- const { message } = this;
2891
- message.writeVarUint(MessageType.Sync);
2892
- // Apply update
2893
- const syncMessageType = readSyncMessage(message.decoder, message.encoder, provider.document, provider);
2894
- // Synced once we receive Step2
2895
- if (emitSynced && syncMessageType === messageYjsSyncStep2) {
2896
- provider.synced = true;
2897
416
  }
2898
417
  }
2899
- applySyncStatusMessage(provider, applied) {
2900
- if (applied) {
2901
- provider.decrementUnsyncedChanges();
2902
- }
2903
- }
2904
- applyAwarenessMessage(provider) {
2905
- if (!provider.awareness)
2906
- return;
2907
- const { message } = this;
2908
- applyAwarenessUpdate(provider.awareness, message.readVarUint8Array(), provider);
2909
- }
2910
- applyAuthMessage(provider) {
2911
- const { message } = this;
2912
- readAuthMessage(message.decoder, provider.sendToken.bind(provider), provider.permissionDeniedHandler.bind(provider), provider.authenticatedHandler.bind(provider));
418
+ broadcastSync() {
419
+ // Broadcast our current state vector to request missing updates
420
+ const encoder = createEncoder();
421
+ writeVarUint(encoder, 2); // Message type: sync response
422
+ writeVarUint8Array(encoder, Y__namespace.encodeStateVector(this.doc));
423
+ this.channel.postMessage(toUint8Array(encoder));
2913
424
  }
2914
- applyQueryAwarenessMessage(provider) {
2915
- if (!provider.awareness)
425
+ async connect() {
426
+ // Wait for initial sync to complete
427
+ if (this._synced) {
2916
428
  return;
2917
- const { message } = this;
2918
- message.writeVarUint(MessageType.Awareness);
2919
- message.writeVarUint8Array(encodeAwarenessUpdate(provider.awareness, Array.from(provider.awareness.getStates().keys())));
2920
- }
2921
- }
2922
-
2923
- class MessageSender {
2924
- constructor(Message, args = {}) {
2925
- this.message = new Message();
2926
- this.encoder = this.message.get(args);
2927
- }
2928
- create() {
2929
- return toUint8Array(this.encoder);
2930
- }
2931
- send(webSocket) {
2932
- webSocket === null || webSocket === void 0 ? void 0 : webSocket.send(this.create());
2933
- }
2934
- }
2935
-
2936
- class AuthenticationMessage extends OutgoingMessage {
2937
- constructor() {
2938
- super(...arguments);
2939
- this.type = MessageType.Auth;
2940
- this.description = "Authentication";
2941
- }
2942
- get(args) {
2943
- if (typeof args.token === "undefined") {
2944
- throw new Error("The authentication message requires `token` as an argument.");
2945
- }
2946
- writeVarString(this.encoder, args.documentName);
2947
- writeVarUint(this.encoder, this.type);
2948
- writeAuthentication(this.encoder, args.token);
2949
- return this.encoder;
2950
- }
2951
- }
2952
-
2953
- class AwarenessMessage extends OutgoingMessage {
2954
- constructor() {
2955
- super(...arguments);
2956
- this.type = MessageType.Awareness;
2957
- this.description = "Awareness states update";
2958
- }
2959
- get(args) {
2960
- if (typeof args.awareness === "undefined") {
2961
- throw new Error("The awareness message requires awareness as an argument");
2962
- }
2963
- if (typeof args.clients === "undefined") {
2964
- throw new Error("The awareness message requires clients as an argument");
2965
429
  }
2966
- writeVarString(this.encoder, args.documentName);
2967
- writeVarUint(this.encoder, this.type);
2968
- let awarenessUpdate;
2969
- if (args.states === undefined) {
2970
- awarenessUpdate = encodeAwarenessUpdate(args.awareness, args.clients);
2971
- }
2972
- else {
2973
- awarenessUpdate = encodeAwarenessUpdate(args.awareness, args.clients, args.states);
2974
- }
2975
- writeVarUint8Array(this.encoder, awarenessUpdate);
2976
- return this.encoder;
2977
- }
2978
- }
2979
-
2980
- class StatelessMessage extends OutgoingMessage {
2981
- constructor() {
2982
- super(...arguments);
2983
- this.type = MessageType.Stateless;
2984
- this.description = "A stateless message";
2985
- }
2986
- get(args) {
2987
- var _a;
2988
- writeVarString(this.encoder, args.documentName);
2989
- writeVarUint(this.encoder, this.type);
2990
- writeVarString(this.encoder, (_a = args.payload) !== null && _a !== void 0 ? _a : "");
2991
- return this.encoder;
2992
- }
2993
- }
2994
-
2995
- class SyncStepOneMessage extends OutgoingMessage {
2996
- constructor() {
2997
- super(...arguments);
2998
- this.type = MessageType.Sync;
2999
- this.description = "First sync step";
430
+ return new Promise((resolve) => {
431
+ const checkSync = () => {
432
+ if (this._synced) {
433
+ resolve();
434
+ }
435
+ else {
436
+ setTimeout(checkSync, 50);
437
+ }
438
+ };
439
+ checkSync();
440
+ });
3000
441
  }
3001
- get(args) {
3002
- if (typeof args.document === "undefined") {
3003
- throw new Error("The sync step one message requires document as an argument");
3004
- }
3005
- writeVarString(this.encoder, args.documentName);
3006
- writeVarUint(this.encoder, this.type);
3007
- writeSyncStep1(this.encoder, args.document);
3008
- return this.encoder;
442
+ disconnect() {
443
+ // BroadcastChannel doesn't have explicit disconnect
3009
444
  }
3010
- }
3011
-
3012
- class UpdateMessage extends OutgoingMessage {
3013
- constructor() {
3014
- super(...arguments);
3015
- this.type = MessageType.Sync;
3016
- this.description = "A document update";
445
+ async reconnect() {
446
+ this.disconnect();
447
+ return this.connect();
3017
448
  }
3018
- get(args) {
3019
- writeVarString(this.encoder, args.documentName);
3020
- writeVarUint(this.encoder, this.type);
3021
- writeUpdate(this.encoder, args.update);
3022
- return this.encoder;
449
+ destroy() {
450
+ this.doc.off('update', this.handleDocUpdate);
451
+ this.channel.close();
3023
452
  }
3024
453
  }
3025
454
 
3026
- class AwarenessError extends Error {
3027
- constructor() {
3028
- super(...arguments);
3029
- this.code = 1001;
3030
- }
3031
- }
3032
- class HocuspocusProvider extends EventEmitter {
3033
- constructor(configuration) {
3034
- var _a, _b, _c;
3035
- super();
3036
- this.configuration = {
3037
- name: "",
3038
- // @ts-ignore
3039
- document: undefined,
3040
- // @ts-ignore
3041
- awareness: undefined,
3042
- token: null,
3043
- forceSyncInterval: false,
3044
- onAuthenticated: () => null,
3045
- onAuthenticationFailed: () => null,
3046
- onOpen: () => null,
3047
- onConnect: () => null,
3048
- onMessage: () => null,
3049
- onOutgoingMessage: () => null,
3050
- onSynced: () => null,
3051
- onStatus: () => null,
3052
- onDisconnect: () => null,
3053
- onClose: () => null,
3054
- onDestroy: () => null,
3055
- onAwarenessUpdate: () => null,
3056
- onAwarenessChange: () => null,
3057
- onStateless: () => null,
3058
- onUnsyncedChanges: () => null,
3059
- };
3060
- this.isSynced = false;
3061
- this.unsyncedChanges = 0;
3062
- this.isAuthenticated = false;
3063
- this.authorizedScope = undefined;
3064
- // @internal
3065
- this.manageSocket = false;
3066
- this._isAttached = false;
3067
- this.intervals = {
3068
- forceSync: null,
3069
- };
3070
- this.boundDocumentUpdateHandler = this.documentUpdateHandler.bind(this);
3071
- this.boundAwarenessUpdateHandler = this.awarenessUpdateHandler.bind(this);
3072
- this.boundPageHide = this.pageHide.bind(this);
3073
- this.boundOnOpen = this.onOpen.bind(this);
3074
- this.boundOnClose = this.onClose.bind(this);
3075
- this.forwardConnect = () => this.emit("connect");
3076
- this.forwardStatus = (e) => this.emit("status", e);
3077
- this.forwardClose = (e) => this.emit("close", e);
3078
- this.forwardDisconnect = (e) => this.emit("disconnect", e);
3079
- this.forwardDestroy = () => this.emit("destroy");
3080
- this.setConfiguration(configuration);
3081
- this.configuration.document = configuration.document
3082
- ? configuration.document
3083
- : new Y__namespace.Doc();
3084
- this.configuration.awareness =
3085
- configuration.awareness !== undefined
3086
- ? configuration.awareness
3087
- : new Awareness(this.document);
3088
- this.on("open", this.configuration.onOpen);
3089
- this.on("message", this.configuration.onMessage);
3090
- this.on("outgoingMessage", this.configuration.onOutgoingMessage);
3091
- this.on("synced", this.configuration.onSynced);
3092
- this.on("destroy", this.configuration.onDestroy);
3093
- this.on("awarenessUpdate", this.configuration.onAwarenessUpdate);
3094
- this.on("awarenessChange", this.configuration.onAwarenessChange);
3095
- this.on("stateless", this.configuration.onStateless);
3096
- this.on("unsyncedChanges", this.configuration.onUnsyncedChanges);
3097
- this.on("authenticated", this.configuration.onAuthenticated);
3098
- this.on("authenticationFailed", this.configuration.onAuthenticationFailed);
3099
- (_a = this.awareness) === null || _a === void 0 ? void 0 : _a.on("update", () => {
3100
- this.emit("awarenessUpdate", {
3101
- states: awarenessStatesToArray(this.awareness.getStates()),
3102
- });
3103
- });
3104
- (_b = this.awareness) === null || _b === void 0 ? void 0 : _b.on("change", () => {
3105
- this.emit("awarenessChange", {
3106
- states: awarenessStatesToArray(this.awareness.getStates()),
3107
- });
3108
- });
3109
- this.document.on("update", this.boundDocumentUpdateHandler);
3110
- (_c = this.awareness) === null || _c === void 0 ? void 0 : _c.on("update", this.boundAwarenessUpdateHandler);
3111
- this.registerEventListeners();
3112
- if (this.configuration.forceSyncInterval &&
3113
- typeof this.configuration.forceSyncInterval === "number") {
3114
- this.intervals.forceSync = setInterval(this.forceSync.bind(this), this.configuration.forceSyncInterval);
3115
- }
3116
- if (this.manageSocket) {
3117
- this.attach();
3118
- }
3119
- }
3120
- setConfiguration(configuration = {}) {
3121
- if (!configuration.websocketProvider) {
3122
- this.manageSocket = true;
3123
- this.configuration.websocketProvider = new HocuspocusProviderWebsocket(configuration);
3124
- }
3125
- this.configuration = { ...this.configuration, ...configuration };
3126
- }
3127
- get document() {
3128
- return this.configuration.document;
3129
- }
3130
- get isAttached() {
3131
- return this._isAttached;
3132
- }
455
+ /**
456
+ * WebSocket sync provider for real-time collaboration
457
+ */
458
+ class WebSocketSyncProvider {
459
+ type = 'network';
460
+ provider;
461
+ isConnected = false;
462
+ _quiet = false;
3133
463
  get awareness() {
3134
- return this.configuration.awareness;
3135
- }
3136
- get hasUnsyncedChanges() {
3137
- return this.unsyncedChanges > 0;
3138
- }
3139
- resetUnsyncedChanges() {
3140
- this.unsyncedChanges = 1;
3141
- this.emit("unsyncedChanges", { number: this.unsyncedChanges });
3142
- }
3143
- incrementUnsyncedChanges() {
3144
- this.unsyncedChanges += 1;
3145
- this.emit("unsyncedChanges", { number: this.unsyncedChanges });
3146
- }
3147
- decrementUnsyncedChanges() {
3148
- if (this.unsyncedChanges > 0) {
3149
- this.unsyncedChanges -= 1;
3150
- }
3151
- if (this.unsyncedChanges === 0) {
3152
- this.synced = true;
3153
- }
3154
- this.emit("unsyncedChanges", { number: this.unsyncedChanges });
464
+ return this.provider.awareness;
3155
465
  }
3156
- forceSync() {
3157
- this.resetUnsyncedChanges();
3158
- this.send(SyncStepOneMessage, {
3159
- document: this.document,
3160
- documentName: this.configuration.name,
466
+ constructor(docName, doc, options) {
467
+ const url = options?.url || 'ws://localhost:1234';
468
+ const roomName = options?.roomName || docName;
469
+ this.provider = new yWebsocket.WebsocketProvider(url, roomName, doc, {
470
+ params: options?.params,
471
+ protocols: options?.protocols,
472
+ WebSocketPolyfill: options?.WebSocketPolyfill,
473
+ awareness: options?.awareness,
474
+ maxBackoffTime: options?.maxBackoffTime,
475
+ disableBc: true,
3161
476
  });
3162
- }
3163
- pageHide() {
3164
- if (this.awareness) {
3165
- removeAwarenessStates(this.awareness, [this.document.clientID], "page hide");
477
+ this._quiet = options?.quiet ?? false;
478
+ this.setupEventListeners();
479
+ if (!this._quiet) {
480
+ console.info(`WebSocket Provider initialized: ${url}/${roomName}`);
3166
481
  }
3167
482
  }
3168
- registerEventListeners() {
3169
- if (typeof window === "undefined" || !("addEventListener" in window)) {
3170
- return;
3171
- }
3172
- window.addEventListener("pagehide", this.boundPageHide);
483
+ /**
484
+ * Static factory method for creating WebSocketSyncProvider with configuration options
485
+ * Returns a ProviderFactory that can be used in sync configuration
486
+ */
487
+ static with(options) {
488
+ return {
489
+ create: (docName, doc, runtimeOptions) => {
490
+ const mergedOptions = runtimeOptions ? { ...options, ...runtimeOptions } : options;
491
+ return new WebSocketSyncProvider(docName, doc, mergedOptions);
492
+ },
493
+ };
3173
494
  }
3174
- sendStateless(payload) {
3175
- this.send(StatelessMessage, {
3176
- documentName: this.configuration.name,
3177
- payload,
495
+ setupEventListeners() {
496
+ this.provider.on('status', ({ status }) => {
497
+ if (status === 'connected') {
498
+ this.isConnected = true;
499
+ if (!this._quiet) {
500
+ console.info('WebSocket connected');
501
+ }
502
+ }
503
+ else if (status === 'disconnected') {
504
+ this.isConnected = false;
505
+ if (!this._quiet) {
506
+ console.info('WebSocket disconnected');
507
+ }
508
+ }
3178
509
  });
3179
- }
3180
- async sendToken() {
3181
- let token;
3182
- try {
3183
- token = await this.getToken();
3184
- }
3185
- catch (error) {
3186
- this.permissionDeniedHandler(`Failed to get token during sendToken(): ${error}`);
3187
- return;
3188
- }
3189
- this.send(AuthenticationMessage, {
3190
- token: token !== null && token !== void 0 ? token : "",
3191
- documentName: this.configuration.name,
510
+ this.provider.on('sync', (synced) => {
511
+ if (synced && !this._quiet) {
512
+ console.info('WebSocket synced');
513
+ }
3192
514
  });
3193
515
  }
3194
- documentUpdateHandler(update, origin) {
3195
- if (origin === this) {
516
+ async connect() {
517
+ if (this.isConnected) {
3196
518
  return;
3197
519
  }
3198
- this.incrementUnsyncedChanges();
3199
- this.send(UpdateMessage, { update, documentName: this.configuration.name });
3200
- }
3201
- awarenessUpdateHandler({ added, updated, removed }, origin) {
3202
- const changedClients = added.concat(updated).concat(removed);
3203
- this.send(AwarenessMessage, {
3204
- awareness: this.awareness,
3205
- clients: changedClients,
3206
- documentName: this.configuration.name,
520
+ return new Promise((resolve, reject) => {
521
+ const timeout = setTimeout(() => {
522
+ reject(new Error('WebSocket connection timeout'));
523
+ }, 10000); // 10 second timeout
524
+ const statusHandler = ({ status }) => {
525
+ if (status === 'connected') {
526
+ clearTimeout(timeout);
527
+ this.provider.off('status', statusHandler);
528
+ this.isConnected = true;
529
+ resolve();
530
+ }
531
+ };
532
+ this.provider.on('status', statusHandler);
533
+ // If already connected, resolve immediately
534
+ if (this.provider.wsconnected) {
535
+ clearTimeout(timeout);
536
+ this.provider.off('status', statusHandler);
537
+ this.isConnected = true;
538
+ resolve();
539
+ }
3207
540
  });
3208
541
  }
3209
- /**
3210
- * Indicates whether a first handshake with the server has been established
3211
- *
3212
- * Note: this does not mean all updates from the client have been persisted to the backend. For this,
3213
- * use `hasUnsyncedChanges`.
3214
- */
3215
- get synced() {
3216
- return this.isSynced;
3217
- }
3218
- set synced(state) {
3219
- if (this.isSynced === state) {
3220
- return;
3221
- }
3222
- this.isSynced = state;
3223
- if (state) {
3224
- this.emit("synced", { state });
3225
- }
3226
- }
3227
- receiveStateless(payload) {
3228
- this.emit("stateless", { payload });
3229
- }
3230
- // not needed, but provides backward compatibility with e.g. lexical/yjs
3231
- async connect() {
3232
- if (this.manageSocket) {
3233
- return this.configuration.websocketProvider.connect();
3234
- }
3235
- console.warn("HocuspocusProvider::connect() is deprecated and does not do anything. Please connect/disconnect on the websocketProvider, or attach/deattach providers.");
3236
- }
3237
542
  disconnect() {
3238
- if (this.manageSocket) {
3239
- return this.configuration.websocketProvider.disconnect();
3240
- }
3241
- console.warn("HocuspocusProvider::disconnect() is deprecated and does not do anything. Please connect/disconnect on the websocketProvider, or attach/deattach providers.");
3242
- }
3243
- async onOpen(event) {
3244
- this.isAuthenticated = false;
3245
- this.emit("open", { event });
3246
- await this.sendToken();
3247
- this.startSync();
3248
- }
3249
- async getToken() {
3250
- if (typeof this.configuration.token === "function") {
3251
- const token = await this.configuration.token();
3252
- return token;
3253
- }
3254
- return this.configuration.token;
3255
- }
3256
- startSync() {
3257
- this.resetUnsyncedChanges();
3258
- this.send(SyncStepOneMessage, {
3259
- document: this.document,
3260
- documentName: this.configuration.name,
3261
- });
3262
- if (this.awareness && this.awareness.getLocalState() !== null) {
3263
- this.send(AwarenessMessage, {
3264
- awareness: this.awareness,
3265
- clients: [this.document.clientID],
3266
- documentName: this.configuration.name,
3267
- });
543
+ if (this.provider) {
544
+ this.provider.disconnect();
3268
545
  }
546
+ this.isConnected = false;
3269
547
  }
3270
- send(message, args) {
3271
- if (!this._isAttached)
3272
- return;
3273
- const messageSender = new MessageSender(message, args);
3274
- this.emit("outgoingMessage", { message: messageSender.message });
3275
- messageSender.send(this.configuration.websocketProvider);
3276
- }
3277
- onMessage(event) {
3278
- const message = new IncomingMessage(event.data);
3279
- const documentName = message.readVarString();
3280
- message.writeVarString(documentName);
3281
- this.emit("message", { event, message: new IncomingMessage(event.data) });
3282
- new MessageReceiver(message).apply(this, true);
3283
- }
3284
- onClose() {
3285
- this.isAuthenticated = false;
3286
- this.synced = false;
3287
- // update awareness (all users except local left)
3288
- if (this.awareness) {
3289
- removeAwarenessStates(this.awareness, Array.from(this.awareness.getStates().keys()).filter((client) => client !== this.document.clientID), this);
3290
- }
548
+ async reconnect() {
549
+ this.disconnect();
550
+ return this.connect();
3291
551
  }
3292
552
  destroy() {
3293
- this.emit("destroy");
3294
- if (this.intervals.forceSync) {
3295
- clearInterval(this.intervals.forceSync);
3296
- }
3297
- if (this.awareness) {
3298
- removeAwarenessStates(this.awareness, [this.document.clientID], "provider destroy");
3299
- this.awareness.off("update", this.boundAwarenessUpdateHandler);
3300
- this.awareness.destroy();
3301
- }
3302
- this.document.off("update", this.boundDocumentUpdateHandler);
3303
- this.removeAllListeners();
3304
- this.detach();
3305
- if (this.manageSocket) {
3306
- this.configuration.websocketProvider.destroy();
3307
- }
3308
- if (typeof window === "undefined" || !("removeEventListener" in window)) {
3309
- return;
3310
- }
3311
- window.removeEventListener("pagehide", this.boundPageHide);
3312
- }
3313
- detach() {
3314
- this.configuration.websocketProvider.off("connect", this.configuration.onConnect);
3315
- this.configuration.websocketProvider.off("connect", this.forwardConnect);
3316
- this.configuration.websocketProvider.off("status", this.forwardStatus);
3317
- this.configuration.websocketProvider.off("status", this.configuration.onStatus);
3318
- this.configuration.websocketProvider.off("open", this.boundOnOpen);
3319
- this.configuration.websocketProvider.off("close", this.boundOnClose);
3320
- this.configuration.websocketProvider.off("close", this.configuration.onClose);
3321
- this.configuration.websocketProvider.off("close", this.forwardClose);
3322
- this.configuration.websocketProvider.off("disconnect", this.configuration.onDisconnect);
3323
- this.configuration.websocketProvider.off("disconnect", this.forwardDisconnect);
3324
- this.configuration.websocketProvider.off("destroy", this.configuration.onDestroy);
3325
- this.configuration.websocketProvider.off("destroy", this.forwardDestroy);
3326
- this.configuration.websocketProvider.detach(this);
3327
- this._isAttached = false;
3328
- }
3329
- attach() {
3330
- if (this._isAttached)
3331
- return;
3332
- this.configuration.websocketProvider.on("connect", this.configuration.onConnect);
3333
- this.configuration.websocketProvider.on("connect", this.forwardConnect);
3334
- this.configuration.websocketProvider.on("status", this.configuration.onStatus);
3335
- this.configuration.websocketProvider.on("status", this.forwardStatus);
3336
- this.configuration.websocketProvider.on("open", this.boundOnOpen);
3337
- this.configuration.websocketProvider.on("close", this.boundOnClose);
3338
- this.configuration.websocketProvider.on("close", this.configuration.onClose);
3339
- this.configuration.websocketProvider.on("close", this.forwardClose);
3340
- this.configuration.websocketProvider.on("disconnect", this.configuration.onDisconnect);
3341
- this.configuration.websocketProvider.on("disconnect", this.forwardDisconnect);
3342
- this.configuration.websocketProvider.on("destroy", this.configuration.onDestroy);
3343
- this.configuration.websocketProvider.on("destroy", this.forwardDestroy);
3344
- this.configuration.websocketProvider.attach(this);
3345
- this._isAttached = true;
3346
- }
3347
- permissionDeniedHandler(reason) {
3348
- this.emit("authenticationFailed", { reason });
3349
- this.isAuthenticated = false;
3350
- }
3351
- authenticatedHandler(scope) {
3352
- this.isAuthenticated = true;
3353
- this.authorizedScope = scope;
3354
- this.emit("authenticated", { scope });
3355
- }
3356
- setAwarenessField(key, value) {
3357
- if (!this.awareness) {
3358
- throw new AwarenessError(`Cannot set awareness field "${key}" to ${JSON.stringify(value)}. You have disabled Awareness for this provider by explicitly passing awareness: null in the provider configuration.`);
553
+ if (this.provider) {
554
+ this.provider.destroy();
3359
555
  }
3360
- this.awareness.setLocalStateField(key, value);
556
+ this.isConnected = false;
3361
557
  }
3362
558
  }
3363
559
 
@@ -3476,7 +672,7 @@ class HocuspocusSyncProvider {
3476
672
  if (options?.onAuthenticationFailed) {
3477
673
  config.onAuthenticationFailed = options.onAuthenticationFailed;
3478
674
  }
3479
- this.provider = new HocuspocusProvider(config);
675
+ this.provider = new workspace_migrations.HocuspocusProvider(config);
3480
676
  // Must call attach() explicitly when using shared socket
3481
677
  this.provider.attach();
3482
678
  if (!options?.quiet) {
@@ -3508,7 +704,7 @@ class HocuspocusSyncProvider {
3508
704
  if (options?.WebSocketPolyfill) {
3509
705
  config.WebSocketPolyfill = options.WebSocketPolyfill;
3510
706
  }
3511
- this.provider = new HocuspocusProvider(config);
707
+ this.provider = new workspace_migrations.HocuspocusProvider(config);
3512
708
  if (!options?.quiet) {
3513
709
  console.info(`Hocuspocus Provider initialized: ${url}/${name}`);
3514
710
  }
@@ -3567,7 +763,7 @@ class HocuspocusSyncProvider {
3567
763
  if (options.onStatus) {
3568
764
  config.onStatus = options.onStatus;
3569
765
  }
3570
- HocuspocusSyncProvider.sharedWebSocketProvider = new HocuspocusProviderWebsocket(config);
766
+ HocuspocusSyncProvider.sharedWebSocketProvider = new workspace_migrations.HocuspocusProviderWebsocket(config);
3571
767
  console.info(`Shared Hocuspocus WebSocket created: ${options.url}`);
3572
768
  return HocuspocusSyncProvider.sharedWebSocketProvider;
3573
769
  }
@@ -3711,7 +907,9 @@ class HttpAssetProvider {
3711
907
  return { create: () => new HttpAssetProvider(options) };
3712
908
  }
3713
909
  async init() {
3714
- // No initialization needed for a stateless HTTP provider.
910
+ if (!this._options.quiet) {
911
+ console.info('HttpAssetProvider initialized');
912
+ }
3715
913
  }
3716
914
  destroy() {
3717
915
  // No-op; no resources to release.
@@ -3760,6 +958,9 @@ class HttpAssetProvider {
3760
958
  if (!res.ok) {
3761
959
  throw new Error(`[HttpAssetProvider] Failed to delete asset ${id}: ${res.status} ${res.statusText}`);
3762
960
  }
961
+ if (!this._options.quiet) {
962
+ console.info(`HttpAssetProvider: deleted asset ${id}`);
963
+ }
3763
964
  }
3764
965
  defaultUpload = async (url, blob, metadata, headers) => {
3765
966
  const form = new FormData();
@@ -3814,7 +1015,9 @@ class PresignedAssetProvider {
3814
1015
  return { create: () => new PresignedAssetProvider(options) };
3815
1016
  }
3816
1017
  async init() {
3817
- // Stateless provider.
1018
+ if (!this._options.quiet) {
1019
+ console.info('PresignedAssetProvider initialized');
1020
+ }
3818
1021
  }
3819
1022
  destroy() {
3820
1023
  // No-op.
@@ -3875,22 +1078,16 @@ class PresignedAssetProvider {
3875
1078
  if (!this._options.deleteAsset)
3876
1079
  return;
3877
1080
  await this._options.deleteAsset(id);
1081
+ if (!this._options.quiet) {
1082
+ console.info(`PresignedAssetProvider: deleted asset ${id}`);
1083
+ }
3878
1084
  }
3879
1085
  }
3880
1086
 
3881
- /**
3882
- * Default asset storage configuration. Stores bytes in IndexedDB only,
3883
- * which provides offline-friendly behavior out of the box. Applications
3884
- * that sync Yjs over the network should also configure a remote provider
3885
- * (e.g. HttpAssetProvider) so images are available across devices.
3886
- */
3887
- const DEFAULT_ASSET_STORAGE_CONFIG = {
3888
- providers: [workspace_migrations.IndexedDBAssetProvider],
3889
- };
3890
-
3891
1087
  exports.APP_STATE_MIGRATIONS = workspace_migrations.APP_STATE_MIGRATIONS;
3892
1088
  exports.CURRENT_APP_STATE_SCHEMA_VERSION = workspace_migrations.CURRENT_APP_STATE_SCHEMA_VERSION;
3893
1089
  exports.CURRENT_WORKSPACE_SCHEMA_VERSION = workspace_migrations.CURRENT_WORKSPACE_SCHEMA_VERSION;
1090
+ exports.DEFAULT_ASSET_STORAGE_CONFIG = workspace_migrations.DEFAULT_ASSET_STORAGE_CONFIG;
3894
1091
  exports.DEFAULT_BRUSH_CONFIG = workspace_migrations.DEFAULT_BRUSH_CONFIG;
3895
1092
  exports.DEFAULT_LINE_TOOL_CONFIG = workspace_migrations.DEFAULT_LINE_TOOL_CONFIG;
3896
1093
  exports.DEFAULT_TEXT_CONFIG = workspace_migrations.DEFAULT_TEXT_CONFIG;
@@ -3928,7 +1125,6 @@ exports.darkTheme = workspace_migrations.darkTheme;
3928
1125
  exports.lightTheme = workspace_migrations.lightTheme;
3929
1126
  exports.runMigrations = workspace_migrations.runMigrations;
3930
1127
  exports.BroadcastSyncProvider = BroadcastSyncProvider;
3931
- exports.DEFAULT_ASSET_STORAGE_CONFIG = DEFAULT_ASSET_STORAGE_CONFIG;
3932
1128
  exports.HocuspocusSyncProvider = HocuspocusSyncProvider;
3933
1129
  exports.HttpAssetProvider = HttpAssetProvider;
3934
1130
  exports.PresignedAssetProvider = PresignedAssetProvider;