@liveblocks/core 2.15.1 → 2.16.0-rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ var __export = (target, all) => {
6
6
 
7
7
  // src/version.ts
8
8
  var PKG_NAME = "@liveblocks/core";
9
- var PKG_VERSION = "2.15.1";
9
+ var PKG_VERSION = "2.16.0-rc1";
10
10
  var PKG_FORMAT = "cjs";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -166,13 +166,18 @@ function wrapWithTitle(method) {
166
166
  var warnWithTitle = wrapWithTitle("warn");
167
167
  var errorWithTitle = wrapWithTitle("error");
168
168
 
169
+ // src/lib/guards.ts
170
+ function isPlainObject(blob) {
171
+ return blob !== null && typeof blob === "object" && Object.prototype.toString.call(blob) === "[object Object]";
172
+ }
173
+ function isStartsWithOperator(blob) {
174
+ return isPlainObject(blob) && typeof blob.startsWith === "string";
175
+ }
176
+
169
177
  // src/lib/utils.ts
170
178
  function raise(msg) {
171
179
  throw new Error(msg);
172
180
  }
173
- function isPlainObject(blob) {
174
- return blob !== null && typeof blob === "object" && Object.prototype.toString.call(blob) === "[object Object]";
175
- }
176
181
  function entries(obj) {
177
182
  return Object.entries(obj);
178
183
  }
@@ -254,13 +259,48 @@ function memoizeOnSuccess(factoryFn) {
254
259
  }
255
260
 
256
261
  // src/lib/autoRetry.ts
257
- var HttpError = class extends Error {
258
- constructor(message, status, details) {
262
+ var HttpError = class _HttpError extends Error {
263
+
264
+
265
+ constructor(message, response, details) {
259
266
  super(message);
260
- this.message = message;
261
- this.status = status;
267
+ this.name = "HttpError";
268
+ this.response = response;
262
269
  this.details = details;
263
270
  }
271
+ static async fromResponse(response) {
272
+ let bodyAsText;
273
+ try {
274
+ bodyAsText = await response.text();
275
+ } catch (e2) {
276
+ }
277
+ const bodyAsJson = bodyAsText ? tryParseJson(bodyAsText) : void 0;
278
+ let bodyAsJsonObject;
279
+ if (isPlainObject(bodyAsJson)) {
280
+ bodyAsJsonObject = bodyAsJson;
281
+ }
282
+ let message = "";
283
+ message ||= typeof _optionalChain([bodyAsJsonObject, 'optionalAccess', _2 => _2.message]) === "string" ? bodyAsJsonObject.message : "";
284
+ message ||= typeof _optionalChain([bodyAsJsonObject, 'optionalAccess', _3 => _3.error]) === "string" ? bodyAsJsonObject.error : "";
285
+ if (bodyAsJson === void 0) {
286
+ message ||= bodyAsText || "";
287
+ }
288
+ message ||= response.statusText;
289
+ let path;
290
+ try {
291
+ path = new URL(response.url).pathname;
292
+ } catch (e3) {
293
+ }
294
+ message += path !== void 0 ? ` (got status ${response.status} from ${path})` : ` (got status ${response.status})`;
295
+ const details = bodyAsJsonObject;
296
+ return new _HttpError(message, response, details);
297
+ }
298
+ /**
299
+ * Convenience accessor for response.status.
300
+ */
301
+ get status() {
302
+ return this.response.status;
303
+ }
264
304
  };
265
305
  var DONT_RETRY_4XX = (x) => x instanceof HttpError && x.status >= 400 && x.status < 500;
266
306
  async function autoRetry(promiseFn, maxTries, backoff, shouldStopRetrying = DONT_RETRY_4XX) {
@@ -323,10 +363,15 @@ function makeEventSource() {
323
363
  res(event);
324
364
  }
325
365
  });
326
- }).finally(() => _optionalChain([unsub, 'optionalCall', _2 => _2()]));
366
+ }).finally(() => _optionalChain([unsub, 'optionalCall', _4 => _4()]));
327
367
  }
328
368
  function notify(event) {
329
- _observers.forEach((callback) => callback(event));
369
+ let called = false;
370
+ for (const callback of _observers) {
371
+ callback(event);
372
+ called = true;
373
+ }
374
+ return called;
330
375
  }
