@liveblocks/core 2.15.1 → 2.15.2

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.mjs 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.15.2";
10
10
  var PKG_FORMAT = "esm";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -385,19 +385,319 @@ function makeBufferableEventSource() {
385
385
  };
386
386
  }
387
387
 
388
+ // src/lib/freeze.ts
389
+ var freeze = process.env.NODE_ENV === "production" ? (
390
+ /* istanbul ignore next */
391
+ (x) => x
392
+ ) : Object.freeze;
393
+
394
+ // src/lib/signals.ts
395
+ var kSinks = Symbol("kSinks");
396
+ var kTrigger = Symbol("kTrigger");
397
+ var signalsToTrigger = null;
398
+ var trackedReads = null;
399
+ function batch(callback) {
400
+ if (signalsToTrigger !== null) {
401
+ callback();
402
+ return;
403
+ }
404
+ signalsToTrigger = /* @__PURE__ */ new Set();
405
+ try {
406
+ callback();
407
+ } finally {
408
+ for (const signal of signalsToTrigger) {
409
+ signal[kTrigger]();
410
+ }
411
+ signalsToTrigger = null;
412
+ }
413
+ }
414
+ function enqueueTrigger(signal) {
415
+ if (!signalsToTrigger) raise("Expected to be in an active batch");
416
+ signalsToTrigger.add(signal);
417
+ }
418
+ function merge(target, patch) {
419
+ let updated = false;
420
+ const newValue = { ...target };
421
+ Object.keys(patch).forEach((k) => {
422
+ const key = k;
423
+ const val = patch[key];
424
+ if (newValue[key] !== val) {
425
+ if (val === void 0) {
426
+ delete newValue[key];
427
+ } else {
428
+ newValue[key] = val;
429
+ }
430
+ updated = true;
431
+ }
432
+ });
433
+ return updated ? newValue : target;
434
+ }
435
+ var AbstractSignal = class {
436
+ /** @internal */
437
+ equals;
438
+ #eventSource;
439
+ /** @internal */
440
+ [kSinks];
441
+ constructor(equals) {
442
+ this.equals = equals ?? Object.is;
443
+ this.#eventSource = makeEventSource();
444
+ this[kSinks] = /* @__PURE__ */ new Set();
445
+ this.get = this.get.bind(this);
446
+ this.subscribe = this.subscribe.bind(this);
447
+ this.subscribeOnce = this.subscribeOnce.bind(this);
448
+ }
449
+ [Symbol.dispose]() {
450
+ this.#eventSource[Symbol.dispose]();
451
+ this.#eventSource = "(disposed)";
452
+ this.equals = "(disposed)";
453
+ }
454
+ get hasWatchers() {
455
+ if (this.#eventSource.count() > 0) return true;
456
+ for (const sink of this[kSinks]) {
457
+ if (sink.hasWatchers) {
458
+ return true;
459
+ }
460
+ }
461
+ return false;
462
+ }
463
+ [kTrigger]() {
464
+ this.#eventSource.notify();
465
+ for (const sink of this[kSinks]) {
466
+ enqueueTrigger(sink);
467
+ }
468
+ }
469
+ subscribe(callback) {
470
+ if (this.#eventSource.count() === 0) {
471
+ this.get();
472
+ }
473
+ return this.#eventSource.subscribe(callback);
474
+ }
475
+ subscribeOnce(callback) {
476
+ const unsub = this.subscribe(() => {
477
+ unsub();
478
+ return callback();
479
+ });
480
+ return unsub;
481
+ }
482
+ waitUntil() {
483
+ throw new Error("waitUntil not supported on Signals");
484
+ }
485
+ markSinksDirty() {
486
+ for (const sink of this[kSinks]) {
487
+ sink.markDirty();
488
+ }
489
+ }
490
+ addSink(sink) {
491
+ this[kSinks].add(sink);
492
+ }
493
+ removeSink(sink) {
494
+ this[kSinks].delete(sink);
495
+ }
496
+ asReadonly() {
497
+ return this;
498
+ }
499
+ };
500
+ var Signal = class extends AbstractSignal {
501
+ #value;
502
+ constructor(value, equals) {
503
+ super(equals);
504
+ this.#value = freeze(value);
505
+ }
506
+ [Symbol.dispose]() {
507
+ super[Symbol.dispose]();
508
+ this.#value = "(disposed)";
509
+ }
510
+ get() {
511
+ trackedReads?.add(this);
512
+ return this.#value;
513
+ }
514
+ set(newValue) {
515
+ batch(() => {
516
+ if (typeof newValue === "function") {
517
+ newValue = newValue(this.#value);
518
+ }
519
+ if (!this.equals(this.#value, newValue)) {
520
+ this.#value = freeze(newValue);
521
+ this.markSinksDirty();
522
+ enqueueTrigger(this);
523
+ }
524
+ });
525
+ }
526
+ };
527
+ var PatchableSignal = class extends Signal {
528
+ constructor(data) {
529
+ super(freeze(compactObject(data)));
530
+ }
531
+ set() {
532
+ throw new Error("Don't call .set() directly, use .patch()");
533
+ }
534
+ /**
535
+ * Patches the current object.
536
+ */
537
+ patch(patch) {
538
+ super.set((old) => merge(old, patch));
539
+ }
540
+ };
541
+ var INITIAL = Symbol();
542
+ var DerivedSignal = class _DerivedSignal extends AbstractSignal {
543
+ #prevValue;
544
+ #dirty;
545
+ // When true, the value in #value may not be up-to-date and needs re-checking
546
+ #sources;
547
+ #deps;
548
+ #transform;
549
+ // prettier-ignore
550
+ static from(...args) {
551
+ const last = args.pop();
552
+ if (typeof last !== "function")
553
+ raise("Invalid .from() call, last argument expected to be a function");
554
+ if (typeof args[args.length - 1] === "function") {
555
+ const equals = last;
556
+ const transform = args.pop();
557
+ return new _DerivedSignal(args, transform, equals);
558
+ } else {
559
+ const transform = last;
560
+ return new _DerivedSignal(args, transform);
561
+ }
562
+ }
563
+ constructor(deps, transform, equals) {
564
+ super(equals);
565
+ this.#dirty = true;
566
+ this.#prevValue = INITIAL;
567
+ this.#deps = deps;
568
+ this.#sources = /* @__PURE__ */ new Set();
569
+ this.#transform = transform;
570
+ }
571
+ [Symbol.dispose]() {
572
+ for (const src of this.#sources) {
573
+ src.removeSink(this);
574
+ }
575
+ this.#prevValue = "(disposed)";
576
+ this.#sources = "(disposed)";
577
+ this.#deps = "(disposed)";
578
+ this.#transform = "(disposed)";
579
+ }
580
+ get isDirty() {
581
+ return this.#dirty;
582
+ }
583
+ #recompute() {
584
+ const oldTrackedReads = trackedReads;
585
+ let derived;
586
+ trackedReads = /* @__PURE__ */ new Set();
587
+ try {
588
+ derived = this.#transform(...this.#deps.map((p) => p.get()));
589
+ } finally {
590
+ const oldSources = this.#sources;
591
+ this.#sources = /* @__PURE__ */ new Set();
592
+ for (const sig of trackedReads) {
593
+ this.#sources.add(sig);
594
+ oldSources.delete(sig);
595
+ }
596
+ for (const oldSource of oldSources) {
597
+ oldSource.removeSink(this);
598
+ }
599
+ for (const newSource of this.#sources) {
600
+ newSource.addSink(this);
601
+ }
602
+ trackedReads = oldTrackedReads;
603
+ }
604
+ this.#dirty = false;
605
+ if (!this.equals(this.#prevValue, derived)) {
606
+ this.#prevValue = derived;
607
+ return true;
608
+ }
609
+ return false;
610
+ }
611
+ markDirty() {
612
+ if (!this.#dirty) {
613
+ this.#dirty = true;
614
+ this.markSinksDirty();
615
+ }
616
+ }
617
+ get() {
618
+ if (this.#dirty) {
619
+ this.#recompute();
620
+ }
621
+ trackedReads?.add(this);
622
+ return this.#prevValue;
623
+ }
624
+ /**
625
+ * Called by the Signal system if one or more of the dependent signals have
626
+ * changed. In the case of a DerivedSignal, we'll only want to re-evaluate
627
+ * the actual value if it's being watched, or any of their sinks are being
628
+ * watched actively.
629
+ */
630
+ [kTrigger]() {
631
+ if (!this.hasWatchers) {
632
+ return;
633
+ }
634
+ const updated = this.#recompute();
635
+ if (updated) {
636
+ super[kTrigger]();
637
+ }
638
+ }
639
+ };
640
+ var MutableSignal = class extends AbstractSignal {
641
+ #state;
642
+ constructor(initialState) {
643
+ super();
644
+ this.#state = initialState;
645
+ }
646
+ [Symbol.dispose]() {
647
+ super[Symbol.dispose]();
648
+ this.#state = "(disposed)";
649
+ }
650
+ get() {
651
+ trackedReads?.add(this);
652
+ return this.#state;
653
+ }
654
+ /**
655
+ * Invokes a callback function that is allowed to mutate the given state
656
+ * value. Do not change the value outside of the callback.
657
+ *
658
+ * If the callback explicitly returns `false`, it's assumed that the state
659
+ * was not changed.
660
+ */
661
+ mutate(callback) {
662
+ batch(() => {
663
+ const result = callback ? callback(this.#state) : true;
664
+ if (result !== null && typeof result === "object" && "then" in result) {
665
+ raise("MutableSignal.mutate() does not support async callbacks");
666
+ }
667
+ if (result !== false) {
668
+ this.markSinksDirty();
669
+ enqueueTrigger(this);
670
+ }
671
+ });
672
+ }
673
+ };
674
+
388
675
  // 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);
676
+ var EXPLICIT_UNDEFINED_PLACEHOLDER = "_explicit_undefined";
677
+ function replacer(_key, value) {
678
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? Object.keys(value).sort().reduce((sorted, key) => {
679
+ sorted[key] = value[key];
680
+ return sorted;
681
+ }, {}) : value === void 0 ? EXPLICIT_UNDEFINED_PLACEHOLDER : value;
682
+ }
683
+ function reviver(key, value) {
684
+ if (!key && value === EXPLICIT_UNDEFINED_PLACEHOLDER) {
685
+ return void 0;
686
+ }
687
+ if (value && typeof value === "object") {
688
+ for (const k in value) {
689
+ if (value[k] === EXPLICIT_UNDEFINED_PLACEHOLDER) {
690
+ Object.defineProperty(value, k, { value: void 0 });
691
+ }
692
+ }
693
+ }
694
+ return value;
695
+ }
696
+ function stringify(value) {
697
+ return JSON.stringify(value, replacer);
698
+ }
699
+ function unstringify(value) {
700
+ return JSON.parse(value, reviver);
401
701
  }
402
702
 
403
703
  // src/lib/batch.ts
@@ -492,57 +792,58 @@ var Batch = class {
492
792
  }
493
793
  };
494
794
  function createBatchStore(batch2) {
495
- const cache = /* @__PURE__ */ new Map();
496
- const eventSource2 = makeEventSource();
795
+ const signal = new MutableSignal(/* @__PURE__ */ new Map());
497
796
  function getCacheKey(args) {
498
797
  return stringify(args);
499
798
  }
500
- function setStateAndNotify(cacheKey, state) {
501
- cache.set(cacheKey, state);
502
- eventSource2.notify();
799
+ function update(cacheKey, state) {
800
+ signal.mutate((cache) => {
801
+ cache.set(cacheKey, state);
802
+ });
503
803
  }
504
804
  function invalidate(inputs) {
505
- if (Array.isArray(inputs)) {
506
- for (const input of inputs) {
507
- cache.delete(getCacheKey(input));
805
+ signal.mutate((cache) => {
806
+ if (Array.isArray(inputs)) {
807
+ for (const input of inputs) {
808
+ cache.delete(getCacheKey(input));
809
+ }
810
+ } else {
811
+ cache.clear();
508
812
  }
509
- } else {
510
- cache.clear();
511
- }
512
- eventSource2.notify();
813
+ });
513
814
  }
514
- async function get(input) {
815
+ async function enqueue(input) {
515
816
  const cacheKey = getCacheKey(input);
817
+ const cache = signal.get();
516
818
  if (cache.has(cacheKey)) {
517
819
  return;
518
820
  }
519
821
  try {
520
- setStateAndNotify(cacheKey, { isLoading: true });
822
+ update(cacheKey, { isLoading: true });
521
823
  const result = await batch2.get(input);
522
- setStateAndNotify(cacheKey, { isLoading: false, data: result });
824
+ update(cacheKey, { isLoading: false, data: result });
523
825
  } catch (error3) {
524
- setStateAndNotify(cacheKey, {
826
+ update(cacheKey, {
525
827
  isLoading: false,
526
828
  error: error3
527
829
  });
528
830
  }
529
831
  }
530
- function getState(input) {
832
+ function getItemState(input) {
531
833
  const cacheKey = getCacheKey(input);
834
+ const cache = signal.get();
532
835
  return cache.get(cacheKey);
533
836
  }
534
837
  function _cacheKeys() {
838
+ const cache = signal.get();
535
839
  return [...cache.keys()];
536
840
  }
537
- function getBatch() {
538
- return batch2;
539
- }
540
841
  return {
541
- ...eventSource2.observable,
542
- get,
543
- getState,
842
+ subscribe: signal.subscribe,
843
+ enqueue,
844
+ getItemState,
544
845
  invalidate,
545
- getBatch,
846
+ batch: batch2,
546
847
  _cacheKeys
547
848
  };
548
849
  }
@@ -583,6 +884,36 @@ function createInboxNotificationId() {
583
884
  return createOptimisticId(INBOX_NOTIFICATION_ID_PREFIX);
584
885
  }
585
886
 
887
+ // src/lib/DefaultMap.ts
888
+ var DefaultMap = class extends Map {
889
+ #defaultFn;
890
+ /**
891
+ * If the default function is not provided to the constructor, it has to be
892
+ * provided in each .getOrCreate() call individually.
893
+ */
894
+ constructor(defaultFn, entries2) {
895
+ super(entries2);
896
+ this.#defaultFn = defaultFn;
897
+ }
898
+ /**
899
+ * Gets the value at the given key, or creates it.
900
+ *
901
+ * Difference from normal Map: if the key does not exist, it will be created
902
+ * on the fly using the factory function, and that value will get returned
903
+ * instead of `undefined`.
904
+ */
905
+ getOrCreate(key, defaultFn) {
906
+ if (super.has(key)) {
907
+ return super.get(key);
908
+ } else {
909
+ const fn = defaultFn ?? this.#defaultFn ?? raise("DefaultMap used without a factory function");
910
+ const value = fn(key);
911
+ this.set(key, value);
912
+ return value;
913
+ }
914
+ }
915
+ };
916
+
586
917
  // src/lib/objectToQuery.ts
587
918
  var identifierRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
588
919
  function objectToQuery(obj) {
@@ -1083,40 +1414,31 @@ function createApiClient({
1083
1414
  }
1084
1415
  }
1085
1416
  }
1086
- const getAttachmentUrlsBatchStoreByRoom = /* @__PURE__ */ new Map();
1417
+ const attachmentUrlsBatchStoresByRoom = new DefaultMap((roomId) => {
1418
+ const batch2 = new Batch(
1419
+ async (batchedAttachmentIds) => {
1420
+ const attachmentIds = batchedAttachmentIds.flat();
1421
+ const { urls } = await httpClient.post(
1422
+ url`/v2/c/rooms/${roomId}/attachments/presigned-urls`,
1423
+ await authManager.getAuthValue({
1424
+ requestedScope: "comments:read",
1425
+ roomId
1426
+ }),
1427
+ { attachmentIds }
1428
+ );
1429
+ return urls.map(
1430
+ (url2) => url2 ?? new Error("There was an error while getting this attachment's URL")
1431
+ );
1432
+ },
1433
+ { delay: 50 }
1434
+ );
1435
+ return createBatchStore(batch2);
1436
+ });
1087
1437
  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) => 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;
1438
+ return attachmentUrlsBatchStoresByRoom.getOrCreate(roomId);
1117
1439
  }
1118
1440
  function getAttachmentUrl(options) {
1119
- const batch2 = getOrCreateAttachmentUrlsStore(options.roomId).getBatch();
1441
+ const batch2 = getOrCreateAttachmentUrlsStore(options.roomId).batch;
1120
1442
  return batch2.get(options.attachmentId);
1121
1443
  }
1122
1444
  async function getNotificationSettings(options) {
@@ -1142,33 +1464,25 @@ function createApiClient({
1142
1464
  options.settings
1143
1465
  );
1144
1466
  }
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
- }
1467
+ const markAsReadBatchesByRoom = new DefaultMap(
1468
+ (roomId) => new Batch(
1469
+ async (batchedInboxNotificationIds) => {
1470
+ const inboxNotificationIds = batchedInboxNotificationIds.flat();
1471
+ await httpClient.post(
1472
+ url`/v2/c/rooms/${roomId}/inbox-notifications/read`,
1473
+ await authManager.getAuthValue({
1474
+ requestedScope: "comments:read",
1475
+ roomId
1476
+ }),
1477
+ { inboxNotificationIds }
1478
+ );
1479
+ return inboxNotificationIds;
1480
+ },
1481
+ { delay: 50 }
1482
+ )
1483
+ );
1170
1484
  async function markRoomInboxNotificationAsRead(options) {
1171
- const batch2 = getOrCreateMarkInboxNotificationsAsReadBatch(options.roomId);
1485
+ const batch2 = markAsReadBatchesByRoom.getOrCreate(options.roomId);
1172
1486
  return batch2.get(options.inboxNotificationId);
1173
1487
  }
1174
1488
  async function createTextMention(options) {
@@ -3214,267 +3528,6 @@ function unlinkDevTools(roomId) {
3214
3528
  });
3215
3529
  }
3216
3530
 
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
- equals;
3266
- #eventSource;
3267
- /** @internal */
3268
- [kSinks];
3269
- constructor(equals) {
3270
- this.equals = 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;
3406
- }
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;
3415
- }
3416
- markDirty() {
3417
- if (!this.#dirty) {
3418
- this.#dirty = true;
3419
- this.markSinksDirty();
3420
- }
3421
- }
3422
- get() {
3423
- if (this.#dirty) {
3424
- this.#recompute();
3425
- }
3426
- return this.#prevValue;
3427
- }
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
- }
3442
- }
3443
- };
3444
- var MutableSignal = class extends AbstractSignal {
3445
- #state;
3446
- constructor(initialState) {
3447
- super();
3448
- this.#state = initialState;
3449
- }
3450
- [Symbol.dispose]() {
3451
- super[Symbol.dispose]();
3452
- this.#state = "(disposed)";
3453
- }
3454
- get() {
3455
- return this.#state;
3456
- }
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);
3473
- }
3474
- });
3475
- }
3476
- };
3477
-
3478
3531
  // src/lib/position.ts
3479
3532
  var MIN_CODE = 32;
3480
3533
  var MAX_CODE = 126;
@@ -8842,6 +8895,7 @@ export {
8842
8895
  ClientMsgCode,
8843
8896
  CommentsApiError,
8844
8897
  CrdtType,
8898
+ DefaultMap,
8845
8899
  DerivedSignal,
8846
8900
  HttpError,
8847
8901
  LiveList,
@@ -8917,6 +8971,7 @@ export {
8917
8971
  toAbsoluteUrl,
8918
8972
  toPlainLson,
8919
8973
  tryParseJson,
8974
+ unstringify,
8920
8975
  url,
8921
8976
  urljoin,
8922
8977
  wait,