331
376
  function count() {
332
377
  return _observers.size;
@@ -367,8 +412,9 @@ function makeBufferableEventSource() {
367
412
  function notifyOrBuffer(event) {
368
413
  if (_buffer !== null) {
369
414
  _buffer.push(event);
415
+ return false;
370
416
  } else {
371
- eventSource2.notify(event);
417
+ return eventSource2.notify(event);
372
418
  }
373
419
  }
374
420
  return {
@@ -385,173 +431,457 @@ function makeBufferableEventSource() {
385
431
  };
386
432
  }
387
433
 
388
- // src/lib/stringify.ts
389
- function stringify(object, ...args) {
390
- if (typeof object !== "object" || object === null || Array.isArray(object)) {
391
- return JSON.stringify(object, ...args);
392
- }
393
- const sortedObject = Object.keys(object).sort().reduce(
394
- (sortedObject2, key) => {
395
- sortedObject2[key] = object[key];
396
- return sortedObject2;
397
- },
398
- {}
399
- );
400
- return JSON.stringify(sortedObject, ...args);
401
- }
434
+ // src/lib/freeze.ts
435
+ var freeze = process.env.NODE_ENV === "production" ? (
436
+ /* istanbul ignore next */
437
+ (x) => x
438
+ ) : Object.freeze;
402
439
 
403
- // src/lib/batch.ts
404
- var DEFAULT_SIZE = 50;
405
- var BatchCall = class {
406
-
407
-
440
+ // src/lib/signals.ts
441
+ var kSinks = Symbol("kSinks");
442
+ var kTrigger = Symbol("kTrigger");
443
+ var signalsToTrigger = null;
444
+ var trackedReads = null;
445
+ function batch(callback) {
446
+ if (signalsToTrigger !== null) {
447
+ callback();
448
+ return;
449
+ }
450
+ signalsToTrigger = /* @__PURE__ */ new Set();
451
+ try {
452
+ callback();
453
+ } finally {
454
+ for (const signal of signalsToTrigger) {
455
+ signal[kTrigger]();
456
+ }
457
+ signalsToTrigger = null;
458
+ }
459
+ }
460
+ function enqueueTrigger(signal) {
461
+ if (!signalsToTrigger) raise("Expected to be in an active batch");
462
+ signalsToTrigger.add(signal);
463
+ }
464
+ function merge(target, patch) {
465
+ let updated = false;
466
+ const newValue = { ...target };
467
+ Object.keys(patch).forEach((k) => {
468
+ const key = k;
469
+ const val = patch[key];
470
+ if (newValue[key] !== val) {
471
+ if (val === void 0) {
472
+ delete newValue[key];
473
+ } else {
474
+ newValue[key] = val;
475
+ }
476
+ updated = true;
477
+ }
478
+ });
479
+ return updated ? newValue : target;
480
+ }
481
+ var AbstractSignal = class {
482
+ /** @internal */
408
483
 
484
+ #eventSource;
485
+ /** @internal */
409
486
 
410
- constructor(input) {
411
- this.input = input;
412
- const { promise, resolve, reject } = Promise_withResolvers();
413
- this.promise = promise;
414
- this.resolve = resolve;
415
- this.reject = reject;
487
+ constructor(equals) {
488
+ this.equals = _nullishCoalesce(equals, () => ( Object.is));
489
+ this.#eventSource = makeEventSource();
490
+ this[kSinks] = /* @__PURE__ */ new Set();
491
+ this.get = this.get.bind(this);
492
+ this.subscribe = this.subscribe.bind(this);
493
+ this.subscribeOnce = this.subscribeOnce.bind(this);
416
494
  }
417
- };
418
- var Batch = (_class = class {
419
- #queue = [];
420
- #callback;
421
- #size;
422
- #delay;
423
- #delayTimeoutId;
424
- __init() {this.error = false}
425
- constructor(callback, options) {;_class.prototype.__init.call(this);
426
- this.#callback = callback;
427
- this.#size = _nullishCoalesce(options.size, () => ( DEFAULT_SIZE));
428
- this.#delay = options.delay;
495
+ [Symbol.dispose]() {
496
+ this.#eventSource[Symbol.dispose]();
497
+ this.#eventSource = "(disposed)";
498
+ this.equals = "(disposed)";
429
499
  }
430
- #clearDelayTimeout() {
431
- if (this.#delayTimeoutId !== void 0) {
432
- clearTimeout(this.#delayTimeoutId);
433
- this.#delayTimeoutId = void 0;
500
+ get hasWatchers() {
501
+ if (this.#eventSource.count() > 0) return true;
502
+ for (const sink of this[kSinks]) {
503
+ if (sink.hasWatchers) {
504
+ return true;
505
+ }
434
506
  }
507
+ return false;
435
508
  }
436
- #schedule() {
437
- if (this.#queue.length === this.#size) {
438
- void this.#flush();
439
- } else if (this.#queue.length === 1) {
440
- this.#clearDelayTimeout();
441
- this.#delayTimeoutId = setTimeout(() => void this.#flush(), this.#delay);
509
+ [kTrigger]() {
510
+ this.#eventSource.notify();
511
+ for (const sink of this[kSinks]) {
512
+ enqueueTrigger(sink);
442
513
  }
443
514
  }
444
- async #flush() {
445
- if (this.#queue.length === 0) {
446
- return;
447
- }
448
- const calls = this.#queue.splice(0);
449
- const inputs = calls.map((call) => call.input);
450
- try {
451
- const results = await this.#callback(inputs);
452
- this.error = false;
453
- calls.forEach((call, index) => {
454
- const result = _optionalChain([results, 'optionalAccess', _3 => _3[index]]);
455
- if (!Array.isArray(results)) {
456
- call.reject(new Error("Callback must return an array."));
457
- } else if (calls.length !== results.length) {
458
- call.reject(
459
- new Error(
460
- `Callback must return an array of the same length as the number of provided items. Expected ${calls.length}, but got ${results.length}.`
461
- )
462
- );
463
- } else if (result instanceof Error) {
464
- call.reject(result);
465
- } else {
466
- call.resolve(result);
467
- }
468
- });
469
- } catch (error3) {
470
- this.error = true;
471
- calls.forEach((call) => {
472
- call.reject(error3);
473
- });
515
+ subscribe(callback) {
516
+ if (this.#eventSource.count() === 0) {
517
+ this.get();
474
518
  }
519
+ return this.#eventSource.subscribe(callback);
475
520
  }
476
- get(input) {
477
- const existingCall = this.#queue.find(
478
- (call2) => stringify(call2.input) === stringify(input)
479
- );
480
- if (existingCall) {
481
- return existingCall.promise;
521
+ subscribeOnce(callback) {
522
+ const unsub = this.subscribe(() => {
523
+ unsub();
524
+ return callback();
525
+ });
526
+ return unsub;
527
+ }
528
+ waitUntil() {
529
+ throw new Error("waitUntil not supported on Signals");
530
+ }
531
+ markSinksDirty() {
532
+ for (const sink of this[kSinks]) {
533
+ sink.markDirty();
482
534
  }
483
- const call = new BatchCall(input);
484
- this.#queue.push(call);
485
- this.#schedule();
486
- return call.promise;
487
535
  }
488
- clear() {
489
- this.#queue = [];
490
- this.error = false;
491
- this.#clearDelayTimeout();
536
+ addSink(sink) {
537
+ this[kSinks].add(sink);
492
538
  }
493
- }, _class);
494
- function createBatchStore(batch2) {
495
- const cache = /* @__PURE__ */ new Map();
496
- const eventSource2 = makeEventSource();
497
- function getCacheKey(args) {
498
- return stringify(args);
539
+ removeSink(sink) {
540
+ this[kSinks].delete(sink);
499
541
  }
500
- function setStateAndNotify(cacheKey, state) {
501
- cache.set(cacheKey, state);
502
- eventSource2.notify();
542
+ asReadonly() {
543
+ return this;
503
544
  }
504
- function invalidate(inputs) {
505
- if (Array.isArray(inputs)) {
506
- for (const input of inputs) {
507
- cache.delete(getCacheKey(input));
508
- }
509
- } else {
510
- cache.clear();
511
- }
512
- eventSource2.notify();
545
+ };
546
+ var Signal = class extends AbstractSignal {
547
+ #value;
548
+ constructor(value, equals) {
549
+ super(equals);
550
+ this.#value = freeze(value);
513
551
  }
514
- async function get(input) {
515
- const cacheKey = getCacheKey(input);
516
- if (cache.has(cacheKey)) {
517
- return;
518
- }
519
- try {
520
- setStateAndNotify(cacheKey, { isLoading: true });
521
- const result = await batch2.get(input);
522
- setStateAndNotify(cacheKey, { isLoading: false, data: result });
523
- } catch (error3) {
524
- setStateAndNotify(cacheKey, {
525
- isLoading: false,
526
- error: error3
527
- });
528
- }
552
+ [Symbol.dispose]() {
553
+ super[Symbol.dispose]();
554
+ this.#value = "(disposed)";
529
555
  }
530
- function getState(input) {
531
- const cacheKey = getCacheKey(input);
532
- return cache.get(cacheKey);
556
+ get() {
557
+ _optionalChain([trackedReads, 'optionalAccess', _5 => _5.add, 'call', _6 => _6(this)]);
558
+ return this.#value;
533
559
  }
534
- function _cacheKeys() {
535
- return [...cache.keys()];
560
+ set(newValue) {
561
+ batch(() => {
562
+ if (typeof newValue === "function") {
563
+ newValue = newValue(this.#value);
564
+ }
565
+ if (!this.equals(this.#value, newValue)) {
566
+ this.#value = freeze(newValue);
567
+ this.markSinksDirty();
568
+ enqueueTrigger(this);
569
+ }
570
+ });
536
571
  }
537
- function getBatch() {
538
- return batch2;
572
+ };
573
+ var PatchableSignal = class extends Signal {
574
+ constructor(data) {
575
+ super(freeze(compactObject(data)));
539
576
  }
540
- return {
541
- ...eventSource2.observable,
542
- get,
543
- getState,
544
- invalidate,
545
- getBatch,
546
- _cacheKeys
547
- };
548
- }
549
-
550
- // src/lib/chunk.ts
551
- function chunk(array, size) {
552
- const chunks = [];
553
- for (let i = 0, j = array.length; i < j; i += size) {
554
- chunks.push(array.slice(i, i + size));
577
+ set() {
578
+ throw new Error("Don't call .set() directly, use .patch()");
579
+ }
580
+ /**
581
+ * Patches the current object.
582
+ */
583
+ patch(patch) {
584
+ super.set((old) => merge(old, patch));
585
+ }
586
+ };
587
+ var INITIAL = Symbol();
588
+ var DerivedSignal = class _DerivedSignal extends AbstractSignal {
589
+ #prevValue;
590
+ #dirty;
591
+ // When true, the value in #value may not be up-to-date and needs re-checking
592
+ #sources;
593
+ #deps;
594
+ #transform;
595
+ // prettier-ignore
596
+ static from(...args) {
597
+ const last = args.pop();
598
+ if (typeof last !== "function")
599
+ raise("Invalid .from() call, last argument expected to be a function");
600
+ if (typeof args[args.length - 1] === "function") {
601
+ const equals = last;
602
+ const transform = args.pop();
603
+ return new _DerivedSignal(args, transform, equals);
604
+ } else {
605
+ const transform = last;
606
+ return new _DerivedSignal(args, transform);
607
+ }
608
+ }
609
+ constructor(deps, transform, equals) {
610
+ super(equals);
611
+ this.#dirty = true;
612
+ this.#prevValue = INITIAL;
613
+ this.#deps = deps;
614
+ this.#sources = /* @__PURE__ */ new Set();
615
+ this.#transform = transform;
616
+ }
617
+ [Symbol.dispose]() {
618
+ for (const src of this.#sources) {
619
+ src.removeSink(this);
620
+ }
621
+ this.#prevValue = "(disposed)";
622
+ this.#sources = "(disposed)";
623
+ this.#deps = "(disposed)";
624
+ this.#transform = "(disposed)";
625
+ }
626
+ get isDirty() {
627
+ return this.#dirty;
628
+ }
629
+ #recompute() {
630
+ const oldTrackedReads = trackedReads;
631
+ let derived;
632
+ trackedReads = /* @__PURE__ */ new Set();
633
+ try {
634
+ derived = this.#transform(...this.#deps.map((p) => p.get()));
635
+ } finally {
636
+ const oldSources = this.#sources;
637
+ this.#sources = /* @__PURE__ */ new Set();
638
+ for (const sig of trackedReads) {
639
+ this.#sources.add(sig);
640
+ oldSources.delete(sig);
641
+ }
642
+ for (const oldSource of oldSources) {
643
+ oldSource.removeSink(this);
644
+ }
645
+ for (const newSource of this.#sources) {
646
+ newSource.addSink(this);
647
+ }
648
+ trackedReads = oldTrackedReads;
649
+ }
650
+ this.#dirty = false;
651
+ if (!this.equals(this.#prevValue, derived)) {
652
+ this.#prevValue = derived;
653
+ return true;
654
+ }
655
+ return false;
656
+ }
657
+ markDirty() {
658
+ if (!this.#dirty) {
659
+ this.#dirty = true;
660
+ this.markSinksDirty();
661
+ }
662
+ }
663
+ get() {
664
+ if (this.#dirty) {
665
+ this.#recompute();
666
+ }
667
+ _optionalChain([trackedReads, 'optionalAccess', _7 => _7.add, 'call', _8 => _8(this)]);
668
+ return this.#prevValue;
669
+ }
670
+ /**
671
+ * Called by the Signal system if one or more of the dependent signals have
672
+ * changed. In the case of a DerivedSignal, we'll only want to re-evaluate
673
+ * the actual value if it's being watched, or any of their sinks are being
674
+ * watched actively.
675
+ */
676
+ [kTrigger]() {
677
+ if (!this.hasWatchers) {
678
+ return;
679
+ }
680
+ const updated = this.#recompute();
681
+ if (updated) {
682
+ super[kTrigger]();
683
+ }
684
+ }
685
+ };
686
+ var MutableSignal = class extends AbstractSignal {
687
+ #state;
688
+ constructor(initialState) {
689
+ super();
690
+ this.#state = initialState;
691
+ }
692
+ [Symbol.dispose]() {
693
+ super[Symbol.dispose]();
694
+ this.#state = "(disposed)";
695
+ }
696
+ get() {
697
+ _optionalChain([trackedReads, 'optionalAccess', _9 => _9.add, 'call', _10 => _10(this)]);
698
+ return this.#state;
699
+ }
700
+ /**
701
+ * Invokes a callback function that is allowed to mutate the given state
702
+ * value. Do not change the value outside of the callback.
703
+ *
704
+ * If the callback explicitly returns `false`, it's assumed that the state
705
+ * was not changed.
706
+ */
707
+ mutate(callback) {
708
+ batch(() => {
709
+ const result = callback ? callback(this.#state) : true;
710
+ if (result !== null && typeof result === "object" && "then" in result) {
711
+ raise("MutableSignal.mutate() does not support async callbacks");
712
+ }
713
+ if (result !== false) {
714
+ this.markSinksDirty();
715
+ enqueueTrigger(this);
716
+ }
717
+ });
718
+ }
719
+ };
720
+
721
+ // src/lib/stringify.ts
722
+ function replacer(_key, value) {
723
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? Object.keys(value).sort().reduce((sorted, key) => {
724
+ sorted[key] = value[key];
725
+ return sorted;
726
+ }, {}) : value;
727
+ }
728
+ function stringify(value) {
729
+ return JSON.stringify(value, replacer);
730
+ }
731
+
732
+ // src/lib/batch.ts
733
+ var DEFAULT_SIZE = 50;
734
+ var BatchCall = class {
735
+
736
+
737
+
738
+
739
+ constructor(input) {
740
+ this.input = input;
741
+ const { promise, resolve, reject } = Promise_withResolvers();
742
+ this.promise = promise;
743
+ this.resolve = resolve;
744
+ this.reject = reject;
745
+ }
746
+ };
747
+ var Batch = (_class = class {
748
+ #queue = [];
749
+ #callback;
750
+ #size;
751
+ #delay;
752
+ #delayTimeoutId;
753
+ __init() {this.error = false}
754
+ constructor(callback, options) {;_class.prototype.__init.call(this);
755
+ this.#callback = callback;
756
+ this.#size = _nullishCoalesce(options.size, () => ( DEFAULT_SIZE));
757
+ this.#delay = options.delay;
758
+ }
759
+ #clearDelayTimeout() {
760
+ if (this.#delayTimeoutId !== void 0) {
761
+ clearTimeout(this.#delayTimeoutId);
762
+ this.#delayTimeoutId = void 0;
763
+ }
764
+ }
765
+ #schedule() {
766
+ if (this.#queue.length === this.#size) {
767
+ void this.#flush();
768
+ } else if (this.#queue.length === 1) {
769
+ this.#clearDelayTimeout();
770
+ this.#delayTimeoutId = setTimeout(() => void this.#flush(), this.#delay);
771
+ }
772
+ }
773
+ async #flush() {
774
+ if (this.#queue.length === 0) {
775
+ return;
776
+ }
777
+ const calls = this.#queue.splice(0);
778
+ const inputs = calls.map((call) => call.input);
779
+ try {
780
+ const results = await this.#callback(inputs);
781
+ this.error = false;
782
+ calls.forEach((call, index) => {
783
+ const result = _optionalChain([results, 'optionalAccess', _11 => _11[index]]);
784
+ if (!Array.isArray(results)) {
785
+ call.reject(new Error("Callback must return an array."));
786
+ } else if (calls.length !== results.length) {
787
+ call.reject(
788
+ new Error(
789
+ `Callback must return an array of the same length as the number of provided items. Expected ${calls.length}, but got ${results.length}.`
790
+ )
791
+ );
792
+ } else if (result instanceof Error) {
793
+ call.reject(result);
794
+ } else {
795
+ call.resolve(result);
796
+ }
797
+ });
798
+ } catch (error3) {
799
+ this.error = true;
800
+ calls.forEach((call) => {
801
+ call.reject(error3);
802
+ });
803
+ }
804
+ }
805
+ get(input) {
806
+ const existingCall = this.#queue.find(
807
+ (call2) => stringify(call2.input) === stringify(input)
808
+ );
809
+ if (existingCall) {
810
+ return existingCall.promise;
811
+ }
812
+ const call = new BatchCall(input);
813
+ this.#queue.push(call);
814
+ this.#schedule();
815
+ return call.promise;
816
+ }
817
+ clear() {
818
+ this.#queue = [];
819
+ this.error = false;
820
+ this.#clearDelayTimeout();
821
+ }
822
+ }, _class);
823
+ function createBatchStore(batch2) {
824
+ const signal = new MutableSignal(/* @__PURE__ */ new Map());
825
+ function getCacheKey(args) {
826
+ return stringify(args);
827
+ }
828
+ function update(cacheKey, state) {
829
+ signal.mutate((cache) => {
830
+ cache.set(cacheKey, state);
831
+ });
832
+ }
833
+ function invalidate(inputs) {
834
+ signal.mutate((cache) => {
835
+ if (Array.isArray(inputs)) {
836
+ for (const input of inputs) {
837
+ cache.delete(getCacheKey(input));
838
+ }
839
+ } else {
840
+ cache.clear();
841
+ }
842
+ });
843
+ }
844
+ async function enqueue(input) {
845
+ const cacheKey = getCacheKey(input);
846
+ const cache = signal.get();
847
+ if (cache.has(cacheKey)) {
848
+ return;
849
+ }
850
+ try {
851
+ update(cacheKey, { isLoading: true });
852
+ const result = await batch2.get(input);
853
+ update(cacheKey, { isLoading: false, data: result });
854
+ } catch (error3) {
855
+ update(cacheKey, {
856
+ isLoading: false,
857
+ error: error3
858
+ });
859
+ }
860
+ }
861
+ function getItemState(input) {
862
+ const cacheKey = getCacheKey(input);
863
+ const cache = signal.get();
864
+ return cache.get(cacheKey);
865
+ }
866
+ function _cacheKeys() {
867
+ const cache = signal.get();
868
+ return [...cache.keys()];
869
+ }
870
+ return {
871
+ subscribe: signal.subscribe,
872
+ enqueue,
873
+ getItemState,
874
+ invalidate,
875
+ batch: batch2,
876
+ _cacheKeys
877
+ };
878
+ }
879
+
880
+ // src/lib/chunk.ts
881
+ function chunk(array, size) {
882
+ const chunks = [];
883
+ for (let i = 0, j = array.length; i < j; i += size) {
884
+ chunks.push(array.slice(i, i + size));
555
885
  }
556
886
  return chunks;
557
887
  }
@@ -583,9 +913,39 @@ function createInboxNotificationId() {
583
913
  return createOptimisticId(INBOX_NOTIFICATION_ID_PREFIX);
584
914
  }
585
915
 
586
- // src/lib/objectToQuery.ts
587
- var identifierRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
588
- function objectToQuery(obj) {
916
+ // src/lib/DefaultMap.ts
917
+ var DefaultMap = class extends Map {
918
+ #defaultFn;
919
+ /**
920
+ * If the default function is not provided to the constructor, it has to be
921
+ * provided in each .getOrCreate() call individually.
922
+ */
923
+ constructor(defaultFn, entries2) {
924
+ super(entries2);
925
+ this.#defaultFn = defaultFn;
926
+ }
927
+ /**
928
+ * Gets the value at the given key, or creates it.
929
+ *
930
+ * Difference from normal Map: if the key does not exist, it will be created
931
+ * on the fly using the factory function, and that value will get returned
932
+ * instead of `undefined`.
933
+ */
934
+ getOrCreate(key, defaultFn) {
935
+ if (super.has(key)) {
936
+ return super.get(key);
937
+ } else {
938
+ const fn = _nullishCoalesce(_nullishCoalesce(defaultFn, () => ( this.#defaultFn)), () => ( raise("DefaultMap used without a factory function")));
939
+ const value = fn(key);
940
+ this.set(key, value);
941
+ return value;
942
+ }
943
+ }
944
+ };
945
+
946
+ // src/lib/objectToQuery.ts
947
+ var identifierRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
948
+ function objectToQuery(obj) {
589
949
  let filterList = [];
590
950
  const entries2 = Object.entries(obj);
591
951
  const keyValuePairs = [];
@@ -597,10 +957,12 @@ function objectToQuery(obj) {
597
957
  }
598
958
  if (isSimpleValue(value)) {
599
959
  keyValuePairs.push([key, value]);
600
- } else if (isValueWithOperator(value)) {
601
- keyValuePairsWithOperator.push([key, value]);
602
- } else if (typeof value === "object" && !("startsWith" in value)) {
603
- indexedKeys.push([key, value]);
960
+ } else if (isPlainObject(value)) {
961
+ if (isStartsWithOperator(value)) {
962
+ keyValuePairsWithOperator.push([key, value]);
963
+ } else {
964
+ indexedKeys.push([key, value]);
965
+ }
604
966
  }
605
967
  });
606
968
  filterList = [
@@ -617,7 +979,7 @@ function objectToQuery(obj) {
617
979
  }
618
980
  if (isSimpleValue(nestedValue)) {
619
981
  nKeyValuePairs.push([formatFilterKey(key, nestedKey), nestedValue]);
620
- } else if (isValueWithOperator(nestedValue)) {
982
+ } else if (isStartsWithOperator(nestedValue)) {
621
983
  nKeyValuePairsWithOperator.push([
622
984
  formatFilterKey(key, nestedKey),
623
985
  nestedValue
@@ -630,9 +992,7 @@ function objectToQuery(obj) {
630
992
  ...getFiltersFromKeyValuePairsWithOperator(nKeyValuePairsWithOperator)
631
993
  ];
632
994
  });
633
- return filterList.map(
634
- ({ key, operator, value }) => formatFilter(key, operator, formatFilterValue(value))
635
- ).join(" AND ");
995
+ return filterList.map(({ key, operator, value }) => `${key}${operator}${quote(value)}`).join(" ");
636
996
  }
637
997
  var getFiltersFromKeyValuePairs = (keyValuePairs) => {
638
998
  const filters = [];
@@ -659,38 +1019,20 @@ var getFiltersFromKeyValuePairsWithOperator = (keyValuePairsWithOperator) => {
659
1019
  return filters;
660
1020
  };
661
1021
  var isSimpleValue = (value) => {
662
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
663
- return true;
664
- }
665
- return false;
666
- };
667
- var isValueWithOperator = (value) => {
668
- if (typeof value === "object" && value !== null && "startsWith" in value) {
669
- return true;
670
- }
671
- return false;
672
- };
673
- var formatFilter = (key, operator, value) => {
674
- return `${key}${operator}${value}`;
1022
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null;
675
1023
  };
676
1024
  var formatFilterKey = (key, nestedKey) => {
677
1025
  if (nestedKey) {
678
- return `${key}[${JSON.stringify(nestedKey)}]`;
1026
+ return `${key}[${quote(nestedKey)}]`;
679
1027
  }
680
1028
  return key;
681
1029
  };
682
- var formatFilterValue = (value) => {
683
- if (typeof value === "string") {
684
- if (isStringEmpty(value)) {
685
- throw new Error("Value cannot be empty");
686
- }
687
- return JSON.stringify(value);
688
- }
689
- return value.toString();
690
- };
691
1030
  var isStringEmpty = (value) => {
692
1031
  return !value || value.toString().trim() === "";
693
1032
  };
1033
+ function quote(value) {
1034
+ return typeof value !== "string" || value.includes("'") ? JSON.stringify(value) : `'${value}'`;
1035
+ }
694
1036
 
695
1037
  // src/lib/url.ts
696
1038
  function toURLSearchParams(params) {
@@ -948,11 +1290,11 @@ function createApiClient({
948
1290
  `Upload of attachment ${options.attachment.id} was aborted.`,
949
1291
  "AbortError"
950
1292
  ) : void 0;
951
- if (_optionalChain([abortSignal, 'optionalAccess', _4 => _4.aborted])) {
1293
+ if (_optionalChain([abortSignal, 'optionalAccess', _12 => _12.aborted])) {
952
1294
  throw abortError;
953
1295
  }
954
1296
  const handleRetryError = (err) => {
955
- if (_optionalChain([abortSignal, 'optionalAccess', _5 => _5.aborted])) {
1297
+ if (_optionalChain([abortSignal, 'optionalAccess', _13 => _13.aborted])) {
956
1298
  throw abortError;
957
1299
  }
958
1300
  if (err instanceof HttpError && err.status === 413) {
@@ -1024,7 +1366,7 @@ function createApiClient({
1024
1366
  try {
1025
1367
  uploadId = createMultiPartUpload.uploadId;
1026
1368
  const parts = splitFileIntoParts(attachment.file);
1027
- if (_optionalChain([abortSignal, 'optionalAccess', _6 => _6.aborted])) {
1369
+ if (_optionalChain([abortSignal, 'optionalAccess', _14 => _14.aborted])) {
1028
1370
  throw abortError;
1029
1371
  }
1030
1372
  const batches = chunk(parts, 5);
@@ -1051,7 +1393,7 @@ function createApiClient({
1051
1393
  }
1052
1394
  uploadedParts.push(...await Promise.all(uploadedPartsPromises));
1053
1395
  }
1054
- if (_optionalChain([abortSignal, 'optionalAccess', _7 => _7.aborted])) {
1396
+ if (_optionalChain([abortSignal, 'optionalAccess', _15 => _15.aborted])) {
1055
1397
  throw abortError;
1056
1398
  }
1057
1399
  const sortedUploadedParts = uploadedParts.sort(
@@ -1067,7 +1409,7 @@ function createApiClient({
1067
1409
  { signal: abortSignal }
1068
1410
  );
1069
1411
  } catch (error3) {
1070
- if (uploadId && _optionalChain([error3, 'optionalAccess', _8 => _8.name]) && (error3.name === "AbortError" || error3.name === "TimeoutError")) {
1412
+ if (uploadId && _optionalChain([error3, 'optionalAccess', _16 => _16.name]) && (error3.name === "AbortError" || error3.name === "TimeoutError")) {
1071
1413
  try {
1072
1414
  await httpClient.rawDelete(
1073
1415
  url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${uploadId}`,
@@ -1083,40 +1425,31 @@ function createApiClient({
1083
1425
  }
1084
1426
  }
1085
1427
  }
1086
- const getAttachmentUrlsBatchStoreByRoom = /* @__PURE__ */ new Map();
1428
+ const attachmentUrlsBatchStoresByRoom = new DefaultMap((roomId) => {
1429
+ const batch2 = new Batch(
1430
+ async (batchedAttachmentIds) => {
1431
+ const attachmentIds = batchedAttachmentIds.flat();
1432
+ const { urls } = await httpClient.post(
1433
+ url`/v2/c/rooms/${roomId}/attachments/presigned-urls`,
1434
+ await authManager.getAuthValue({
1435
+ requestedScope: "comments:read",
1436
+ roomId
1437
+ }),
1438
+ { attachmentIds }
1439
+ );
1440
+ return urls.map(
1441
+ (url2) => _nullishCoalesce(url2, () => ( new Error("There was an error while getting this attachment's URL")))
1442
+ );
1443
+ },
1444
+ { delay: 50 }
1445
+ );
1446
+ return createBatchStore(batch2);
1447
+ });
1087
1448
  function getOrCreateAttachmentUrlsStore(roomId) {
1088
- let store = getAttachmentUrlsBatchStoreByRoom.get(roomId);
1089
- if (store === void 0) {
1090
- const batch2 = new Batch(
1091
- async (batchedAttachmentIds) => {
1092
- const attachmentIds = batchedAttachmentIds.flat();
1093
- const { urls } = await httpClient.post(
1094
- url`/v2/c/rooms/${roomId}/attachments/presigned-urls`,
1095
- await authManager.getAuthValue({
1096
- requestedScope: "comments:read",
1097
- roomId
1098
- }),
1099
- {
1100
- attachmentIds
1101
- }
1102
- );
1103
- return urls.map(
1104
- (url2) => _nullishCoalesce(url2, () => ( new Error(
1105
- "There was an error while getting this attachment's URL"
1106
- )))
1107
- );
1108
- },
1109
- {
1110
- delay: 50
1111
- }
1112
- );
1113
- store = createBatchStore(batch2);
1114
- getAttachmentUrlsBatchStoreByRoom.set(roomId, store);
1115
- }
1116
- return store;
1449
+ return attachmentUrlsBatchStoresByRoom.getOrCreate(roomId);
1117
1450
  }
1118
1451
  function getAttachmentUrl(options) {
1119
- const batch2 = getOrCreateAttachmentUrlsStore(options.roomId).getBatch();
1452
+ const batch2 = getOrCreateAttachmentUrlsStore(options.roomId).batch;
1120
1453
  return batch2.get(options.attachmentId);
1121
1454
  }
1122
1455
  async function getNotificationSettings(options) {
@@ -1142,33 +1475,25 @@ function createApiClient({
1142
1475
  options.settings
1143
1476
  );
1144
1477
  }
1145
- const markInboxNotificationsAsReadBatchByRoom = /* @__PURE__ */ new Map();
1146
- function getOrCreateMarkInboxNotificationsAsReadBatch(roomId) {
1147
- let batch2 = markInboxNotificationsAsReadBatchByRoom.get(roomId);
1148
- if (batch2 === void 0) {
1149
- batch2 = new Batch(
1150
- async (batchedInboxNotificationIds) => {
1151
- const inboxNotificationIds = batchedInboxNotificationIds.flat();
1152
- await httpClient.post(
1153
- url`/v2/c/rooms/${roomId}/inbox-notifications/read`,
1154
- await authManager.getAuthValue({
1155
- requestedScope: "comments:read",
1156
- roomId
1157
- }),
1158
- { inboxNotificationIds }
1159
- );
1160
- return inboxNotificationIds;
1161
- },
1162
- {
1163
- delay: 50
1164
- }
1165
- );
1166
- markInboxNotificationsAsReadBatchByRoom.set(roomId, batch2);
1167
- }
1168
- return batch2;
1169
- }
1478
+ const markAsReadBatchesByRoom = new DefaultMap(
1479
+ (roomId) => new Batch(
1480
+ async (batchedInboxNotificationIds) => {
1481
+ const inboxNotificationIds = batchedInboxNotificationIds.flat();
1482
+ await httpClient.post(
1483
+ url`/v2/c/rooms/${roomId}/inbox-notifications/read`,
1484
+ await authManager.getAuthValue({
1485
+ requestedScope: "comments:read",
1486
+ roomId
1487
+ }),
1488
+ { inboxNotificationIds }
1489
+ );
1490
+ return inboxNotificationIds;
1491
+ },
1492
+ { delay: 50 }
1493
+ )
1494
+ );
1170
1495
  async function markRoomInboxNotificationAsRead(options) {
1171
- const batch2 = getOrCreateMarkInboxNotificationsAsReadBatch(options.roomId);
1496
+ const batch2 = markAsReadBatchesByRoom.getOrCreate(options.roomId);
1172
1497
  return batch2.get(options.inboxNotificationId);
1173
1498
  }
1174
1499
  async function createTextMention(options) {
@@ -1291,7 +1616,7 @@ function createApiClient({
1291
1616
  url`/v2/c/inbox-notifications`,
1292
1617
  await authManager.getAuthValue({ requestedScope: "comments:read" }),
1293
1618
  {
1294
- cursor: _optionalChain([options, 'optionalAccess', _9 => _9.cursor]),
1619
+ cursor: _optionalChain([options, 'optionalAccess', _17 => _17.cursor]),
1295
1620
  limit: PAGE_SIZE
1296
1621
  }
1297
1622
  );
@@ -1375,7 +1700,7 @@ function createApiClient({
1375
1700
  }
1376
1701
  async function getUserThreads_experimental(options) {
1377
1702
  let query;
1378
- if (_optionalChain([options, 'optionalAccess', _10 => _10.query])) {
1703
+ if (_optionalChain([options, 'optionalAccess', _18 => _18.query])) {
1379
1704
  query = objectToQuery(options.query);
1380
1705
  }
1381
1706
  const PAGE_SIZE = 50;
@@ -1383,7 +1708,7 @@ function createApiClient({
1383
1708
  url`/v2/c/threads`,
1384
1709
  await authManager.getAuthValue({ requestedScope: "comments:read" }),
1385
1710
  {
1386
- cursor: _optionalChain([options, 'optionalAccess', _11 => _11.cursor]),
1711
+ cursor: _optionalChain([options, 'optionalAccess', _19 => _19.cursor]),
1387
1712
  query,
1388
1713
  limit: PAGE_SIZE
1389
1714
  }
@@ -1508,7 +1833,7 @@ var HttpClient = class {
1508
1833
  // These headers are default, but can be overriden by custom headers
1509
1834
  "Content-Type": "application/json; charset=utf-8",
1510
1835
  // Possible header overrides
1511
- ..._optionalChain([options, 'optionalAccess', _12 => _12.headers]),
1836
+ ..._optionalChain([options, 'optionalAccess', _20 => _20.headers]),
1512
1837
  // Cannot be overriden by custom headers
1513
1838
  Authorization: `Bearer ${getBearerTokenFromAuthValue(authValue)}`,
1514
1839
  "X-LB-Client": PKG_VERSION || "dev"
@@ -1532,19 +1857,12 @@ var HttpClient = class {
1532
1857
  async #fetch(endpoint, authValue, options, params) {
1533
1858
  const response = await this.#rawFetch(endpoint, authValue, options, params);
1534
1859
  if (!response.ok) {
1535
- let error3;
1536
- try {
1537
- const errorBody = await response.json();
1538
- error3 = new HttpError(errorBody.message, response.status, errorBody);
1539
- } catch (e2) {
1540
- error3 = new HttpError(response.statusText, response.status);
1541
- }
1542
- throw error3;
1860
+ throw await HttpError.fromResponse(response);
1543
1861
  }
1544
1862
  let body;
1545
1863
  try {
1546
1864
  body = await response.json();
1547
- } catch (e3) {
1865
+ } catch (e4) {
1548
1866
  body = {};
1549
1867
  }
1550
1868
  return body;
@@ -1990,7 +2308,7 @@ var FSM = class {
1990
2308
  });
1991
2309
  }
1992
2310
  #getTargetFn(eventName) {
1993
- return _optionalChain([this, 'access', _13 => _13.#allowedTransitions, 'access', _14 => _14.get, 'call', _15 => _15(this.currentState), 'optionalAccess', _16 => _16.get, 'call', _17 => _17(eventName)]);
2311
+ return _optionalChain([this, 'access', _21 => _21.#allowedTransitions, 'access', _22 => _22.get, 'call', _23 => _23(this.currentState), 'optionalAccess', _24 => _24.get, 'call', _25 => _25(eventName)]);
1994
2312
  }
1995
2313
  /**
1996
2314
  * Exits the current state, and executes any necessary cleanup functions.
@@ -2007,7 +2325,7 @@ var FSM = class {
2007
2325
  this.#currentContext.allowPatching((patchableContext) => {
2008
2326
  levels = _nullishCoalesce(levels, () => ( this.#cleanupStack.length));
2009
2327
  for (let i = 0; i < levels; i++) {
2010
- _optionalChain([this, 'access', _18 => _18.#cleanupStack, 'access', _19 => _19.pop, 'call', _20 => _20(), 'optionalCall', _21 => _21(patchableContext)]);
2328
+ _optionalChain([this, 'access', _26 => _26.#cleanupStack, 'access', _27 => _27.pop, 'call', _28 => _28(), 'optionalCall', _29 => _29(patchableContext)]);
2011
2329
  }
2012
2330
  });
2013
2331
  }
@@ -2023,7 +2341,7 @@ var FSM = class {
2023
2341
  this.#currentContext.allowPatching((patchableContext) => {
2024
2342
  for (const pattern of enterPatterns) {
2025
2343
  const enterFn = this.#enterFns.get(pattern);
2026
- const cleanupFn = _optionalChain([enterFn, 'optionalCall', _22 => _22(patchableContext)]);
2344
+ const cleanupFn = _optionalChain([enterFn, 'optionalCall', _30 => _30(patchableContext)]);
2027
2345
  if (typeof cleanupFn === "function") {
2028
2346
  this.#cleanupStack.push(cleanupFn);
2029
2347
  } else {
@@ -2166,6 +2484,7 @@ function toNewConnectionStatus(machine) {
2166
2484
  return machine.context.successCount > 0 ? "reconnecting" : "connecting";
2167
2485
  case "@idle.failed":
2168
2486
  return "disconnected";
2487
+ // istanbul ignore next
2169
2488
  default:
2170
2489
  return assertNever(state, "Unknown state");
2171
2490
  }
@@ -2182,13 +2501,6 @@ var StopRetrying = class extends Error {
2182
2501
  super(reason);
2183
2502
  }
2184
2503
  };
2185
- var LiveblocksError = class extends Error {
2186
- /** @internal */
2187
- constructor(message, code) {
2188
- super(message);
2189
- this.code = code;
2190
- }
2191
- };
2192
2504
  function nextBackoffDelay(currentDelay, delays) {
2193
2505
  return _nullishCoalesce(delays.find((delay) => delay > currentDelay), () => ( delays[delays.length - 1]));
2194
2506
  }
@@ -2298,11 +2610,10 @@ var assign = (patch) => (ctx) => ctx.patch(patch);
2298
2610
  function createConnectionStateMachine(delegates, options) {
2299
2611
  const onMessage = makeBufferableEventSource();
2300
2612
  onMessage.pause();
2301
- const onLiveblocksError = makeEventSource();
2302
- function fireErrorEvent(errmsg, errcode) {
2613
+ const onConnectionError = makeEventSource();
2614
+ function fireErrorEvent(message, code) {
2303
2615
  return () => {
2304
- const err = new LiveblocksError(errmsg, errcode);
2305
- onLiveblocksError.notify(err);
2616
+ onConnectionError.notify({ message, code });
2306
2617
  };
2307
2618
  }
2308
2619
  const initialContext = {
@@ -2424,7 +2735,7 @@ function createConnectionStateMachine(delegates, options) {
2424
2735
  }
2425
2736
  function waitForActorId(event) {
2426
2737
  const serverMsg = tryParseJson(event.data);
2427
- if (_optionalChain([serverMsg, 'optionalAccess', _23 => _23.type]) === 104 /* ROOM_STATE */) {
2738
+ if (_optionalChain([serverMsg, 'optionalAccess', _31 => _31.type]) === 104 /* ROOM_STATE */) {
2428
2739
  didReceiveActor();
2429
2740
  }
2430
2741
  }
@@ -2533,12 +2844,12 @@ function createConnectionStateMachine(delegates, options) {
2533
2844
  const sendHeartbeat = {
2534
2845
  target: "@ok.awaiting-pong",
2535
2846
  effect: (ctx) => {
2536
- _optionalChain([ctx, 'access', _24 => _24.socket, 'optionalAccess', _25 => _25.send, 'call', _26 => _26("ping")]);
2847
+ _optionalChain([ctx, 'access', _32 => _32.socket, 'optionalAccess', _33 => _33.send, 'call', _34 => _34("ping")]);
2537
2848
  }
2538
2849
  };
2539
2850
  const maybeHeartbeat = () => {
2540
2851
  const doc = typeof document !== "undefined" ? document : void 0;
2541
- const canZombie = _optionalChain([doc, 'optionalAccess', _27 => _27.visibilityState]) === "hidden" && delegates.canZombie();
2852
+ const canZombie = _optionalChain([doc, 'optionalAccess', _35 => _35.visibilityState]) === "hidden" && delegates.canZombie();
2542
2853
  return canZombie ? "@idle.zombie" : sendHeartbeat;
2543
2854
  };
2544
2855
  machine.addTimedTransition("@ok.connected", HEARTBEAT_INTERVAL, maybeHeartbeat).addTransitions("@ok.connected", {
@@ -2577,7 +2888,7 @@ function createConnectionStateMachine(delegates, options) {
2577
2888
  // socket, or not. So always check to see if the socket is still OPEN or
2578
2889
  // not. When still OPEN, don't transition.
2579
2890
  EXPLICIT_SOCKET_ERROR: (_, context) => {
2580
- if (_optionalChain([context, 'access', _28 => _28.socket, 'optionalAccess', _29 => _29.readyState]) === 1) {
2891
+ if (_optionalChain([context, 'access', _36 => _36.socket, 'optionalAccess', _37 => _37.readyState]) === 1) {
2581
2892
  return null;
2582
2893
  }
2583
2894
  return {
@@ -2629,17 +2940,17 @@ function createConnectionStateMachine(delegates, options) {
2629
2940
  machine.send({ type: "NAVIGATOR_ONLINE" });
2630
2941
  }
2631
2942
  function onVisibilityChange() {
2632
- if (_optionalChain([doc, 'optionalAccess', _30 => _30.visibilityState]) === "visible") {
2943
+ if (_optionalChain([doc, 'optionalAccess', _38 => _38.visibilityState]) === "visible") {
2633
2944
  machine.send({ type: "WINDOW_GOT_FOCUS" });
2634
2945
  }
2635
2946
  }
2636
- _optionalChain([win, 'optionalAccess', _31 => _31.addEventListener, 'call', _32 => _32("online", onNetworkBackOnline)]);
2637
- _optionalChain([win, 'optionalAccess', _33 => _33.addEventListener, 'call', _34 => _34("offline", onNetworkOffline)]);
2638
- _optionalChain([root, 'optionalAccess', _35 => _35.addEventListener, 'call', _36 => _36("visibilitychange", onVisibilityChange)]);
2947
+ _optionalChain([win, 'optionalAccess', _39 => _39.addEventListener, 'call', _40 => _40("online", onNetworkBackOnline)]);
2948
+ _optionalChain([win, 'optionalAccess', _41 => _41.addEventListener, 'call', _42 => _42("offline", onNetworkOffline)]);
2949
+ _optionalChain([root, 'optionalAccess', _43 => _43.addEventListener, 'call', _44 => _44("visibilitychange", onVisibilityChange)]);
2639
2950
  return () => {
2640
- _optionalChain([root, 'optionalAccess', _37 => _37.removeEventListener, 'call', _38 => _38("visibilitychange", onVisibilityChange)]);
2641
- _optionalChain([win, 'optionalAccess', _39 => _39.removeEventListener, 'call', _40 => _40("online", onNetworkBackOnline)]);
2642
- _optionalChain([win, 'optionalAccess', _41 => _41.removeEventListener, 'call', _42 => _42("offline", onNetworkOffline)]);
2951
+ _optionalChain([root, 'optionalAccess', _45 => _45.removeEventListener, 'call', _46 => _46("visibilitychange", onVisibilityChange)]);
2952
+ _optionalChain([win, 'optionalAccess', _47 => _47.removeEventListener, 'call', _48 => _48("online", onNetworkBackOnline)]);
2953
+ _optionalChain([win, 'optionalAccess', _49 => _49.removeEventListener, 'call', _50 => _50("offline", onNetworkOffline)]);
2643
2954
  teardownSocket(ctx.socket);
2644
2955
  };
2645
2956
  });
@@ -2660,7 +2971,7 @@ function createConnectionStateMachine(delegates, options) {
2660
2971
  didConnect,
2661
2972
  didDisconnect,
2662
2973
  onMessage: onMessage.observable,
2663
- onLiveblocksError: onLiveblocksError.observable
2974
+ onConnectionError: onConnectionError.observable
2664
2975
  }
2665
2976
  };
2666
2977
  }
@@ -2680,7 +2991,7 @@ var ManagedSocket = class {
2680
2991
  getStatus() {
2681
2992
  try {
2682
2993
  return toNewConnectionStatus(this.#machine);
2683
- } catch (e4) {
2994
+ } catch (e5) {
2684
2995
  return "initial";
2685
2996
  }
2686
2997
  }
@@ -2728,7 +3039,7 @@ var ManagedSocket = class {
2728
3039
  * message if this is somehow impossible.
2729
3040
  */
2730
3041
  send(data) {
2731
- const socket = _optionalChain([this, 'access', _43 => _43.#machine, 'access', _44 => _44.context, 'optionalAccess', _45 => _45.socket]);
3042
+ const socket = _optionalChain([this, 'access', _51 => _51.#machine, 'access', _52 => _52.context, 'optionalAccess', _53 => _53.socket]);
2732
3043
  if (socket === null) {
2733
3044
  warn("Cannot send: not connected yet", data);
2734
3045
  } else if (socket.readyState !== 1) {
@@ -2832,7 +3143,7 @@ function createAuthManager(authOptions, onAuthenticate) {
2832
3143
  return void 0;
2833
3144
  }
2834
3145
  async function makeAuthRequest(options) {
2835
- const fetcher = _nullishCoalesce(_optionalChain([authOptions, 'access', _46 => _46.polyfills, 'optionalAccess', _47 => _47.fetch]), () => ( (typeof window === "undefined" ? void 0 : window.fetch)));
3146
+ const fetcher = _nullishCoalesce(_optionalChain([authOptions, 'access', _54 => _54.polyfills, 'optionalAccess', _55 => _55.fetch]), () => ( (typeof window === "undefined" ? void 0 : window.fetch)));
2836
3147
  if (authentication.type === "private") {
2837
3148
  if (fetcher === void 0) {
2838
3149
  throw new StopRetrying(
@@ -2848,7 +3159,7 @@ function createAuthManager(authOptions, onAuthenticate) {
2848
3159
  "The same Liveblocks auth token was issued from the backend before. Caching Liveblocks tokens is not supported."
2849
3160
  );
2850
3161
  }
2851
- _optionalChain([onAuthenticate, 'optionalCall', _48 => _48(parsed.parsed)]);
3162
+ _optionalChain([onAuthenticate, 'optionalCall', _56 => _56(parsed.parsed)]);
2852
3163
  return parsed;
2853
3164
  }
2854
3165
  if (authentication.type === "custom") {
@@ -2856,7 +3167,7 @@ function createAuthManager(authOptions, onAuthenticate) {
2856
3167
  if (response && typeof response === "object") {
2857
3168
  if (typeof response.token === "string") {
2858
3169
  const parsed = parseAuthToken(response.token);
2859
- _optionalChain([onAuthenticate, 'optionalCall', _49 => _49(parsed.parsed)]);
3170
+ _optionalChain([onAuthenticate, 'optionalCall', _57 => _57(parsed.parsed)]);
2860
3171
  return parsed;
2861
3172
  } else if (typeof response.error === "string") {
2862
3173
  const reason = `Authentication failed: ${"reason" in response && typeof response.reason === "string" ? response.reason : "Forbidden"}`;
@@ -3017,7 +3328,7 @@ function sendToPanel(message, options) {
3017
3328
  ...message,
3018
3329
  source: "liveblocks-devtools-client"
3019
3330
  };
3020
- if (!(_optionalChain([options, 'optionalAccess', _50 => _50.force]) || _bridgeActive)) {
3331
+ if (!(_optionalChain([options, 'optionalAccess', _58 => _58.force]) || _bridgeActive)) {
3021
3332
  return;
3022
3333
  }
3023
3334
  window.postMessage(fullMsg, "*");
@@ -3025,7 +3336,7 @@ function sendToPanel(message, options) {
3025
3336
  var eventSource = makeEventSource();
3026
3337
  if (process.env.NODE_ENV !== "production" && typeof window !== "undefined") {
3027
3338
  window.addEventListener("message", (event) => {
3028
- if (event.source === window && _optionalChain([event, 'access', _51 => _51.data, 'optionalAccess', _52 => _52.source]) === "liveblocks-devtools-panel") {
3339
+ if (event.source === window && _optionalChain([event, 'access', _59 => _59.data, 'optionalAccess', _60 => _60.source]) === "liveblocks-devtools-panel") {
3029
3340
  eventSource.notify(event.data);
3030
3341
  } else {
3031
3342
  }
@@ -3038,442 +3349,189 @@ var VERSION = PKG_VERSION || "dev";
3038
3349
  var _devtoolsSetupHasRun = false;
3039
3350
  function setupDevTools(getAllRooms) {
3040
3351
  if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
3041
- return;
3042
- }
3043
- if (_devtoolsSetupHasRun) {
3044
- return;
3045
- }
3046
- _devtoolsSetupHasRun = true;
3047
- onMessageFromPanel.subscribe((msg) => {
3048
- switch (msg.msg) {
3049
- case "connect": {
3050
- activateBridge(true);
3051
- for (const roomId of getAllRooms()) {
3052
- sendToPanel({
3053
- msg: "room::available",
3054
- roomId,
3055
- clientVersion: VERSION
3056
- });
3057
- }
3058
- break;
3059
- }
3060
- }
3061
- });
3062
- sendToPanel({ msg: "wake-up-devtools" }, { force: true });
3063
- }
3064
- var unsubsByRoomId = /* @__PURE__ */ new Map();
3065
- function stopSyncStream(roomId) {
3066
- const unsubs = _nullishCoalesce(unsubsByRoomId.get(roomId), () => ( []));
3067
- unsubsByRoomId.delete(roomId);
3068
- for (const unsub of unsubs) {
3069
- unsub();
3070
- }
3071
- }
3072
- function startSyncStream(room) {
3073
- stopSyncStream(room.id);
3074
- fullSync(room);
3075
- unsubsByRoomId.set(room.id, [
3076
- // When the connection status changes
3077
- room.events.status.subscribe(() => partialSyncConnection(room)),
3078
- // When storage initializes, send the update
3079
- room.events.storageDidLoad.subscribeOnce(() => partialSyncStorage(room)),
3080
- // Any time storage updates, send the new storage root
3081
- room.events.storageBatch.subscribe(() => partialSyncStorage(room)),
3082
- // Any time "me" or "others" updates, send the new values accordingly
3083
- room.events.self.subscribe(() => partialSyncMe(room)),
3084
- room.events.others.subscribe(() => partialSyncOthers(room)),
3085
- // Any time ydoc is updated, forward the update
3086
- room.events.ydoc.subscribe((update) => syncYdocUpdate(room, update)),
3087
- // Any time a custom room event is received, forward it
3088
- room.events.customEvent.subscribe(
3089
- (eventData) => forwardEvent(room, eventData)
3090
- )
3091
- ]);
3092
- }
3093
- function syncYdocUpdate(room, update) {
3094
- sendToPanel({
3095
- msg: "room::sync::ydoc",
3096
- roomId: room.id,
3097
- update
3098
- });
3099
- }
3100
- var loadedAt = Date.now();
3101
- var eventCounter = 0;
3102
- function nextEventId() {
3103
- return `event-${loadedAt}-${eventCounter++}`;
3104
- }
3105
- function forwardEvent(room, eventData) {
3106
- sendToPanel({
3107
- msg: "room::events::custom-event",
3108
- roomId: room.id,
3109
- event: {
3110
- type: "CustomEvent",
3111
- id: nextEventId(),
3112
- key: "Event",
3113
- connectionId: eventData.connectionId,
3114
- payload: eventData.event
3115
- }
3116
- });
3117
- }
3118
- function partialSyncConnection(room) {
3119
- sendToPanel({
3120
- msg: "room::sync::partial",
3121
- roomId: room.id,
3122
- status: room.getStatus()
3123
- });
3124
- }
3125
- function partialSyncStorage(room) {
3126
- const root = room.getStorageSnapshot();
3127
- if (root) {
3128
- sendToPanel({
3129
- msg: "room::sync::partial",
3130
- roomId: room.id,
3131
- storage: root.toTreeNode("root").payload
3132
- });
3133
- }
3134
- }
3135
- function partialSyncMe(room) {
3136
- const me = room[kInternal].getSelf_forDevTools();
3137
- if (me) {
3138
- sendToPanel({
3139
- msg: "room::sync::partial",
3140
- roomId: room.id,
3141
- me
3142
- });
3143
- }
3144
- }
3145
- function partialSyncOthers(room) {
3146
- const others = room[kInternal].getOthers_forDevTools();
3147
- if (others) {
3148
- sendToPanel({
3149
- msg: "room::sync::partial",
3150
- roomId: room.id,
3151
- others
3152
- });
3153
- }
3154
- }
3155
- function fullSync(room) {
3156
- const root = room.getStorageSnapshot();
3157
- const me = room[kInternal].getSelf_forDevTools();
3158
- const others = room[kInternal].getOthers_forDevTools();
3159
- room.fetchYDoc("");
3160
- sendToPanel({
3161
- msg: "room::sync::full",
3162
- roomId: room.id,
3163
- status: room.getStatus(),
3164
- storage: _nullishCoalesce(_optionalChain([root, 'optionalAccess', _53 => _53.toTreeNode, 'call', _54 => _54("root"), 'access', _55 => _55.payload]), () => ( null)),
3165
- me,
3166
- others
3167
- });
3168
- }
3169
- var roomChannelListeners = /* @__PURE__ */ new Map();
3170
- function stopRoomChannelListener(roomId) {
3171
- const listener = roomChannelListeners.get(roomId);
3172
- roomChannelListeners.delete(roomId);
3173
- if (listener) {
3174
- listener();
3175
- }
3176
- }
3177
- function linkDevTools(roomId, room) {
3178
- if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
3179
- return;
3180
- }
3181
- sendToPanel({ msg: "room::available", roomId, clientVersion: VERSION });
3182
- stopRoomChannelListener(roomId);
3183
- roomChannelListeners.set(
3184
- roomId,
3185
- // Returns the unsubscribe callback, that we store in the
3186
- // roomChannelListeners registry
3187
- onMessageFromPanel.subscribe((msg) => {
3188
- switch (msg.msg) {
3189
- case "room::subscribe": {
3190
- if (msg.roomId === roomId) {
3191
- startSyncStream(room);
3192
- }
3193
- break;
3194
- }
3195
- case "room::unsubscribe": {
3196
- if (msg.roomId === roomId) {
3197
- stopSyncStream(roomId);
3198
- }
3199
- break;
3200
- }
3201
- }
3202
- })
3203
- );
3204
- }
3205
- function unlinkDevTools(roomId) {
3206
- if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
3207
- return;
3208
- }
3209
- stopSyncStream(roomId);
3210
- stopRoomChannelListener(roomId);
3211
- sendToPanel({
3212
- msg: "room::unavailable",
3213
- roomId
3214
- });
3215
- }
3216
-
3217
- // src/lib/freeze.ts
3218
- var freeze = process.env.NODE_ENV === "production" ? (
3219
- /* istanbul ignore next */
3220
- (x) => x
3221
- ) : Object.freeze;
3222
-
3223
- // src/lib/signals.ts
3224
- var kSinks = Symbol("kSinks");
3225
- var kTrigger = Symbol("kTrigger");
3226
- var signalsToTrigger = null;
3227
- function batch(callback) {
3228
- if (signalsToTrigger !== null) {
3229
- callback();
3230
- return;
3231
- }
3232
- signalsToTrigger = /* @__PURE__ */ new Set();
3233
- try {
3234
- callback();
3235
- } finally {
3236
- for (const signal of signalsToTrigger) {
3237
- signal[kTrigger]();
3238
- }
3239
- signalsToTrigger = null;
3240
- }
3241
- }
3242
- function enqueueTrigger(signal) {
3243
- if (!signalsToTrigger) raise("Expected to be in an active batch");
3244
- signalsToTrigger.add(signal);
3245
- }
3246
- function merge(target, patch) {
3247
- let updated = false;
3248
- const newValue = { ...target };
3249
- Object.keys(patch).forEach((k) => {
3250
- const key = k;
3251
- const val = patch[key];
3252
- if (newValue[key] !== val) {
3253
- if (val === void 0) {
3254
- delete newValue[key];
3255
- } else {
3256
- newValue[key] = val;
3257
- }
3258
- updated = true;
3259
- }
3260
- });
3261
- return updated ? newValue : target;
3262
- }
3263
- var AbstractSignal = class {
3264
- /** @internal */
3265
-
3266
- #eventSource;
3267
- /** @internal */
3268
-
3269
- constructor(equals) {
3270
- this.equals = _nullishCoalesce(equals, () => ( Object.is));
3271
- this.#eventSource = makeEventSource();
3272
- this[kSinks] = /* @__PURE__ */ new Set();
3273
- this.get = this.get.bind(this);
3274
- this.subscribe = this.subscribe.bind(this);
3275
- this.subscribeOnce = this.subscribeOnce.bind(this);
3276
- }
3277
- [Symbol.dispose]() {
3278
- this.#eventSource[Symbol.dispose]();
3279
- this.#eventSource = "(disposed)";
3280
- this.equals = "(disposed)";
3281
- }
3282
- get hasWatchers() {
3283
- if (this.#eventSource.count() > 0) return true;
3284
- for (const sink of this[kSinks]) {
3285
- if (sink.hasWatchers) {
3286
- return true;
3287
- }
3288
- }
3289
- return false;
3290
- }
3291
- [kTrigger]() {
3292
- this.#eventSource.notify();
3293
- for (const sink of this[kSinks]) {
3294
- enqueueTrigger(sink);
3295
- }
3296
- }
3297
- subscribe(callback) {
3298
- return this.#eventSource.subscribe(callback);
3299
- }
3300
- subscribeOnce(callback) {
3301
- const unsub = this.subscribe(() => {
3302
- unsub();
3303
- return callback();
3304
- });
3305
- return unsub;
3306
- }
3307
- waitUntil() {
3308
- throw new Error("waitUntil not supported on Signals");
3309
- }
3310
- markSinksDirty() {
3311
- for (const sink of this[kSinks]) {
3312
- sink.markDirty();
3313
- }
3314
- }
3315
- addSink(sink) {
3316
- this[kSinks].add(sink);
3317
- }
3318
- removeSink(sink) {
3319
- this[kSinks].delete(sink);
3320
- }
3321
- asReadonly() {
3322
- return this;
3323
- }
3324
- };
3325
- var Signal = class extends AbstractSignal {
3326
- #value;
3327
- constructor(value, equals) {
3328
- super(equals);
3329
- this.#value = freeze(value);
3330
- }
3331
- [Symbol.dispose]() {
3332
- super[Symbol.dispose]();
3333
- this.#value = "(disposed)";
3334
- }
3335
- get() {
3336
- return this.#value;
3337
- }
3338
- set(newValue) {
3339
- batch(() => {
3340
- if (typeof newValue === "function") {
3341
- newValue = newValue(this.#value);
3342
- }
3343
- if (!this.equals(this.#value, newValue)) {
3344
- this.#value = freeze(newValue);
3345
- this.markSinksDirty();
3346
- enqueueTrigger(this);
3347
- }
3348
- });
3349
- }
3350
- };
3351
- var PatchableSignal = class extends Signal {
3352
- constructor(data) {
3353
- super(freeze(compactObject(data)));
3354
- }
3355
- set() {
3356
- throw new Error("Don't call .set() directly, use .patch()");
3357
- }
3358
- /**
3359
- * Patches the current object.
3360
- */
3361
- patch(patch) {
3362
- super.set((old) => merge(old, patch));
3363
- }
3364
- };
3365
- var INITIAL = Symbol();
3366
- var DerivedSignal = class _DerivedSignal extends AbstractSignal {
3367
- #prevValue;
3368
- #dirty;
3369
- // When true, the value in #value may not be up-to-date and needs re-checking
3370
- #parents;
3371
- #transform;
3372
- // prettier-ignore
3373
- static from(...args) {
3374
- const last = args.pop();
3375
- if (typeof last !== "function")
3376
- raise("Invalid .from() call, last argument expected to be a function");
3377
- if (typeof args[args.length - 1] === "function") {
3378
- const equals = last;
3379
- const transform = args.pop();
3380
- return new _DerivedSignal(args, transform, equals);
3381
- } else {
3382
- const transform = last;
3383
- return new _DerivedSignal(args, transform);
3384
- }
3385
- }
3386
- constructor(parents, transform, equals) {
3387
- super(equals);
3388
- this.#dirty = true;
3389
- this.#prevValue = INITIAL;
3390
- this.#parents = parents;
3391
- this.#transform = transform;
3392
- for (const parent of parents) {
3393
- parent.addSink(this);
3394
- }
3395
- }
3396
- [Symbol.dispose]() {
3397
- for (const parent of this.#parents) {
3398
- parent.removeSink(this);
3399
- }
3400
- this.#prevValue = "(disposed)";
3401
- this.#parents = "(disposed)";
3402
- this.#transform = "(disposed)";
3403
- }
3404
- get isDirty() {
3405
- return this.#dirty;
3352
+ return;
3406
3353
  }
3407
- #recompute() {
3408
- const derived = this.#transform(...this.#parents.map((p) => p.get()));
3409
- this.#dirty = false;
3410
- if (!this.equals(this.#prevValue, derived)) {
3411
- this.#prevValue = derived;
3412
- return true;
3413
- }
3414
- return false;
3354
+ if (_devtoolsSetupHasRun) {
3355
+ return;
3415
3356
  }
3416
- markDirty() {
3417
- if (!this.#dirty) {
3418
- this.#dirty = true;
3419
- this.markSinksDirty();
3357
+ _devtoolsSetupHasRun = true;
3358
+ onMessageFromPanel.subscribe((msg) => {
3359
+ switch (msg.msg) {
3360
+ // When a devtool panel sends an explicit "connect" message back to this
3361
+ // live running client (in response to the "wake-up-devtools" message,
3362
+ // or when the devtool panel is opened for the first time), it means that it's okay to
3363
+ // start emitting messages.
3364
+ // Before this explicit acknowledgement, any call to sendToPanel() will
3365
+ // be a no-op.
3366
+ case "connect": {
3367
+ activateBridge(true);
3368
+ for (const roomId of getAllRooms()) {
3369
+ sendToPanel({
3370
+ msg: "room::available",
3371
+ roomId,
3372
+ clientVersion: VERSION
3373
+ });
3374
+ }
3375
+ break;
3376
+ }
3420
3377
  }
3378
+ });
3379
+ sendToPanel({ msg: "wake-up-devtools" }, { force: true });
3380
+ }
3381
+ var unsubsByRoomId = /* @__PURE__ */ new Map();
3382
+ function stopSyncStream(roomId) {
3383
+ const unsubs = _nullishCoalesce(unsubsByRoomId.get(roomId), () => ( []));
3384
+ unsubsByRoomId.delete(roomId);
3385
+ for (const unsub of unsubs) {
3386
+ unsub();
3421
3387
  }
3422
- get() {
3423
- if (this.#dirty) {
3424
- this.#recompute();
3388
+ }
3389
+ function startSyncStream(room) {
3390
+ stopSyncStream(room.id);
3391
+ fullSync(room);
3392
+ unsubsByRoomId.set(room.id, [
3393
+ // When the connection status changes
3394
+ room.events.status.subscribe(() => partialSyncConnection(room)),
3395
+ // When storage initializes, send the update
3396
+ room.events.storageDidLoad.subscribeOnce(() => partialSyncStorage(room)),
3397
+ // Any time storage updates, send the new storage root
3398
+ room.events.storageBatch.subscribe(() => partialSyncStorage(room)),
3399
+ // Any time "me" or "others" updates, send the new values accordingly
3400
+ room.events.self.subscribe(() => partialSyncMe(room)),
3401
+ room.events.others.subscribe(() => partialSyncOthers(room)),
3402
+ // Any time ydoc is updated, forward the update
3403
+ room.events.ydoc.subscribe((update) => syncYdocUpdate(room, update)),
3404
+ // Any time a custom room event is received, forward it
3405
+ room.events.customEvent.subscribe(
3406
+ (eventData) => forwardEvent(room, eventData)
3407
+ )
3408
+ ]);
3409
+ }
3410
+ function syncYdocUpdate(room, update) {
3411
+ sendToPanel({
3412
+ msg: "room::sync::ydoc",
3413
+ roomId: room.id,
3414
+ update
3415
+ });
3416
+ }
3417
+ var loadedAt = Date.now();
3418
+ var eventCounter = 0;
3419
+ function nextEventId() {
3420
+ return `event-${loadedAt}-${eventCounter++}`;
3421
+ }
3422
+ function forwardEvent(room, eventData) {
3423
+ sendToPanel({
3424
+ msg: "room::events::custom-event",
3425
+ roomId: room.id,
3426
+ event: {
3427
+ type: "CustomEvent",
3428
+ id: nextEventId(),
3429
+ key: "Event",
3430
+ connectionId: eventData.connectionId,
3431
+ payload: eventData.event
3425
3432
  }
3426
- return this.#prevValue;
3433
+ });
3434
+ }
3435
+ function partialSyncConnection(room) {
3436
+ sendToPanel({
3437
+ msg: "room::sync::partial",
3438
+ roomId: room.id,
3439
+ status: room.getStatus()
3440
+ });
3441
+ }
3442
+ function partialSyncStorage(room) {
3443
+ const root = room.getStorageSnapshot();
3444
+ if (root) {
3445
+ sendToPanel({
3446
+ msg: "room::sync::partial",
3447
+ roomId: room.id,
3448
+ storage: root.toTreeNode("root").payload
3449
+ });
3427
3450
  }
3428
- /**
3429
- * Called by the Signal system if one or more of the dependent signals have
3430
- * changed. In the case of a DerivedSignal, we'll only want to re-evaluate
3431
- * the actual value if it's being watched, or any of their sinks are being
3432
- * watched actively.
3433
- */
3434
- [kTrigger]() {
3435
- if (!this.hasWatchers) {
3436
- return;
3437
- }
3438
- const updated = this.#recompute();
3439
- if (updated) {
3440
- super[kTrigger]();
3441
- }
3451
+ }
3452
+ function partialSyncMe(room) {
3453
+ const me = room[kInternal].getSelf_forDevTools();
3454
+ if (me) {
3455
+ sendToPanel({
3456
+ msg: "room::sync::partial",
3457
+ roomId: room.id,
3458
+ me
3459
+ });
3442
3460
  }
3443
- };
3444
- var MutableSignal = class extends AbstractSignal {
3445
- #state;
3446
- constructor(initialState) {
3447
- super();
3448
- this.#state = initialState;
3461
+ }
3462
+ function partialSyncOthers(room) {
3463
+ const others = room[kInternal].getOthers_forDevTools();
3464
+ if (others) {
3465
+ sendToPanel({
3466
+ msg: "room::sync::partial",
3467
+ roomId: room.id,
3468
+ others
3469
+ });
3449
3470
  }
3450
- [Symbol.dispose]() {
3451
- super[Symbol.dispose]();
3452
- this.#state = "(disposed)";
3471
+ }
3472
+ function fullSync(room) {
3473
+ const root = room.getStorageSnapshot();
3474
+ const me = room[kInternal].getSelf_forDevTools();
3475
+ const others = room[kInternal].getOthers_forDevTools();
3476
+ room.fetchYDoc("");
3477
+ sendToPanel({
3478
+ msg: "room::sync::full",
3479
+ roomId: room.id,
3480
+ status: room.getStatus(),
3481
+ storage: _nullishCoalesce(_optionalChain([root, 'optionalAccess', _61 => _61.toTreeNode, 'call', _62 => _62("root"), 'access', _63 => _63.payload]), () => ( null)),
3482
+ me,
3483
+ others
3484
+ });
3485
+ }
3486
+ var roomChannelListeners = /* @__PURE__ */ new Map();
3487
+ function stopRoomChannelListener(roomId) {
3488
+ const listener = roomChannelListeners.get(roomId);
3489
+ roomChannelListeners.delete(roomId);
3490
+ if (listener) {
3491
+ listener();
3453
3492
  }
3454
- get() {
3455
- return this.#state;
3493
+ }
3494
+ function linkDevTools(roomId, room) {
3495
+ if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
3496
+ return;
3456
3497
  }
3457
- /**
3458
- * Invokes a callback function that is allowed to mutate the given state
3459
- * value. Do not change the value outside of the callback.
3460
- *
3461
- * If the callback explicitly returns `false`, it's assumed that the state
3462
- * was not changed.
3463
- */
3464
- mutate(callback) {
3465
- batch(() => {
3466
- const result = callback ? callback(this.#state) : true;
3467
- if (result !== null && typeof result === "object" && "then" in result) {
3468
- raise("MutableSignal.mutate() does not support async callbacks");
3469
- }
3470
- if (result !== false) {
3471
- this.markSinksDirty();
3472
- enqueueTrigger(this);
3498
+ sendToPanel({ msg: "room::available", roomId, clientVersion: VERSION });
3499
+ stopRoomChannelListener(roomId);
3500
+ roomChannelListeners.set(
3501
+ roomId,
3502
+ // Returns the unsubscribe callback, that we store in the
3503
+ // roomChannelListeners registry
3504
+ onMessageFromPanel.subscribe((msg) => {
3505
+ switch (msg.msg) {
3506
+ // Sent by the devtool panel when it wants to receive the sync stream
3507
+ // for a room
3508
+ case "room::subscribe": {
3509
+ if (msg.roomId === roomId) {
3510
+ startSyncStream(room);
3511
+ }
3512
+ break;
3513
+ }
3514
+ case "room::unsubscribe": {
3515
+ if (msg.roomId === roomId) {
3516
+ stopSyncStream(roomId);
3517
+ }
3518
+ break;
3519
+ }
3473
3520
  }
3474
- });
3521
+ })
3522
+ );
3523
+ }
3524
+ function unlinkDevTools(roomId) {
3525
+ if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
3526
+ return;
3475
3527
  }
3476
- };
3528
+ stopSyncStream(roomId);
3529
+ stopRoomChannelListener(roomId);
3530
+ sendToPanel({
3531
+ msg: "room::unavailable",
3532
+ roomId
3533
+ });
3534
+ }
3477
3535
 
3478
3536
  // src/lib/position.ts
3479
3537
  var MIN_CODE = 32;
@@ -3844,7 +3902,7 @@ var LiveRegister = class _LiveRegister extends AbstractCrdt {
3844
3902
  return [
3845
3903
  {
3846
3904
  type: 8 /* CREATE_REGISTER */,
3847
- opId: _optionalChain([pool, 'optionalAccess', _56 => _56.generateOpId, 'call', _57 => _57()]),
3905
+ opId: _optionalChain([pool, 'optionalAccess', _64 => _64.generateOpId, 'call', _65 => _65()]),
3848
3906
  id: this._id,
3849
3907
  parentId,
3850
3908
  parentKey,
@@ -3950,7 +4008,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3950
4008
  const ops = [];
3951
4009
  const op = {
3952
4010
  id: this._id,
3953
- opId: _optionalChain([pool, 'optionalAccess', _58 => _58.generateOpId, 'call', _59 => _59()]),
4011
+ opId: _optionalChain([pool, 'optionalAccess', _66 => _66.generateOpId, 'call', _67 => _67()]),
3954
4012
  type: 2 /* CREATE_LIST */,
3955
4013
  parentId,
3956
4014
  parentKey
@@ -4221,7 +4279,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4221
4279
  #applyInsertUndoRedo(op) {
4222
4280
  const { id, parentKey: key } = op;
4223
4281
  const child = creationOpToLiveNode(op);
4224
- if (_optionalChain([this, 'access', _60 => _60._pool, 'optionalAccess', _61 => _61.getNode, 'call', _62 => _62(id)]) !== void 0) {
4282
+ if (_optionalChain([this, 'access', _68 => _68._pool, 'optionalAccess', _69 => _69.getNode, 'call', _70 => _70(id)]) !== void 0) {
4225
4283
  return { modified: false };
4226
4284
  }
4227
4285
  child._attach(id, nn(this._pool));
@@ -4229,8 +4287,8 @@ var LiveList = class _LiveList extends AbstractCrdt {
4229
4287
  const existingItemIndex = this._indexOfPosition(key);
4230
4288
  let newKey = key;
4231
4289
  if (existingItemIndex !== -1) {
4232
- const before2 = _optionalChain([this, 'access', _63 => _63.#items, 'access', _64 => _64[existingItemIndex], 'optionalAccess', _65 => _65._parentPos]);
4233
- const after2 = _optionalChain([this, 'access', _66 => _66.#items, 'access', _67 => _67[existingItemIndex + 1], 'optionalAccess', _68 => _68._parentPos]);
4290
+ const before2 = _optionalChain([this, 'access', _71 => _71.#items, 'access', _72 => _72[existingItemIndex], 'optionalAccess', _73 => _73._parentPos]);
4291
+ const after2 = _optionalChain([this, 'access', _74 => _74.#items, 'access', _75 => _75[existingItemIndex + 1], 'optionalAccess', _76 => _76._parentPos]);
4234
4292
  newKey = makePosition(before2, after2);
4235
4293
  child._setParentLink(this, newKey);
4236
4294
  }
@@ -4244,7 +4302,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4244
4302
  #applySetUndoRedo(op) {
4245
4303
  const { id, parentKey: key } = op;
4246
4304
  const child = creationOpToLiveNode(op);
4247
- if (_optionalChain([this, 'access', _69 => _69._pool, 'optionalAccess', _70 => _70.getNode, 'call', _71 => _71(id)]) !== void 0) {
4305
+ if (_optionalChain([this, 'access', _77 => _77._pool, 'optionalAccess', _78 => _78.getNode, 'call', _79 => _79(id)]) !== void 0) {
4248
4306
  return { modified: false };
4249
4307
  }
4250
4308
  this.#unacknowledgedSets.set(key, nn(op.opId));
@@ -4365,7 +4423,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4365
4423
  } else {
4366
4424
  this.#items[existingItemIndex]._setParentLink(
4367
4425
  this,
4368
- makePosition(newKey, _optionalChain([this, 'access', _72 => _72.#items, 'access', _73 => _73[existingItemIndex + 1], 'optionalAccess', _74 => _74._parentPos]))
4426
+ makePosition(newKey, _optionalChain([this, 'access', _80 => _80.#items, 'access', _81 => _81[existingItemIndex + 1], 'optionalAccess', _82 => _82._parentPos]))
4369
4427
  );
4370
4428
  const previousIndex = this.#items.indexOf(child);
4371
4429
  child._setParentLink(this, newKey);
@@ -4390,7 +4448,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4390
4448
  if (existingItemIndex !== -1) {
4391
4449
  this.#items[existingItemIndex]._setParentLink(
4392
4450
  this,
4393
- makePosition(newKey, _optionalChain([this, 'access', _75 => _75.#items, 'access', _76 => _76[existingItemIndex + 1], 'optionalAccess', _77 => _77._parentPos]))
4451
+ makePosition(newKey, _optionalChain([this, 'access', _83 => _83.#items, 'access', _84 => _84[existingItemIndex + 1], 'optionalAccess', _85 => _85._parentPos]))
4394
4452
  );
4395
4453
  }
4396
4454
  child._setParentLink(this, newKey);
@@ -4409,7 +4467,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4409
4467
  if (existingItemIndex !== -1) {
4410
4468
  this.#items[existingItemIndex]._setParentLink(
4411
4469
  this,
4412
- makePosition(newKey, _optionalChain([this, 'access', _78 => _78.#items, 'access', _79 => _79[existingItemIndex + 1], 'optionalAccess', _80 => _80._parentPos]))
4470
+ makePosition(newKey, _optionalChain([this, 'access', _86 => _86.#items, 'access', _87 => _87[existingItemIndex + 1], 'optionalAccess', _88 => _88._parentPos]))
4413
4471
  );
4414
4472
  }
4415
4473
  child._setParentLink(this, newKey);
@@ -4436,7 +4494,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4436
4494
  if (existingItemIndex !== -1) {
4437
4495
  this.#items[existingItemIndex]._setParentLink(
4438
4496
  this,
4439
- makePosition(newKey, _optionalChain([this, 'access', _81 => _81.#items, 'access', _82 => _82[existingItemIndex + 1], 'optionalAccess', _83 => _83._parentPos]))
4497
+ makePosition(newKey, _optionalChain([this, 'access', _89 => _89.#items, 'access', _90 => _90[existingItemIndex + 1], 'optionalAccess', _91 => _91._parentPos]))
4440
4498
  );
4441
4499
  }
4442
4500
  child._setParentLink(this, newKey);
@@ -4494,7 +4552,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4494
4552
  * @param element The element to add to the end of the LiveList.
4495
4553
  */
4496
4554
  push(element) {
4497
- _optionalChain([this, 'access', _84 => _84._pool, 'optionalAccess', _85 => _85.assertStorageIsWritable, 'call', _86 => _86()]);
4555
+ _optionalChain([this, 'access', _92 => _92._pool, 'optionalAccess', _93 => _93.assertStorageIsWritable, 'call', _94 => _94()]);
4498
4556
  return this.insert(element, this.length);
4499
4557
  }
4500
4558
  /**
@@ -4503,7 +4561,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4503
4561
  * @param index The index at which you want to insert the element.
4504
4562
  */
4505
4563
  insert(element, index) {
4506
- _optionalChain([this, 'access', _87 => _87._pool, 'optionalAccess', _88 => _88.assertStorageIsWritable, 'call', _89 => _89()]);
4564
+ _optionalChain([this, 'access', _95 => _95._pool, 'optionalAccess', _96 => _96.assertStorageIsWritable, 'call', _97 => _97()]);
4507
4565
  if (index < 0 || index > this.#items.length) {
4508
4566
  throw new Error(
4509
4567
  `Cannot insert list item at index "${index}". index should be between 0 and ${this.#items.length}`
@@ -4533,7 +4591,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4533
4591
  * @param targetIndex The index where the element should be after moving.
4534
4592
  */
4535
4593
  move(index, targetIndex) {
4536
- _optionalChain([this, 'access', _90 => _90._pool, 'optionalAccess', _91 => _91.assertStorageIsWritable, 'call', _92 => _92()]);
4594
+ _optionalChain([this, 'access', _98 => _98._pool, 'optionalAccess', _99 => _99.assertStorageIsWritable, 'call', _100 => _100()]);
4537
4595
  if (targetIndex < 0) {
4538
4596
  throw new Error("targetIndex cannot be less than 0");
4539
4597
  }
@@ -4591,7 +4649,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4591
4649
  * @param index The index of the element to delete
4592
4650
  */
4593
4651
  delete(index) {
4594
- _optionalChain([this, 'access', _93 => _93._pool, 'optionalAccess', _94 => _94.assertStorageIsWritable, 'call', _95 => _95()]);
4652
+ _optionalChain([this, 'access', _101 => _101._pool, 'optionalAccess', _102 => _102.assertStorageIsWritable, 'call', _103 => _103()]);
4595
4653
  if (index < 0 || index >= this.#items.length) {
4596
4654
  throw new Error(
4597
4655
  `Cannot delete list item at index "${index}". index should be between 0 and ${this.#items.length - 1}`
@@ -4624,7 +4682,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4624
4682
  }
4625
4683
  }
4626
4684
  clear() {
4627
- _optionalChain([this, 'access', _96 => _96._pool, 'optionalAccess', _97 => _97.assertStorageIsWritable, 'call', _98 => _98()]);
4685
+ _optionalChain([this, 'access', _104 => _104._pool, 'optionalAccess', _105 => _105.assertStorageIsWritable, 'call', _106 => _106()]);
4628
4686
  if (this._pool) {
4629
4687
  const ops = [];
4630
4688
  const reverseOps = [];
@@ -4658,7 +4716,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4658
4716
  }
4659
4717
  }
4660
4718
  set(index, item) {
4661
- _optionalChain([this, 'access', _99 => _99._pool, 'optionalAccess', _100 => _100.assertStorageIsWritable, 'call', _101 => _101()]);
4719
+ _optionalChain([this, 'access', _107 => _107._pool, 'optionalAccess', _108 => _108.assertStorageIsWritable, 'call', _109 => _109()]);
4662
4720
  if (index < 0 || index >= this.#items.length) {
4663
4721
  throw new Error(
4664
4722
  `Cannot set list item at index "${index}". index should be between 0 and ${this.#items.length - 1}`
@@ -4804,7 +4862,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4804
4862
  #shiftItemPosition(index, key) {
4805
4863
  const shiftedPosition = makePosition(
4806
4864
  key,
4807
- this.#items.length > index + 1 ? _optionalChain([this, 'access', _102 => _102.#items, 'access', _103 => _103[index + 1], 'optionalAccess', _104 => _104._parentPos]) : void 0
4865
+ this.#items.length > index + 1 ? _optionalChain([this, 'access', _110 => _110.#items, 'access', _111 => _111[index + 1], 'optionalAccess', _112 => _112._parentPos]) : void 0
4808
4866
  );
4809
4867
  this.#items[index]._setParentLink(this, shiftedPosition);
4810
4868
  }
@@ -4929,7 +4987,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
4929
4987
  const ops = [];
4930
4988
  const op = {
4931
4989
  id: this._id,
4932
- opId: _optionalChain([pool, 'optionalAccess', _105 => _105.generateOpId, 'call', _106 => _106()]),
4990
+ opId: _optionalChain([pool, 'optionalAccess', _113 => _113.generateOpId, 'call', _114 => _114()]),
4933
4991
  type: 7 /* CREATE_MAP */,
4934
4992
  parentId,
4935
4993
  parentKey
@@ -5064,7 +5122,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
5064
5122
  * @param value The value of the element to add. Should be serializable to JSON.
5065
5123
  */
5066
5124
  set(key, value) {
5067
- _optionalChain([this, 'access', _107 => _107._pool, 'optionalAccess', _108 => _108.assertStorageIsWritable, 'call', _109 => _109()]);
5125
+ _optionalChain([this, 'access', _115 => _115._pool, 'optionalAccess', _116 => _116.assertStorageIsWritable, 'call', _117 => _117()]);
5068
5126
  const oldValue = this.#map.get(key);
5069
5127
  if (oldValue) {
5070
5128
  oldValue._detach();
@@ -5110,7 +5168,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
5110
5168
  * @returns true if an element existed and has been removed, or false if the element does not exist.
5111
5169
  */
5112
5170
  delete(key) {
5113
- _optionalChain([this, 'access', _110 => _110._pool, 'optionalAccess', _111 => _111.assertStorageIsWritable, 'call', _112 => _112()]);
5171
+ _optionalChain([this, 'access', _118 => _118._pool, 'optionalAccess', _119 => _119.assertStorageIsWritable, 'call', _120 => _120()]);
5114
5172
  const item = this.#map.get(key);
5115
5173
  if (item === void 0) {
5116
5174
  return false;
@@ -5289,7 +5347,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
5289
5347
  if (this._id === void 0) {
5290
5348
  throw new Error("Cannot serialize item is not attached");
5291
5349
  }
5292
- const opId = _optionalChain([pool, 'optionalAccess', _113 => _113.generateOpId, 'call', _114 => _114()]);
5350
+ const opId = _optionalChain([pool, 'optionalAccess', _121 => _121.generateOpId, 'call', _122 => _122()]);
5293
5351
  const ops = [];
5294
5352
  const op = {
5295
5353
  type: 4 /* CREATE_OBJECT */,
@@ -5561,7 +5619,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
5561
5619
  * @param value The value of the property to add
5562
5620
  */
5563
5621
  set(key, value) {
5564
- _optionalChain([this, 'access', _115 => _115._pool, 'optionalAccess', _116 => _116.assertStorageIsWritable, 'call', _117 => _117()]);
5622
+ _optionalChain([this, 'access', _123 => _123._pool, 'optionalAccess', _124 => _124.assertStorageIsWritable, 'call', _125 => _125()]);
5565
5623
  this.update({ [key]: value });
5566
5624
  }
5567
5625
  /**
@@ -5576,7 +5634,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
5576
5634
  * @param key The key of the property to delete
5577
5635
  */
5578
5636
  delete(key) {
5579
- _optionalChain([this, 'access', _118 => _118._pool, 'optionalAccess', _119 => _119.assertStorageIsWritable, 'call', _120 => _120()]);
5637
+ _optionalChain([this, 'access', _126 => _126._pool, 'optionalAccess', _127 => _127.assertStorageIsWritable, 'call', _128 => _128()]);
5580
5638
  const keyAsString = key;
5581
5639
  const oldValue = this.#map.get(keyAsString);
5582
5640
  if (oldValue === void 0) {
@@ -5629,7 +5687,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
5629
5687
  * @param patch The object used to overrides properties
5630
5688
  */
5631
5689
  update(patch) {
5632
- _optionalChain([this, 'access', _121 => _121._pool, 'optionalAccess', _122 => _122.assertStorageIsWritable, 'call', _123 => _123()]);
5690
+ _optionalChain([this, 'access', _129 => _129._pool, 'optionalAccess', _130 => _130.assertStorageIsWritable, 'call', _131 => _131()]);
5633
5691
  if (this._pool === void 0 || this._id === void 0) {
5634
5692
  for (const key in patch) {
5635
5693
  const newValue = patch[key];
@@ -6177,6 +6235,83 @@ var ManagedOthers = class {
6177
6235
  }
6178
6236
  };
6179
6237
 
6238
+ // src/types/LiveblocksError.ts
6239
+ var LiveblocksError = class _LiveblocksError extends Error {
6240
+
6241
+ constructor(message, context, cause) {
6242
+ super(message, { cause });
6243
+ this.context = context;
6244
+ this.name = "LiveblocksError";
6245
+ }
6246
+ /** Convenience accessor for error.context.roomId (if available) */
6247
+ get roomId() {
6248
+ return this.context.roomId;
6249
+ }
6250
+ /** @deprecated Prefer using `context.code` instead, to enable type narrowing */
6251
+ get code() {
6252
+ return this.context.code;
6253
+ }
6254
+ /**
6255
+ * Creates a LiveblocksError from a generic error, by attaching Liveblocks
6256
+ * contextual information like room ID, thread ID, etc.
6257
+ */
6258
+ static from(context, cause) {
6259
+ return new _LiveblocksError(
6260
+ defaultMessageFromContext(context),
6261
+ context,
6262
+ cause
6263
+ );
6264
+ }
6265
+ };
6266
+ function defaultMessageFromContext(context) {
6267
+ switch (context.type) {
6268
+ case "ROOM_CONNECTION_ERROR": {
6269
+ switch (context.code) {
6270
+ case 4001:
6271
+ return "Not allowed to connect to the room";
6272
+ case 4005:
6273
+ return "Room is already full";
6274
+ case 4006:
6275
+ return "Kicked out of the room, because the room ID changed";
6276
+ default:
6277
+ return "Could not connect to the room";
6278
+ }
6279
+ }
6280
+ case "CREATE_THREAD_ERROR":
6281
+ return "Could not create new thread";
6282
+ case "DELETE_THREAD_ERROR":
6283
+ return "Could not delete thread";
6284
+ case "EDIT_THREAD_METADATA_ERROR":
6285
+ return "Could not edit thread metadata";
6286
+ case "MARK_THREAD_AS_RESOLVED_ERROR":
6287
+ return "Could not mark thread as resolved";
6288
+ case "MARK_THREAD_AS_UNRESOLVED_ERROR":
6289
+ return "Could not mark thread as unresolved";
6290
+ case "CREATE_COMMENT_ERROR":
6291
+ return "Could not create new comment";
6292
+ case "EDIT_COMMENT_ERROR":
6293
+ return "Could not edit comment";
6294
+ case "DELETE_COMMENT_ERROR":
6295
+ return "Could not delete comment";
6296
+ case "ADD_REACTION_ERROR":
6297
+ return "Could not add reaction";
6298
+ case "REMOVE_REACTION_ERROR":
6299
+ return "Could not remove reaction";
6300
+ case "MARK_INBOX_NOTIFICATION_AS_READ_ERROR":
6301
+ return "Could not mark inbox notification as read";
6302
+ case "DELETE_INBOX_NOTIFICATION_ERROR":
6303
+ return "Could not delete inbox notification";
6304
+ case "MARK_ALL_INBOX_NOTIFICATIONS_AS_READ_ERROR":
6305
+ return "Could not mark all inbox notifications as read";
6306
+ case "DELETE_ALL_INBOX_NOTIFICATIONS_ERROR":
6307
+ return "Could not delete all inbox notifications";
6308
+ case "UPDATE_NOTIFICATION_SETTINGS_ERROR":
6309
+ return "Could not update notification settings";
6310
+ default:
6311
+ return assertNever(context, "Unhandled case");
6312
+ }
6313
+ }
6314
+
6180
6315
  // src/room.ts
6181
6316
  var MAX_SOCKET_MESSAGE_SIZE = 1024 * 1024 - 1024;
6182
6317
  function makeIdFactory(connectionId) {
@@ -6201,15 +6336,15 @@ function installBackgroundTabSpy() {
6201
6336
  const doc = typeof document !== "undefined" ? document : void 0;
6202
6337
  const inBackgroundSince = { current: null };
6203
6338
  function onVisibilityChange() {
6204
- if (_optionalChain([doc, 'optionalAccess', _124 => _124.visibilityState]) === "hidden") {
6339
+ if (_optionalChain([doc, 'optionalAccess', _132 => _132.visibilityState]) === "hidden") {
6205
6340
  inBackgroundSince.current = _nullishCoalesce(inBackgroundSince.current, () => ( Date.now()));
6206
6341
  } else {
6207
6342
  inBackgroundSince.current = null;
6208
6343
  }
6209
6344
  }
6210
- _optionalChain([doc, 'optionalAccess', _125 => _125.addEventListener, 'call', _126 => _126("visibilitychange", onVisibilityChange)]);
6345
+ _optionalChain([doc, 'optionalAccess', _133 => _133.addEventListener, 'call', _134 => _134("visibilitychange", onVisibilityChange)]);
6211
6346
  const unsub = () => {
6212
- _optionalChain([doc, 'optionalAccess', _127 => _127.removeEventListener, 'call', _128 => _128("visibilitychange", onVisibilityChange)]);
6347
+ _optionalChain([doc, 'optionalAccess', _135 => _135.removeEventListener, 'call', _136 => _136("visibilitychange", onVisibilityChange)]);
6213
6348
  };
6214
6349
  return [inBackgroundSince, unsub];
6215
6350
  }
@@ -6341,13 +6476,17 @@ function createRoom(options, config) {
6341
6476
  managedSocket.events.statusDidChange.subscribe(handleConnectionLossEvent);
6342
6477
  managedSocket.events.didConnect.subscribe(onDidConnect);
6343
6478
  managedSocket.events.didDisconnect.subscribe(onDidDisconnect);
6344
- managedSocket.events.onLiveblocksError.subscribe((err) => {
6345
- if (process.env.NODE_ENV !== "production") {
6346
- error2(
6347
- `Connection to websocket server closed. Reason: ${err.message} (code: ${err.code}).`
6348
- );
6479
+ managedSocket.events.onConnectionError.subscribe(({ message, code }) => {
6480
+ const type = "ROOM_CONNECTION_ERROR";
6481
+ const err = new LiveblocksError(message, { type, code, roomId });
6482
+ const didNotify = config.errorEventSource.notify(err);
6483
+ if (!didNotify) {
6484
+ if (process.env.NODE_ENV !== "production") {
6485
+ error2(
6486
+ `Connection to websocket server closed. Reason: ${message} (code: ${code}).`
6487
+ );
6488
+ }
6349
6489
  }
6350
- eventHub.error.notify(err);
6351
6490
  });
6352
6491
  const pool = {
6353
6492
  roomId: config.roomId,
@@ -6390,7 +6529,7 @@ function createRoom(options, config) {
6390
6529
  }
6391
6530
  },
6392
6531
  assertStorageIsWritable: () => {
6393
- const scopes = _optionalChain([context, 'access', _129 => _129.dynamicSessionInfoSig, 'access', _130 => _130.get, 'call', _131 => _131(), 'optionalAccess', _132 => _132.scopes]);
6532
+ const scopes = _optionalChain([context, 'access', _137 => _137.dynamicSessionInfoSig, 'access', _138 => _138.get, 'call', _139 => _139(), 'optionalAccess', _140 => _140.scopes]);
6394
6533
  if (scopes === void 0) {
6395
6534
  return;
6396
6535
  }
@@ -6410,7 +6549,6 @@ function createRoom(options, config) {
6410
6549
  self: makeEventSource(),
6411
6550
  myPresence: makeEventSource(),
6412
6551
  others: makeEventSource(),
6413
- error: makeEventSource(),
6414
6552
  storageBatch: makeEventSource(),
6415
6553
  history: makeEventSource(),
6416
6554
  storageDidLoad: makeEventSource(),
@@ -6446,7 +6584,7 @@ function createRoom(options, config) {
6446
6584
  }
6447
6585
  function sendMessages(messages) {
6448
6586
  const serializedPayload = JSON.stringify(messages);
6449
- const nonce = _optionalChain([context, 'access', _133 => _133.dynamicSessionInfoSig, 'access', _134 => _134.get, 'call', _135 => _135(), 'optionalAccess', _136 => _136.nonce]);
6587
+ const nonce = _optionalChain([context, 'access', _141 => _141.dynamicSessionInfoSig, 'access', _142 => _142.get, 'call', _143 => _143(), 'optionalAccess', _144 => _144.nonce]);
6450
6588
  if (config.unstable_fallbackToHTTP && nonce) {
6451
6589
  const size = new TextEncoder().encode(serializedPayload).length;
6452
6590
  if (size > MAX_SOCKET_MESSAGE_SIZE) {
@@ -6504,7 +6642,7 @@ function createRoom(options, config) {
6504
6642
  } else {
6505
6643
  context.root = LiveObject._fromItems(message.items, pool);
6506
6644
  }
6507
- const canWrite = _nullishCoalesce(_optionalChain([self, 'access', _137 => _137.get, 'call', _138 => _138(), 'optionalAccess', _139 => _139.canWrite]), () => ( true));
6645
+ const canWrite = _nullishCoalesce(_optionalChain([self, 'access', _145 => _145.get, 'call', _146 => _146(), 'optionalAccess', _147 => _147.canWrite]), () => ( true));
6508
6646
  const stackSizeBefore = context.undoStack.length;
6509
6647
  for (const key in context.initialStorage) {
6510
6648
  if (context.root.get(key) === void 0) {
@@ -6707,7 +6845,7 @@ function createRoom(options, config) {
6707
6845
  }
6708
6846
  context.myPresence.patch(patch);
6709
6847
  if (context.activeBatch) {
6710
- if (_optionalChain([options2, 'optionalAccess', _140 => _140.addToHistory])) {
6848
+ if (_optionalChain([options2, 'optionalAccess', _148 => _148.addToHistory])) {
6711
6849
  context.activeBatch.reverseOps.unshift({
6712
6850
  type: "presence",
6713
6851
  data: oldValues
@@ -6716,7 +6854,7 @@ function createRoom(options, config) {
6716
6854
  context.activeBatch.updates.presence = true;
6717
6855
  } else {
6718
6856
  flushNowOrSoon();
6719
- if (_optionalChain([options2, 'optionalAccess', _141 => _141.addToHistory])) {
6857
+ if (_optionalChain([options2, 'optionalAccess', _149 => _149.addToHistory])) {
6720
6858
  addToUndoStack([{ type: "presence", data: oldValues }]);
6721
6859
  }
6722
6860
  notify({ presence: true });
@@ -6889,6 +7027,7 @@ function createRoom(options, config) {
6889
7027
  processInitialStorage(message);
6890
7028
  break;
6891
7029
  }
7030
+ // Write event
6892
7031
  case 201 /* UPDATE_STORAGE */: {
6893
7032
  const applyResult = applyOps(message.ops, false);
6894
7033
  for (const [key, value] of applyResult.updates.storageUpdates) {
@@ -6899,6 +7038,11 @@ function createRoom(options, config) {
6899
7038
  }
6900
7039
  break;
6901
7040
  }
7041
+ // Receiving a RejectedOps message in the client means that the server is no
7042
+ // longer in sync with the client. Trying to synchronize the client again by
7043
+ // rolling back particular Ops may be hard/impossible. It's fine to not try and
7044
+ // accept the out-of-sync reality and throw an error. We look at this kind of bug
7045
+ // as a developer-owned bug. In production, these errors are not expected to happen.
6902
7046
  case 299 /* REJECT_STORAGE_OP */: {
6903
7047
  errorWithTitle(
6904
7048
  "Storage mutation rejection error",
@@ -6907,7 +7051,7 @@ function createRoom(options, config) {
6907
7051
  if (process.env.NODE_ENV !== "production") {
6908
7052
  const traces = /* @__PURE__ */ new Set();
6909
7053
  for (const opId of message.opIds) {
6910
- const trace = _optionalChain([context, 'access', _142 => _142.opStackTraces, 'optionalAccess', _143 => _143.get, 'call', _144 => _144(opId)]);
7054
+ const trace = _optionalChain([context, 'access', _150 => _150.opStackTraces, 'optionalAccess', _151 => _151.get, 'call', _152 => _152(opId)]);
6911
7055
  if (trace) {
6912
7056
  traces.add(trace);
6913
7057
  }
@@ -7040,7 +7184,7 @@ ${Array.from(traces).join("\n\n")}`
7040
7184
  const unacknowledgedOps = new Map(context.unacknowledgedOps);
7041
7185
  createOrUpdateRootFromMessage(message);
7042
7186
  applyAndSendOps(unacknowledgedOps);
7043
- _optionalChain([_resolveStoragePromise, 'optionalCall', _145 => _145()]);
7187
+ _optionalChain([_resolveStoragePromise, 'optionalCall', _153 => _153()]);
7044
7188
  notifyStorageStatus();
7045
7189
  eventHub.storageDidLoad.notify();
7046
7190
  }
@@ -7242,7 +7386,6 @@ ${Array.from(traces).join("\n\n")}`
7242
7386
  others: eventHub.others.observable,
7243
7387
  self: eventHub.self.observable,
7244
7388
  myPresence: eventHub.myPresence.observable,
7245
- error: eventHub.error.observable,
7246
7389
  /** @deprecated */
7247
7390
  storage: eventHub.storageBatch.observable,
7248
7391
  storageBatch: eventHub.storageBatch.observable,
@@ -7262,8 +7405,8 @@ ${Array.from(traces).join("\n\n")}`
7262
7405
  async function getThreads(options2) {
7263
7406
  return httpClient.getThreads({
7264
7407
  roomId,
7265
- query: _optionalChain([options2, 'optionalAccess', _146 => _146.query]),
7266
- cursor: _optionalChain([options2, 'optionalAccess', _147 => _147.cursor])
7408
+ query: _optionalChain([options2, 'optionalAccess', _154 => _154.query]),
7409
+ cursor: _optionalChain([options2, 'optionalAccess', _155 => _155.cursor])
7267
7410
  });
7268
7411
  }
7269
7412
  async function getThread(threadId) {
@@ -7364,7 +7507,7 @@ ${Array.from(traces).join("\n\n")}`
7364
7507
  function getNotificationSettings(options2) {
7365
7508
  return httpClient.getNotificationSettings({
7366
7509
  roomId,
7367
- signal: _optionalChain([options2, 'optionalAccess', _148 => _148.signal])
7510
+ signal: _optionalChain([options2, 'optionalAccess', _156 => _156.signal])
7368
7511
  });
7369
7512
  }
7370
7513
  function updateNotificationSettings(settings) {
@@ -7386,7 +7529,7 @@ ${Array.from(traces).join("\n\n")}`
7386
7529
  {
7387
7530
  [kInternal]: {
7388
7531
  get presenceBuffer() {
7389
- return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _149 => _149.buffer, 'access', _150 => _150.presenceUpdates, 'optionalAccess', _151 => _151.data]), () => ( null)));
7532
+ return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _157 => _157.buffer, 'access', _158 => _158.presenceUpdates, 'optionalAccess', _159 => _159.data]), () => ( null)));
7390
7533
  },
7391
7534
  // prettier-ignore
7392
7535
  get undoStack() {
@@ -7401,9 +7544,9 @@ ${Array.from(traces).join("\n\n")}`
7401
7544
  return context.yjsProvider;
7402
7545
  },
7403
7546
  setYjsProvider(newProvider) {
7404
- _optionalChain([context, 'access', _152 => _152.yjsProvider, 'optionalAccess', _153 => _153.off, 'call', _154 => _154("status", yjsStatusDidChange)]);
7547
+ _optionalChain([context, 'access', _160 => _160.yjsProvider, 'optionalAccess', _161 => _161.off, 'call', _162 => _162("status", yjsStatusDidChange)]);
7405
7548
  context.yjsProvider = newProvider;
7406
- _optionalChain([newProvider, 'optionalAccess', _155 => _155.on, 'call', _156 => _156("status", yjsStatusDidChange)]);
7549
+ _optionalChain([newProvider, 'optionalAccess', _163 => _163.on, 'call', _164 => _164("status", yjsStatusDidChange)]);
7407
7550
  context.yjsProviderDidChange.notify();
7408
7551
  },
7409
7552
  yjsProviderDidChange: context.yjsProviderDidChange.observable,
@@ -7433,13 +7576,17 @@ ${Array.from(traces).join("\n\n")}`
7433
7576
  attachmentUrlsStore: httpClient.getOrCreateAttachmentUrlsStore(roomId)
7434
7577
  },
7435
7578
  id: config.roomId,
7436
- subscribe: makeClassicSubscribeFn(events),
7579
+ subscribe: makeClassicSubscribeFn(
7580
+ config.roomId,
7581
+ events,
7582
+ config.errorEventSource
7583
+ ),
7437
7584
  connect: () => managedSocket.connect(),
7438
7585
  reconnect: () => managedSocket.reconnect(),
7439
7586
  disconnect: () => managedSocket.disconnect(),
7440
7587
  destroy: () => {
7441
7588
  syncSourceForStorage.destroy();
7442
- _optionalChain([context, 'access', _157 => _157.yjsProvider, 'optionalAccess', _158 => _158.off, 'call', _159 => _159("status", yjsStatusDidChange)]);
7589
+ _optionalChain([context, 'access', _165 => _165.yjsProvider, 'optionalAccess', _166 => _166.off, 'call', _167 => _167("status", yjsStatusDidChange)]);
7443
7590
  syncSourceForYjs.destroy();
7444
7591
  uninstallBgTabSpy();
7445
7592
  managedSocket.destroy();
@@ -7502,7 +7649,7 @@ ${Array.from(traces).join("\n\n")}`
7502
7649
  { enumerable: false }
7503
7650
  );
7504
7651
  }
7505
- function makeClassicSubscribeFn(events) {
7652
+ function makeClassicSubscribeFn(roomId, events, errorEvents) {
7506
7653
  function subscribeToLiveStructureDeeply(node, callback) {
7507
7654
  return events.storageBatch.subscribe((updates) => {
7508
7655
  const relatedUpdates = updates.filter(
@@ -7542,8 +7689,13 @@ function makeClassicSubscribeFn(events) {
7542
7689
  return cb(others, internalEvent);
7543
7690
  });
7544
7691
  }
7545
- case "error":
7546
- return events.error.subscribe(callback);
7692
+ case "error": {
7693
+ return errorEvents.subscribe((err) => {
7694
+ if (err.roomId === roomId) {
7695
+ return callback(err);
7696
+ }
7697
+ });
7698
+ }
7547
7699
  case "status":
7548
7700
  return events.status.subscribe(callback);
7549
7701
  case "lost-connection":
@@ -7560,6 +7712,7 @@ function makeClassicSubscribeFn(events) {
7560
7712
  return events.comments.subscribe(
7561
7713
  callback
7562
7714
  );
7715
+ // istanbul ignore next
7563
7716
  default:
7564
7717
  return assertNever(
7565
7718
  first,
@@ -7577,7 +7730,7 @@ function makeClassicSubscribeFn(events) {
7577
7730
  }
7578
7731
  if (isLiveNode(first)) {
7579
7732
  const node = first;
7580
- if (_optionalChain([options, 'optionalAccess', _160 => _160.isDeep])) {
7733
+ if (_optionalChain([options, 'optionalAccess', _168 => _168.isDeep])) {
7581
7734
  const storageCallback = second;
7582
7735
  return subscribeToLiveStructureDeeply(node, storageCallback);
7583
7736
  } else {
@@ -7656,8 +7809,8 @@ function createClient(options) {
7656
7809
  const userId = token.k === "sec-legacy" /* SECRET_LEGACY */ ? token.id : token.uid;
7657
7810
  currentUserId.set(() => userId);
7658
7811
  });
7659
- const fetchPolyfill = _optionalChain([clientOptions, 'access', _161 => _161.polyfills, 'optionalAccess', _162 => _162.fetch]) || /* istanbul ignore next */
7660
- _optionalChain([globalThis, 'access', _163 => _163.fetch, 'optionalAccess', _164 => _164.bind, 'call', _165 => _165(globalThis)]);
7812
+ const fetchPolyfill = _optionalChain([clientOptions, 'access', _169 => _169.polyfills, 'optionalAccess', _170 => _170.fetch]) || /* istanbul ignore next */
7813
+ _optionalChain([globalThis, 'access', _171 => _171.fetch, 'optionalAccess', _172 => _172.bind, 'call', _173 => _173(globalThis)]);
7661
7814
  const httpClient = createApiClient({
7662
7815
  baseUrl,
7663
7816
  fetchPolyfill,
@@ -7708,12 +7861,13 @@ function createClient(options) {
7708
7861
  createSocket: makeCreateSocketDelegateForRoom(
7709
7862
  roomId,
7710
7863
  baseUrl,
7711
- _optionalChain([clientOptions, 'access', _166 => _166.polyfills, 'optionalAccess', _167 => _167.WebSocket])
7864
+ _optionalChain([clientOptions, 'access', _174 => _174.polyfills, 'optionalAccess', _175 => _175.WebSocket])
7712
7865
  ),
7713
7866
  authenticate: makeAuthDelegateForRoom(roomId, authManager)
7714
7867
  })),
7715
7868
  enableDebugLogging: clientOptions.enableDebugLogging,
7716
7869
  baseUrl,
7870
+ errorEventSource: liveblocksErrorSource,
7717
7871
  unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP,
7718
7872
  unstable_streamData: !!clientOptions.unstable_streamData,
7719
7873
  roomHttpClient: httpClient,
@@ -7730,7 +7884,7 @@ function createClient(options) {
7730
7884
  const shouldConnect = _nullishCoalesce(options2.autoConnect, () => ( true));
7731
7885
  if (shouldConnect) {
7732
7886
  if (typeof atob === "undefined") {
7733
- if (_optionalChain([clientOptions, 'access', _168 => _168.polyfills, 'optionalAccess', _169 => _169.atob]) === void 0) {
7887
+ if (_optionalChain([clientOptions, 'access', _176 => _176.polyfills, 'optionalAccess', _177 => _177.atob]) === void 0) {
7734
7888
  throw new Error(
7735
7889
  "You need to polyfill atob to use the client in your environment. Please follow the instructions at https://liveblocks.io/docs/errors/liveblocks-client/atob-polyfill"
7736
7890
  );
@@ -7742,7 +7896,7 @@ function createClient(options) {
7742
7896
  return leaseRoom(newRoomDetails);
7743
7897
  }
7744
7898
  function getRoom(roomId) {
7745
- const room = _optionalChain([roomsById, 'access', _170 => _170.get, 'call', _171 => _171(roomId), 'optionalAccess', _172 => _172.room]);
7899
+ const room = _optionalChain([roomsById, 'access', _178 => _178.get, 'call', _179 => _179(roomId), 'optionalAccess', _180 => _180.room]);
7746
7900
  return room ? room : null;
7747
7901
  }
7748
7902
  function logout() {
@@ -7762,7 +7916,7 @@ function createClient(options) {
7762
7916
  const batchedResolveUsers = new Batch(
7763
7917
  async (batchedUserIds) => {
7764
7918
  const userIds = batchedUserIds.flat();
7765
- const users = await _optionalChain([resolveUsers, 'optionalCall', _173 => _173({ userIds })]);
7919
+ const users = await _optionalChain([resolveUsers, 'optionalCall', _181 => _181({ userIds })]);
7766
7920
  warnIfNoResolveUsers();
7767
7921
  return _nullishCoalesce(users, () => ( userIds.map(() => void 0)));
7768
7922
  },
@@ -7780,7 +7934,7 @@ function createClient(options) {
7780
7934
  const batchedResolveRoomsInfo = new Batch(
7781
7935
  async (batchedRoomIds) => {
7782
7936
  const roomIds = batchedRoomIds.flat();
7783
- const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _174 => _174({ roomIds })]);
7937
+ const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _182 => _182({ roomIds })]);
7784
7938
  warnIfNoResolveRoomsInfo();
7785
7939
  return _nullishCoalesce(roomsInfo, () => ( roomIds.map(() => void 0)));
7786
7940
  },
@@ -7796,6 +7950,7 @@ function createClient(options) {
7796
7950
  }
7797
7951
  const syncStatusSources = [];
7798
7952
  const syncStatusSignal = new Signal("synchronized");
7953
+ const liveblocksErrorSource = makeEventSource();
7799
7954
  function getSyncStatus() {
7800
7955
  const status = syncStatusSignal.get();
7801
7956
  return status === "synchronizing" ? status : "synchronized";
@@ -7832,7 +7987,7 @@ function createClient(options) {
7832
7987
  }
7833
7988
  };
7834
7989
  const win = typeof window !== "undefined" ? window : void 0;
7835
- _optionalChain([win, 'optionalAccess', _175 => _175.addEventListener, 'call', _176 => _176("beforeunload", maybePreventClose)]);
7990
+ _optionalChain([win, 'optionalAccess', _183 => _183.addEventListener, 'call', _184 => _184("beforeunload", maybePreventClose)]);
7836
7991
  }
7837
7992
  const client = Object.defineProperty(
7838
7993
  {
@@ -7855,6 +8010,7 @@ function createClient(options) {
7855
8010
  },
7856
8011
  getSyncStatus,
7857
8012
  events: {
8013
+ error: liveblocksErrorSource,
7858
8014
  syncStatus: syncStatusSignal
7859
8015
  },
7860
8016
  // Internal
@@ -7870,7 +8026,14 @@ function createClient(options) {
7870
8026
  httpClient,
7871
8027
  // Type-level helper only, it's effectively only an identity-function at runtime
7872
8028
  as: () => client,
7873
- createSyncSource
8029
+ createSyncSource,
8030
+ emitError: (context, cause) => {
8031
+ const error3 = LiveblocksError.from(context, cause);
8032
+ const didNotify = liveblocksErrorSource.notify(error3);
8033
+ if (!didNotify) {
8034
+ error2(error3.message);
8035
+ }
8036
+ }
7874
8037
  }
7875
8038
  },
7876
8039
  kInternal,
@@ -7949,7 +8112,7 @@ var commentBodyElementsTypes = {
7949
8112
  mention: "inline"
7950
8113
  };
7951
8114
  function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
7952
- if (!body || !_optionalChain([body, 'optionalAccess', _177 => _177.content])) {
8115
+ if (!body || !_optionalChain([body, 'optionalAccess', _185 => _185.content])) {
7953
8116
  return;
7954
8117
  }
7955
8118
  const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
@@ -7959,13 +8122,13 @@ function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
7959
8122
  for (const block of body.content) {
7960
8123
  if (type === "all" || type === "block") {
7961
8124
  if (guard(block)) {
7962
- _optionalChain([visitor, 'optionalCall', _178 => _178(block)]);
8125
+ _optionalChain([visitor, 'optionalCall', _186 => _186(block)]);
7963
8126
  }
7964
8127
  }
7965
8128
  if (type === "all" || type === "inline") {
7966
8129
  for (const inline of block.children) {
7967
8130
  if (guard(inline)) {
7968
- _optionalChain([visitor, 'optionalCall', _179 => _179(inline)]);
8131
+ _optionalChain([visitor, 'optionalCall', _187 => _187(inline)]);
7969
8132
  }
7970
8133
  }
7971
8134
  }
@@ -7990,7 +8153,7 @@ async function resolveUsersInCommentBody(body, resolveUsers) {
7990
8153
  userIds
7991
8154
  });
7992
8155
  for (const [index, userId] of userIds.entries()) {
7993
- const user = _optionalChain([users, 'optionalAccess', _180 => _180[index]]);
8156
+ const user = _optionalChain([users, 'optionalAccess', _188 => _188[index]]);
7994
8157
  if (user) {
7995
8158
  resolvedUsers.set(userId, user);
7996
8159
  }
@@ -8117,7 +8280,7 @@ var stringifyCommentBodyPlainElements = {
8117
8280
  text: ({ element }) => element.text,
8118
8281
  link: ({ element }) => _nullishCoalesce(element.text, () => ( element.url)),
8119
8282
  mention: ({ element, user }) => {
8120
- return `@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _181 => _181.name]), () => ( element.id))}`;
8283
+ return `@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _189 => _189.name]), () => ( element.id))}`;
8121
8284
  }
8122
8285
  };
8123
8286
  var stringifyCommentBodyHtmlElements = {
@@ -8147,7 +8310,7 @@ var stringifyCommentBodyHtmlElements = {
8147
8310
  return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${_nullishCoalesce(element.text, () => ( element.url))}</a>`;
8148
8311
  },
8149
8312
  mention: ({ element, user }) => {
8150
- return html`<span data-mention>@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _182 => _182.name]), () => ( element.id))}</span>`;
8313
+ return html`<span data-mention>@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _190 => _190.name]), () => ( element.id))}</span>`;
8151
8314
  }
8152
8315
  };
8153
8316
  var stringifyCommentBodyMarkdownElements = {
@@ -8177,19 +8340,19 @@ var stringifyCommentBodyMarkdownElements = {
8177
8340
  return markdown`[${_nullishCoalesce(element.text, () => ( element.url))}](${href})`;
8178
8341
  },
8179
8342
  mention: ({ element, user }) => {
8180
- return markdown`@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _183 => _183.name]), () => ( element.id))}`;
8343
+ return markdown`@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _191 => _191.name]), () => ( element.id))}`;
8181
8344
  }
8182
8345
  };
8183
8346
  async function stringifyCommentBody(body, options) {
8184
- const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _184 => _184.format]), () => ( "plain"));
8185
- const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _185 => _185.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
8347
+ const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _192 => _192.format]), () => ( "plain"));
8348
+ const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _193 => _193.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
8186
8349
  const elements = {
8187
8350
  ...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
8188
- ..._optionalChain([options, 'optionalAccess', _186 => _186.elements])
8351
+ ..._optionalChain([options, 'optionalAccess', _194 => _194.elements])
8189
8352
  };
8190
8353
  const resolvedUsers = await resolveUsersInCommentBody(
8191
8354
  body,
8192
- _optionalChain([options, 'optionalAccess', _187 => _187.resolveUsers])
8355
+ _optionalChain([options, 'optionalAccess', _195 => _195.resolveUsers])
8193
8356
  );
8194
8357
  const blocks = body.content.flatMap((block, blockIndex) => {
8195
8358
  switch (block.type) {
@@ -8480,12 +8643,12 @@ function legacy_patchImmutableNode(state, path, update) {
8480
8643
  }
8481
8644
  const newState = Object.assign({}, state);
8482
8645
  for (const key in update.updates) {
8483
- if (_optionalChain([update, 'access', _188 => _188.updates, 'access', _189 => _189[key], 'optionalAccess', _190 => _190.type]) === "update") {
8646
+ if (_optionalChain([update, 'access', _196 => _196.updates, 'access', _197 => _197[key], 'optionalAccess', _198 => _198.type]) === "update") {
8484
8647
  const val = update.node.get(key);
8485
8648
  if (val !== void 0) {
8486
8649
  newState[key] = lsonToJson(val);
8487
8650
  }
8488
- } else if (_optionalChain([update, 'access', _191 => _191.updates, 'access', _192 => _192[key], 'optionalAccess', _193 => _193.type]) === "delete") {
8651
+ } else if (_optionalChain([update, 'access', _199 => _199.updates, 'access', _200 => _200[key], 'optionalAccess', _201 => _201.type]) === "delete") {
8489
8652
  delete newState[key];
8490
8653
  }
8491
8654
  }
@@ -8546,12 +8709,12 @@ function legacy_patchImmutableNode(state, path, update) {
8546
8709
  }
8547
8710
  const newState = Object.assign({}, state);
8548
8711
  for (const key in update.updates) {
8549
- if (_optionalChain([update, 'access', _194 => _194.updates, 'access', _195 => _195[key], 'optionalAccess', _196 => _196.type]) === "update") {
8712
+ if (_optionalChain([update, 'access', _202 => _202.updates, 'access', _203 => _203[key], 'optionalAccess', _204 => _204.type]) === "update") {
8550
8713
  const value = update.node.get(key);
8551
8714
  if (value !== void 0) {
8552
8715
  newState[key] = lsonToJson(value);
8553
8716
  }
8554
- } else if (_optionalChain([update, 'access', _197 => _197.updates, 'access', _198 => _198[key], 'optionalAccess', _199 => _199.type]) === "delete") {
8717
+ } else if (_optionalChain([update, 'access', _205 => _205.updates, 'access', _206 => _206[key], 'optionalAccess', _207 => _207.type]) === "delete") {
8555
8718
  delete newState[key];
8556
8719
  }
8557
8720
  }
@@ -8622,9 +8785,9 @@ function makePoller(callback, intervalMs, options) {
8622
8785
  const startTime = performance.now();
8623
8786
  const doc = typeof document !== "undefined" ? document : void 0;
8624
8787
  const win = typeof window !== "undefined" ? window : void 0;
8625
- const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _200 => _200.maxStaleTimeMs]), () => ( Number.POSITIVE_INFINITY));
8788
+ const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _208 => _208.maxStaleTimeMs]), () => ( Number.POSITIVE_INFINITY));
8626
8789
  const context = {
8627
- inForeground: _optionalChain([doc, 'optionalAccess', _201 => _201.visibilityState]) !== "hidden",
8790
+ inForeground: _optionalChain([doc, 'optionalAccess', _209 => _209.visibilityState]) !== "hidden",
8628
8791
  lastSuccessfulPollAt: startTime,
8629
8792
  count: 0,
8630
8793
  backoff: 0
@@ -8702,10 +8865,10 @@ function makePoller(callback, intervalMs, options) {
8702
8865
  pollNowIfStale();
8703
8866
  }
8704
8867
  function onVisibilityChange() {
8705
- setInForeground(_optionalChain([doc, 'optionalAccess', _202 => _202.visibilityState]) !== "hidden");
8868
+ setInForeground(_optionalChain([doc, 'optionalAccess', _210 => _210.visibilityState]) !== "hidden");
8706
8869
  }
8707
- _optionalChain([doc, 'optionalAccess', _203 => _203.addEventListener, 'call', _204 => _204("visibilitychange", onVisibilityChange)]);
8708
- _optionalChain([win, 'optionalAccess', _205 => _205.addEventListener, 'call', _206 => _206("online", onVisibilityChange)]);
8870
+ _optionalChain([doc, 'optionalAccess', _211 => _211.addEventListener, 'call', _212 => _212("visibilitychange", onVisibilityChange)]);
8871
+ _optionalChain([win, 'optionalAccess', _213 => _213.addEventListener, 'call', _214 => _214("online", onVisibilityChange)]);
8709
8872
  fsm.start();
8710
8873
  return {
8711
8874
  inc,
@@ -8921,5 +9084,8 @@ var NotificationsApiError = HttpError;
8921
9084
 
8922
9085
 
8923
9086
 
8924
- exports.ClientMsgCode = ClientMsgCode; exports.CommentsApiError = CommentsApiError; exports.CrdtType = CrdtType; exports.DerivedSignal = DerivedSignal; exports.HttpError = HttpError; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.MutableSignal = MutableSignal; exports.NotificationsApiError = NotificationsApiError; exports.OpCode = OpCode; exports.Permission = Permission; exports.Promise_withResolvers = Promise_withResolvers; exports.ServerMsgCode = ServerMsgCode; exports.Signal = Signal; exports.SortedList = SortedList; exports.TextEditorType = TextEditorType; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.ackOp = ackOp; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.autoRetry = autoRetry; exports.b64decode = b64decode; exports.batch = batch; exports.chunk = chunk; exports.cloneLson = cloneLson; exports.compactObject = compactObject; exports.console = fancy_console_exports; exports.convertToCommentData = convertToCommentData; exports.convertToCommentUserReaction = convertToCommentUserReaction; exports.convertToInboxNotificationData = convertToInboxNotificationData; exports.convertToThreadData = convertToThreadData; exports.createClient = createClient; exports.createCommentAttachmentId = createCommentAttachmentId; exports.createCommentId = createCommentId; exports.createInboxNotificationId = createInboxNotificationId; exports.createThreadId = createThreadId; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.detectDupes = detectDupes; exports.errorIf = errorIf; exports.freeze = freeze; exports.generateCommentUrl = generateCommentUrl; exports.getMentionedIdsFromCommentBody = getMentionedIdsFromCommentBody; exports.html = html; exports.htmlSafe = htmlSafe; exports.isChildCrdt = isChildCrdt; exports.isCommentBodyLink = isCommentBodyLink; exports.isCommentBodyMention = isCommentBodyMention; exports.isCommentBodyText = isCommentBodyText; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isLiveNode = isLiveNode; exports.isPlainObject = isPlainObject; exports.isRootCrdt = isRootCrdt; exports.kInternal = kInternal; exports.legacy_patchImmutableObject = legacy_patchImmutableObject; exports.lsonToJson = lsonToJson; exports.makeEventSource = makeEventSource; exports.makePoller = makePoller; exports.makePosition = makePosition; exports.mapValues = mapValues; exports.memoizeOnSuccess = memoizeOnSuccess; exports.nanoid = nanoid; exports.nn = nn; exports.objectToQuery = objectToQuery; exports.patchLiveObjectKey = patchLiveObjectKey; exports.raise = raise; exports.resolveUsersInCommentBody = resolveUsersInCommentBody; exports.shallow = shallow; exports.stringify = stringify; exports.stringifyCommentBody = stringifyCommentBody; exports.throwUsageError = throwUsageError; exports.toAbsoluteUrl = toAbsoluteUrl; exports.toPlainLson = toPlainLson; exports.tryParseJson = tryParseJson; exports.url = url; exports.urljoin = urljoin; exports.wait = wait; exports.withTimeout = withTimeout;
9087
+
9088
+
9089
+
9090
+ exports.ClientMsgCode = ClientMsgCode; exports.CommentsApiError = CommentsApiError; exports.CrdtType = CrdtType; exports.DefaultMap = DefaultMap; exports.DerivedSignal = DerivedSignal; exports.HttpError = HttpError; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.LiveblocksError = LiveblocksError; exports.MutableSignal = MutableSignal; exports.NotificationsApiError = NotificationsApiError; exports.OpCode = OpCode; exports.Permission = Permission; exports.Promise_withResolvers = Promise_withResolvers; exports.ServerMsgCode = ServerMsgCode; exports.Signal = Signal; exports.SortedList = SortedList; exports.TextEditorType = TextEditorType; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.ackOp = ackOp; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.autoRetry = autoRetry; exports.b64decode = b64decode; exports.batch = batch; exports.chunk = chunk; exports.cloneLson = cloneLson; exports.compactObject = compactObject; exports.console = fancy_console_exports; exports.convertToCommentData = convertToCommentData; exports.convertToCommentUserReaction = convertToCommentUserReaction; exports.convertToInboxNotificationData = convertToInboxNotificationData; exports.convertToThreadData = convertToThreadData; exports.createClient = createClient; exports.createCommentAttachmentId = createCommentAttachmentId; exports.createCommentId = createCommentId; exports.createInboxNotificationId = createInboxNotificationId; exports.createThreadId = createThreadId; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.detectDupes = detectDupes; exports.errorIf = errorIf; exports.freeze = freeze; exports.generateCommentUrl = generateCommentUrl; exports.getMentionedIdsFromCommentBody = getMentionedIdsFromCommentBody; exports.html = html; exports.htmlSafe = htmlSafe; exports.isChildCrdt = isChildCrdt; exports.isCommentBodyLink = isCommentBodyLink; exports.isCommentBodyMention = isCommentBodyMention; exports.isCommentBodyText = isCommentBodyText; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isLiveNode = isLiveNode; exports.isPlainObject = isPlainObject; exports.isRootCrdt = isRootCrdt; exports.isStartsWithOperator = isStartsWithOperator; exports.kInternal = kInternal; exports.legacy_patchImmutableObject = legacy_patchImmutableObject; exports.lsonToJson = lsonToJson; exports.makeEventSource = makeEventSource; exports.makePoller = makePoller; exports.makePosition = makePosition; exports.mapValues = mapValues; exports.memoizeOnSuccess = memoizeOnSuccess; exports.nanoid = nanoid; exports.nn = nn; exports.objectToQuery = objectToQuery; exports.patchLiveObjectKey = patchLiveObjectKey; exports.raise = raise; exports.resolveUsersInCommentBody = resolveUsersInCommentBody; exports.shallow = shallow; exports.stringify = stringify; exports.stringifyCommentBody = stringifyCommentBody; exports.throwUsageError = throwUsageError; exports.toAbsoluteUrl = toAbsoluteUrl; exports.toPlainLson = toPlainLson; exports.tryParseJson = tryParseJson; exports.url = url; exports.urljoin = urljoin; exports.wait = wait; exports.withTimeout = withTimeout;
8925
9091
  //# sourceMappingURL=index.js.map