@liveblocks/core 2.14.0 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.mts +103 -38
- package/dist/index.d.ts +103 -38
- package/dist/index.js +1076 -943
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1029 -896
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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.
|
|
9
|
+
var PKG_VERSION = "2.15.0";
|
|
10
10
|
var PKG_FORMAT = "esm";
|
|
11
11
|
|
|
12
12
|
// src/dupe-detection.ts
|
|
@@ -304,19 +304,6 @@ function Promise_withResolvers() {
|
|
|
304
304
|
// src/lib/EventSource.ts
|
|
305
305
|
function makeEventSource() {
|
|
306
306
|
const _observers = /* @__PURE__ */ new Set();
|
|
307
|
-
let _buffer = null;
|
|
308
|
-
function pause() {
|
|
309
|
-
_buffer = [];
|
|
310
|
-
}
|
|
311
|
-
function unpause() {
|
|
312
|
-
if (_buffer === null) {
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
for (const event of _buffer) {
|
|
316
|
-
notify(event);
|
|
317
|
-
}
|
|
318
|
-
_buffer = null;
|
|
319
|
-
}
|
|
320
307
|
function subscribe(callback) {
|
|
321
308
|
_observers.add(callback);
|
|
322
309
|
return () => _observers.delete(callback);
|
|
@@ -338,32 +325,22 @@ function makeEventSource() {
|
|
|
338
325
|
});
|
|
339
326
|
}).finally(() => unsub?.());
|
|
340
327
|
}
|
|
341
|
-
function notifyOrBuffer(event) {
|
|
342
|
-
if (_buffer !== null) {
|
|
343
|
-
_buffer.push(event);
|
|
344
|
-
} else {
|
|
345
|
-
notify(event);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
328
|
function notify(event) {
|
|
349
329
|
_observers.forEach((callback) => callback(event));
|
|
350
330
|
}
|
|
351
|
-
function _forceClear() {
|
|
352
|
-
_observers.clear();
|
|
353
|
-
}
|
|
354
331
|
function count() {
|
|
355
332
|
return _observers.size;
|
|
356
333
|
}
|
|
357
334
|
return {
|
|
358
335
|
// Private/internal control over event emission
|
|
359
|
-
notify
|
|
336
|
+
notify,
|
|
360
337
|
subscribe,
|
|
361
338
|
subscribeOnce,
|
|
362
|
-
_forceClear,
|
|
363
339
|
count,
|
|
364
340
|
waitUntil,
|
|
365
|
-
|
|
366
|
-
|
|
341
|
+
[Symbol.dispose]: () => {
|
|
342
|
+
_observers.clear();
|
|
343
|
+
},
|
|
367
344
|
// Publicly exposable subscription API
|
|
368
345
|
observable: {
|
|
369
346
|
subscribe,
|
|
@@ -372,6 +349,41 @@ function makeEventSource() {
|
|
|
372
349
|
}
|
|
373
350
|
};
|
|
374
351
|
}
|
|
352
|
+
function makeBufferableEventSource() {
|
|
353
|
+
const eventSource2 = makeEventSource();
|
|
354
|
+
let _buffer = null;
|
|
355
|
+
function pause() {
|
|
356
|
+
_buffer = [];
|
|
357
|
+
}
|
|
358
|
+
function unpause() {
|
|
359
|
+
if (_buffer === null) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
for (const event of _buffer) {
|
|
363
|
+
eventSource2.notify(event);
|
|
364
|
+
}
|
|
365
|
+
_buffer = null;
|
|
366
|
+
}
|
|
367
|
+
function notifyOrBuffer(event) {
|
|
368
|
+
if (_buffer !== null) {
|
|
369
|
+
_buffer.push(event);
|
|
370
|
+
} else {
|
|
371
|
+
eventSource2.notify(event);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return {
|
|
375
|
+
...eventSource2,
|
|
376
|
+
notify: notifyOrBuffer,
|
|
377
|
+
pause,
|
|
378
|
+
unpause,
|
|
379
|
+
[Symbol.dispose]: () => {
|
|
380
|
+
eventSource2[Symbol.dispose]();
|
|
381
|
+
if (_buffer !== null) {
|
|
382
|
+
_buffer.length = 0;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
}
|
|
375
387
|
|
|
376
388
|
// src/lib/stringify.ts
|
|
377
389
|
function stringify(object, ...args) {
|
|
@@ -391,6 +403,10 @@ function stringify(object, ...args) {
|
|
|
391
403
|
// src/lib/batch.ts
|
|
392
404
|
var DEFAULT_SIZE = 50;
|
|
393
405
|
var BatchCall = class {
|
|
406
|
+
input;
|
|
407
|
+
resolve;
|
|
408
|
+
reject;
|
|
409
|
+
promise;
|
|
394
410
|
constructor(input) {
|
|
395
411
|
this.input = input;
|
|
396
412
|
const { promise, resolve, reject } = Promise_withResolvers();
|
|
@@ -400,35 +416,39 @@ var BatchCall = class {
|
|
|
400
416
|
}
|
|
401
417
|
};
|
|
402
418
|
var Batch = class {
|
|
419
|
+
#queue = [];
|
|
420
|
+
#callback;
|
|
421
|
+
#size;
|
|
422
|
+
#delay;
|
|
423
|
+
#delayTimeoutId;
|
|
424
|
+
error = false;
|
|
403
425
|
constructor(callback, options) {
|
|
404
|
-
this
|
|
405
|
-
this
|
|
406
|
-
this
|
|
407
|
-
this.size = options.size ?? DEFAULT_SIZE;
|
|
408
|
-
this.delay = options.delay;
|
|
426
|
+
this.#callback = callback;
|
|
427
|
+
this.#size = options.size ?? DEFAULT_SIZE;
|
|
428
|
+
this.#delay = options.delay;
|
|
409
429
|
}
|
|
410
|
-
clearDelayTimeout() {
|
|
411
|
-
if (this
|
|
412
|
-
clearTimeout(this
|
|
413
|
-
this
|
|
430
|
+
#clearDelayTimeout() {
|
|
431
|
+
if (this.#delayTimeoutId !== void 0) {
|
|
432
|
+
clearTimeout(this.#delayTimeoutId);
|
|
433
|
+
this.#delayTimeoutId = void 0;
|
|
414
434
|
}
|
|
415
435
|
}
|
|
416
|
-
schedule() {
|
|
417
|
-
if (this
|
|
418
|
-
void this
|
|
419
|
-
} else if (this
|
|
420
|
-
this
|
|
421
|
-
this
|
|
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);
|
|
422
442
|
}
|
|
423
443
|
}
|
|
424
|
-
async flush() {
|
|
425
|
-
if (this
|
|
444
|
+
async #flush() {
|
|
445
|
+
if (this.#queue.length === 0) {
|
|
426
446
|
return;
|
|
427
447
|
}
|
|
428
|
-
const calls = this
|
|
448
|
+
const calls = this.#queue.splice(0);
|
|
429
449
|
const inputs = calls.map((call) => call.input);
|
|
430
450
|
try {
|
|
431
|
-
const results = await this
|
|
451
|
+
const results = await this.#callback(inputs);
|
|
432
452
|
this.error = false;
|
|
433
453
|
calls.forEach((call, index) => {
|
|
434
454
|
const result = results?.[index];
|
|
@@ -454,24 +474,24 @@ var Batch = class {
|
|
|
454
474
|
}
|
|
455
475
|
}
|
|
456
476
|
get(input) {
|
|
457
|
-
const existingCall = this
|
|
477
|
+
const existingCall = this.#queue.find(
|
|
458
478
|
(call2) => stringify(call2.input) === stringify(input)
|
|
459
479
|
);
|
|
460
480
|
if (existingCall) {
|
|
461
481
|
return existingCall.promise;
|
|
462
482
|
}
|
|
463
483
|
const call = new BatchCall(input);
|
|
464
|
-
this
|
|
465
|
-
this
|
|
484
|
+
this.#queue.push(call);
|
|
485
|
+
this.#schedule();
|
|
466
486
|
return call.promise;
|
|
467
487
|
}
|
|
468
488
|
clear() {
|
|
469
|
-
this
|
|
489
|
+
this.#queue = [];
|
|
470
490
|
this.error = false;
|
|
471
|
-
this
|
|
491
|
+
this.#clearDelayTimeout();
|
|
472
492
|
}
|
|
473
493
|
};
|
|
474
|
-
function createBatchStore(
|
|
494
|
+
function createBatchStore(batch2) {
|
|
475
495
|
const cache = /* @__PURE__ */ new Map();
|
|
476
496
|
const eventSource2 = makeEventSource();
|
|
477
497
|
function getCacheKey(args) {
|
|
@@ -498,7 +518,7 @@ function createBatchStore(batch) {
|
|
|
498
518
|
}
|
|
499
519
|
try {
|
|
500
520
|
setStateAndNotify(cacheKey, { isLoading: true });
|
|
501
|
-
const result = await
|
|
521
|
+
const result = await batch2.get(input);
|
|
502
522
|
setStateAndNotify(cacheKey, { isLoading: false, data: result });
|
|
503
523
|
} catch (error3) {
|
|
504
524
|
setStateAndNotify(cacheKey, {
|
|
@@ -515,7 +535,7 @@ function createBatchStore(batch) {
|
|
|
515
535
|
return [...cache.keys()];
|
|
516
536
|
}
|
|
517
537
|
function getBatch() {
|
|
518
|
-
return
|
|
538
|
+
return batch2;
|
|
519
539
|
}
|
|
520
540
|
return {
|
|
521
541
|
...eventSource2.observable,
|
|
@@ -1067,7 +1087,7 @@ function createApiClient({
|
|
|
1067
1087
|
function getOrCreateAttachmentUrlsStore(roomId) {
|
|
1068
1088
|
let store = getAttachmentUrlsBatchStoreByRoom.get(roomId);
|
|
1069
1089
|
if (store === void 0) {
|
|
1070
|
-
const
|
|
1090
|
+
const batch2 = new Batch(
|
|
1071
1091
|
async (batchedAttachmentIds) => {
|
|
1072
1092
|
const attachmentIds = batchedAttachmentIds.flat();
|
|
1073
1093
|
const { urls } = await httpClient.post(
|
|
@@ -1090,14 +1110,14 @@ function createApiClient({
|
|
|
1090
1110
|
delay: 50
|
|
1091
1111
|
}
|
|
1092
1112
|
);
|
|
1093
|
-
store = createBatchStore(
|
|
1113
|
+
store = createBatchStore(batch2);
|
|
1094
1114
|
getAttachmentUrlsBatchStoreByRoom.set(roomId, store);
|
|
1095
1115
|
}
|
|
1096
1116
|
return store;
|
|
1097
1117
|
}
|
|
1098
1118
|
function getAttachmentUrl(options) {
|
|
1099
|
-
const
|
|
1100
|
-
return
|
|
1119
|
+
const batch2 = getOrCreateAttachmentUrlsStore(options.roomId).getBatch();
|
|
1120
|
+
return batch2.get(options.attachmentId);
|
|
1101
1121
|
}
|
|
1102
1122
|
async function getNotificationSettings(options) {
|
|
1103
1123
|
return httpClient.get(
|
|
@@ -1124,9 +1144,9 @@ function createApiClient({
|
|
|
1124
1144
|
}
|
|
1125
1145
|
const markInboxNotificationsAsReadBatchByRoom = /* @__PURE__ */ new Map();
|
|
1126
1146
|
function getOrCreateMarkInboxNotificationsAsReadBatch(roomId) {
|
|
1127
|
-
let
|
|
1128
|
-
if (
|
|
1129
|
-
|
|
1147
|
+
let batch2 = markInboxNotificationsAsReadBatchByRoom.get(roomId);
|
|
1148
|
+
if (batch2 === void 0) {
|
|
1149
|
+
batch2 = new Batch(
|
|
1130
1150
|
async (batchedInboxNotificationIds) => {
|
|
1131
1151
|
const inboxNotificationIds = batchedInboxNotificationIds.flat();
|
|
1132
1152
|
await httpClient.post(
|
|
@@ -1143,13 +1163,13 @@ function createApiClient({
|
|
|
1143
1163
|
delay: 50
|
|
1144
1164
|
}
|
|
1145
1165
|
);
|
|
1146
|
-
markInboxNotificationsAsReadBatchByRoom.set(roomId,
|
|
1166
|
+
markInboxNotificationsAsReadBatchByRoom.set(roomId, batch2);
|
|
1147
1167
|
}
|
|
1148
|
-
return
|
|
1168
|
+
return batch2;
|
|
1149
1169
|
}
|
|
1150
1170
|
async function markRoomInboxNotificationAsRead(options) {
|
|
1151
|
-
const
|
|
1152
|
-
return
|
|
1171
|
+
const batch2 = getOrCreateMarkInboxNotificationsAsReadBatch(options.roomId);
|
|
1172
|
+
return batch2.get(options.inboxNotificationId);
|
|
1153
1173
|
}
|
|
1154
1174
|
async function createTextMention(options) {
|
|
1155
1175
|
await httpClient.rawPost(
|
|
@@ -1455,9 +1475,11 @@ function getBearerTokenFromAuthValue(authValue) {
|
|
|
1455
1475
|
}
|
|
1456
1476
|
}
|
|
1457
1477
|
var HttpClient = class {
|
|
1478
|
+
#baseUrl;
|
|
1479
|
+
#fetchPolyfill;
|
|
1458
1480
|
constructor(baseUrl, fetchPolyfill) {
|
|
1459
|
-
this
|
|
1460
|
-
this
|
|
1481
|
+
this.#baseUrl = baseUrl;
|
|
1482
|
+
this.#fetchPolyfill = fetchPolyfill;
|
|
1461
1483
|
}
|
|
1462
1484
|
// ------------------------------------------------------------------
|
|
1463
1485
|
// Public methods
|
|
@@ -1475,12 +1497,12 @@ var HttpClient = class {
|
|
|
1475
1497
|
* 5. ...but silently return `{}` if that parsing fails
|
|
1476
1498
|
* 6. Throw HttpError if response is an error
|
|
1477
1499
|
*/
|
|
1478
|
-
async rawFetch(endpoint, authValue, options, params) {
|
|
1500
|
+
async #rawFetch(endpoint, authValue, options, params) {
|
|
1479
1501
|
if (!endpoint.startsWith("/v2/c/")) {
|
|
1480
1502
|
raise("This client can only be used to make /v2/c/* requests");
|
|
1481
1503
|
}
|
|
1482
|
-
const url2 = urljoin(this
|
|
1483
|
-
return await this
|
|
1504
|
+
const url2 = urljoin(this.#baseUrl, endpoint, params);
|
|
1505
|
+
return await this.#fetchPolyfill(url2, {
|
|
1484
1506
|
...options,
|
|
1485
1507
|
headers: {
|
|
1486
1508
|
// These headers are default, but can be overriden by custom headers
|
|
@@ -1507,8 +1529,8 @@ var HttpClient = class {
|
|
|
1507
1529
|
* 5. ...but silently return `{}` if that parsing fails (🤔)
|
|
1508
1530
|
* 6. Throw HttpError if response is an error
|
|
1509
1531
|
*/
|
|
1510
|
-
async fetch(endpoint, authValue, options, params) {
|
|
1511
|
-
const response = await this
|
|
1532
|
+
async #fetch(endpoint, authValue, options, params) {
|
|
1533
|
+
const response = await this.#rawFetch(endpoint, authValue, options, params);
|
|
1512
1534
|
if (!response.ok) {
|
|
1513
1535
|
let error3;
|
|
1514
1536
|
try {
|
|
@@ -1533,7 +1555,7 @@ var HttpClient = class {
|
|
|
1533
1555
|
* @deprecated Ideally, use .get() instead.
|
|
1534
1556
|
*/
|
|
1535
1557
|
async rawGet(endpoint, authValue, params, options) {
|
|
1536
|
-
return await this
|
|
1558
|
+
return await this.#rawFetch(endpoint, authValue, options, params);
|
|
1537
1559
|
}
|
|
1538
1560
|
/**
|
|
1539
1561
|
* Makes a POST request and returns the raw response.
|
|
@@ -1541,7 +1563,7 @@ var HttpClient = class {
|
|
|
1541
1563
|
* @deprecated Ideally, use .post() instead.
|
|
1542
1564
|
*/
|
|
1543
1565
|
async rawPost(endpoint, authValue, body) {
|
|
1544
|
-
return await this
|
|
1566
|
+
return await this.#rawFetch(endpoint, authValue, {
|
|
1545
1567
|
method: "POST",
|
|
1546
1568
|
body: JSON.stringify(body)
|
|
1547
1569
|
});
|
|
@@ -1552,21 +1574,21 @@ var HttpClient = class {
|
|
|
1552
1574
|
* @deprecated Ideally, use .delete() instead.
|
|
1553
1575
|
*/
|
|
1554
1576
|
async rawDelete(endpoint, authValue) {
|
|
1555
|
-
return await this
|
|
1577
|
+
return await this.#rawFetch(endpoint, authValue, { method: "DELETE" });
|
|
1556
1578
|
}
|
|
1557
1579
|
/**
|
|
1558
1580
|
* Makes a GET request, and return the JSON response.
|
|
1559
1581
|
* Will throw if the reponse is a non-2xx.
|
|
1560
1582
|
*/
|
|
1561
1583
|
async get(endpoint, authValue, params, options) {
|
|
1562
|
-
return await this
|
|
1584
|
+
return await this.#fetch(endpoint, authValue, options, params);
|
|
1563
1585
|
}
|
|
1564
1586
|
/**
|
|
1565
1587
|
* Makes a POST request, and return the JSON response.
|
|
1566
1588
|
* Will throw if the reponse is a non-2xx.
|
|
1567
1589
|
*/
|
|
1568
1590
|
async post(endpoint, authValue, body, options, params) {
|
|
1569
|
-
return await this
|
|
1591
|
+
return await this.#fetch(
|
|
1570
1592
|
endpoint,
|
|
1571
1593
|
authValue,
|
|
1572
1594
|
{
|
|
@@ -1582,14 +1604,14 @@ var HttpClient = class {
|
|
|
1582
1604
|
* Will throw if the reponse is a non-2xx.
|
|
1583
1605
|
*/
|
|
1584
1606
|
async delete(endpoint, authValue) {
|
|
1585
|
-
return await this
|
|
1607
|
+
return await this.#fetch(endpoint, authValue, { method: "DELETE" });
|
|
1586
1608
|
}
|
|
1587
1609
|
/**
|
|
1588
1610
|
* Makes a PUT request for a Blob body, and return the JSON response.
|
|
1589
1611
|
* Will throw if the reponse is a non-2xx.
|
|
1590
1612
|
*/
|
|
1591
1613
|
async putBlob(endpoint, authValue, blob, params, options) {
|
|
1592
|
-
return await this
|
|
1614
|
+
return await this.#fetch(
|
|
1593
1615
|
endpoint,
|
|
1594
1616
|
authValue,
|
|
1595
1617
|
{
|
|
@@ -1660,11 +1682,12 @@ function patterns(targetState, levels) {
|
|
|
1660
1682
|
return result;
|
|
1661
1683
|
}
|
|
1662
1684
|
var SafeContext = class {
|
|
1685
|
+
#curr;
|
|
1663
1686
|
constructor(initialContext) {
|
|
1664
|
-
this
|
|
1687
|
+
this.#curr = initialContext;
|
|
1665
1688
|
}
|
|
1666
1689
|
get current() {
|
|
1667
|
-
return this
|
|
1690
|
+
return this.#curr;
|
|
1668
1691
|
}
|
|
1669
1692
|
/**
|
|
1670
1693
|
* Call a callback function that allows patching of the context, by
|
|
@@ -1675,10 +1698,10 @@ var SafeContext = class {
|
|
|
1675
1698
|
const self = this;
|
|
1676
1699
|
let allowed = true;
|
|
1677
1700
|
const patchableContext = {
|
|
1678
|
-
...this
|
|
1701
|
+
...this.#curr,
|
|
1679
1702
|
patch(patch) {
|
|
1680
1703
|
if (allowed) {
|
|
1681
|
-
self
|
|
1704
|
+
self.#curr = Object.assign({}, self.#curr, patch);
|
|
1682
1705
|
for (const pair of Object.entries(patch)) {
|
|
1683
1706
|
const [key, value] = pair;
|
|
1684
1707
|
if (key !== "patch") {
|
|
@@ -1697,12 +1720,42 @@ var SafeContext = class {
|
|
|
1697
1720
|
};
|
|
1698
1721
|
var nextId = 1;
|
|
1699
1722
|
var FSM = class {
|
|
1723
|
+
id;
|
|
1724
|
+
// Indicates whether this state machine is still being configured, has
|
|
1725
|
+
// started, or has terminated
|
|
1726
|
+
#runningState;
|
|
1727
|
+
#currentContext;
|
|
1728
|
+
#states;
|
|
1729
|
+
#currentStateOrNull;
|
|
1730
|
+
#allowedTransitions;
|
|
1731
|
+
#eventHub;
|
|
1732
|
+
events;
|
|
1733
|
+
//
|
|
1734
|
+
// The cleanup stack is a stack of (optional) callback functions that will
|
|
1735
|
+
// be run when exiting the current state. If a state (or state group) does
|
|
1736
|
+
// not have an exit handler, then the entry for that level may be
|
|
1737
|
+
// `undefined`, but there will be an explicit entry in the stack for it.
|
|
1738
|
+
//
|
|
1739
|
+
// This will always be true:
|
|
1740
|
+
//
|
|
1741
|
+
// cleanupStack.length == currentState.split('.').length + 1
|
|
1742
|
+
//
|
|
1743
|
+
// Each stack level represents a different state "group".
|
|
1744
|
+
//
|
|
1745
|
+
// For example, if you are in a state named `foo.bar.qux`, then the stack
|
|
1746
|
+
// will contain the exit handler for `foo.bar.qux` (at the top), then
|
|
1747
|
+
// `foo.bar.*`, then `foo.*`, and finally, `*`.
|
|
1748
|
+
//
|
|
1749
|
+
#cleanupStack;
|
|
1750
|
+
#enterFns;
|
|
1751
|
+
// Used to provide better error messages
|
|
1752
|
+
#knownEventTypes;
|
|
1700
1753
|
/**
|
|
1701
1754
|
* Returns the initial state, which is defined by the first call made to
|
|
1702
1755
|
* .addState().
|
|
1703
1756
|
*/
|
|
1704
|
-
get initialState() {
|
|
1705
|
-
const result = this
|
|
1757
|
+
get #initialState() {
|
|
1758
|
+
const result = this.#states.values()[Symbol.iterator]().next();
|
|
1706
1759
|
if (result.done) {
|
|
1707
1760
|
throw new Error("No states defined yet");
|
|
1708
1761
|
} else {
|
|
@@ -1710,25 +1763,25 @@ var FSM = class {
|
|
|
1710
1763
|
}
|
|
1711
1764
|
}
|
|
1712
1765
|
get currentState() {
|
|
1713
|
-
if (this
|
|
1714
|
-
if (this
|
|
1766
|
+
if (this.#currentStateOrNull === null) {
|
|
1767
|
+
if (this.#runningState === 0 /* NOT_STARTED_YET */) {
|
|
1715
1768
|
throw new Error("Not started yet");
|
|
1716
1769
|
} else {
|
|
1717
1770
|
throw new Error("Already stopped");
|
|
1718
1771
|
}
|
|
1719
1772
|
}
|
|
1720
|
-
return this
|
|
1773
|
+
return this.#currentStateOrNull;
|
|
1721
1774
|
}
|
|
1722
1775
|
/**
|
|
1723
1776
|
* Starts the machine by entering the initial state.
|
|
1724
1777
|
*/
|
|
1725
1778
|
start() {
|
|
1726
|
-
if (this
|
|
1779
|
+
if (this.#runningState !== 0 /* NOT_STARTED_YET */) {
|
|
1727
1780
|
throw new Error("State machine has already started");
|
|
1728
1781
|
}
|
|
1729
|
-
this
|
|
1730
|
-
this
|
|
1731
|
-
this
|
|
1782
|
+
this.#runningState = 1 /* STARTED */;
|
|
1783
|
+
this.#currentStateOrNull = this.#initialState;
|
|
1784
|
+
this.#enter(null);
|
|
1732
1785
|
return this;
|
|
1733
1786
|
}
|
|
1734
1787
|
/**
|
|
@@ -1736,24 +1789,24 @@ var FSM = class {
|
|
|
1736
1789
|
* handlers for the current state, but not enter a new state.
|
|
1737
1790
|
*/
|
|
1738
1791
|
stop() {
|
|
1739
|
-
if (this
|
|
1792
|
+
if (this.#runningState !== 1 /* STARTED */) {
|
|
1740
1793
|
throw new Error("Cannot stop a state machine that hasn't started yet");
|
|
1741
1794
|
}
|
|
1742
|
-
this
|
|
1743
|
-
this
|
|
1744
|
-
this
|
|
1795
|
+
this.#exit(null);
|
|
1796
|
+
this.#runningState = 2 /* STOPPED */;
|
|
1797
|
+
this.#currentStateOrNull = null;
|
|
1745
1798
|
}
|
|
1746
1799
|
constructor(initialContext) {
|
|
1747
1800
|
this.id = nextId++;
|
|
1748
|
-
this
|
|
1749
|
-
this
|
|
1750
|
-
this
|
|
1751
|
-
this
|
|
1752
|
-
this
|
|
1753
|
-
this
|
|
1754
|
-
this
|
|
1755
|
-
this
|
|
1756
|
-
this
|
|
1801
|
+
this.#runningState = 0 /* NOT_STARTED_YET */;
|
|
1802
|
+
this.#currentStateOrNull = null;
|
|
1803
|
+
this.#states = /* @__PURE__ */ new Set();
|
|
1804
|
+
this.#enterFns = /* @__PURE__ */ new Map();
|
|
1805
|
+
this.#cleanupStack = [];
|
|
1806
|
+
this.#knownEventTypes = /* @__PURE__ */ new Set();
|
|
1807
|
+
this.#allowedTransitions = /* @__PURE__ */ new Map();
|
|
1808
|
+
this.#currentContext = new SafeContext(initialContext);
|
|
1809
|
+
this.#eventHub = {
|
|
1757
1810
|
didReceiveEvent: makeEventSource(),
|
|
1758
1811
|
willTransition: makeEventSource(),
|
|
1759
1812
|
didIgnoreEvent: makeEventSource(),
|
|
@@ -1761,30 +1814,30 @@ var FSM = class {
|
|
|
1761
1814
|
didEnterState: makeEventSource()
|
|
1762
1815
|
};
|
|
1763
1816
|
this.events = {
|
|
1764
|
-
didReceiveEvent: this
|
|
1765
|
-
willTransition: this
|
|
1766
|
-
didIgnoreEvent: this
|
|
1767
|
-
willExitState: this
|
|
1768
|
-
didEnterState: this
|
|
1817
|
+
didReceiveEvent: this.#eventHub.didReceiveEvent.observable,
|
|
1818
|
+
willTransition: this.#eventHub.willTransition.observable,
|
|
1819
|
+
didIgnoreEvent: this.#eventHub.didIgnoreEvent.observable,
|
|
1820
|
+
willExitState: this.#eventHub.willExitState.observable,
|
|
1821
|
+
didEnterState: this.#eventHub.didEnterState.observable
|
|
1769
1822
|
};
|
|
1770
1823
|
}
|
|
1771
1824
|
get context() {
|
|
1772
|
-
return this
|
|
1825
|
+
return this.#currentContext.current;
|
|
1773
1826
|
}
|
|
1774
1827
|
/**
|
|
1775
1828
|
* Define an explicit finite state in the state machine.
|
|
1776
1829
|
*/
|
|
1777
1830
|
addState(state) {
|
|
1778
|
-
if (this
|
|
1831
|
+
if (this.#runningState !== 0 /* NOT_STARTED_YET */) {
|
|
1779
1832
|
throw new Error("Already started");
|
|
1780
1833
|
}
|
|
1781
|
-
this
|
|
1834
|
+
this.#states.add(state);
|
|
1782
1835
|
return this;
|
|
1783
1836
|
}
|
|
1784
1837
|
onEnter(nameOrPattern, enterFn) {
|
|
1785
|
-
if (this
|
|
1838
|
+
if (this.#runningState !== 0 /* NOT_STARTED_YET */) {
|
|
1786
1839
|
throw new Error("Already started");
|
|
1787
|
-
} else if (this
|
|
1840
|
+
} else if (this.#enterFns.has(nameOrPattern)) {
|
|
1788
1841
|
throw new Error(
|
|
1789
1842
|
// TODO We _currently_ don't support multiple .onEnters() for the same
|
|
1790
1843
|
// state, but this is not a fundamental limitation. Just not
|
|
@@ -1792,7 +1845,7 @@ var FSM = class {
|
|
|
1792
1845
|
`enter/exit function for ${nameOrPattern} already exists`
|
|
1793
1846
|
);
|
|
1794
1847
|
}
|
|
1795
|
-
this
|
|
1848
|
+
this.#enterFns.set(nameOrPattern, enterFn);
|
|
1796
1849
|
return this;
|
|
1797
1850
|
}
|
|
1798
1851
|
/**
|
|
@@ -1826,22 +1879,22 @@ var FSM = class {
|
|
|
1826
1879
|
const signal = abortController.signal;
|
|
1827
1880
|
const timeoutId = maxTimeout ? setTimeout(() => {
|
|
1828
1881
|
const reason = new Error("Timed out");
|
|
1829
|
-
this
|
|
1882
|
+
this.#transition({ type: "ASYNC_ERROR", reason }, onError);
|
|
1830
1883
|
}, maxTimeout) : void 0;
|
|
1831
1884
|
let done = false;
|
|
1832
|
-
void promiseFn(this
|
|
1885
|
+
void promiseFn(this.#currentContext.current, signal).then(
|
|
1833
1886
|
// On OK
|
|
1834
1887
|
(data) => {
|
|
1835
1888
|
if (!signal.aborted) {
|
|
1836
1889
|
done = true;
|
|
1837
|
-
this
|
|
1890
|
+
this.#transition({ type: "ASYNC_OK", data }, onOK);
|
|
1838
1891
|
}
|
|
1839
1892
|
},
|
|
1840
1893
|
// On Error
|
|
1841
1894
|
(reason) => {
|
|
1842
1895
|
if (!signal.aborted) {
|
|
1843
1896
|
done = true;
|
|
1844
|
-
this
|
|
1897
|
+
this.#transition({ type: "ASYNC_ERROR", reason }, onError);
|
|
1845
1898
|
}
|
|
1846
1899
|
}
|
|
1847
1900
|
);
|
|
@@ -1853,22 +1906,22 @@ var FSM = class {
|
|
|
1853
1906
|
};
|
|
1854
1907
|
});
|
|
1855
1908
|
}
|
|
1856
|
-
getStatesMatching(nameOrPattern) {
|
|
1909
|
+
#getStatesMatching(nameOrPattern) {
|
|
1857
1910
|
const matches = [];
|
|
1858
1911
|
if (nameOrPattern === "*") {
|
|
1859
|
-
for (const state of this
|
|
1912
|
+
for (const state of this.#states) {
|
|
1860
1913
|
matches.push(state);
|
|
1861
1914
|
}
|
|
1862
1915
|
} else if (nameOrPattern.endsWith(".*")) {
|
|
1863
1916
|
const prefix = nameOrPattern.slice(0, -1);
|
|
1864
|
-
for (const state of this
|
|
1917
|
+
for (const state of this.#states) {
|
|
1865
1918
|
if (state.startsWith(prefix)) {
|
|
1866
1919
|
matches.push(state);
|
|
1867
1920
|
}
|
|
1868
1921
|
}
|
|
1869
1922
|
} else {
|
|
1870
1923
|
const name = nameOrPattern;
|
|
1871
|
-
if (this
|
|
1924
|
+
if (this.#states.has(name)) {
|
|
1872
1925
|
matches.push(name);
|
|
1873
1926
|
}
|
|
1874
1927
|
}
|
|
@@ -1890,14 +1943,14 @@ var FSM = class {
|
|
|
1890
1943
|
* such events will get ignored.
|
|
1891
1944
|
*/
|
|
1892
1945
|
addTransitions(nameOrPattern, mapping) {
|
|
1893
|
-
if (this
|
|
1946
|
+
if (this.#runningState !== 0 /* NOT_STARTED_YET */) {
|
|
1894
1947
|
throw new Error("Already started");
|
|
1895
1948
|
}
|
|
1896
|
-
for (const srcState of this
|
|
1897
|
-
let map = this
|
|
1949
|
+
for (const srcState of this.#getStatesMatching(nameOrPattern)) {
|
|
1950
|
+
let map = this.#allowedTransitions.get(srcState);
|
|
1898
1951
|
if (map === void 0) {
|
|
1899
1952
|
map = /* @__PURE__ */ new Map();
|
|
1900
|
-
this
|
|
1953
|
+
this.#allowedTransitions.set(srcState, map);
|
|
1901
1954
|
}
|
|
1902
1955
|
for (const [type, target_] of Object.entries(mapping)) {
|
|
1903
1956
|
if (map.has(type)) {
|
|
@@ -1906,7 +1959,7 @@ var FSM = class {
|
|
|
1906
1959
|
);
|
|
1907
1960
|
}
|
|
1908
1961
|
const target = target_;
|
|
1909
|
-
this
|
|
1962
|
+
this.#knownEventTypes.add(type);
|
|
1910
1963
|
if (target !== void 0) {
|
|
1911
1964
|
const targetFn = typeof target === "function" ? target : () => target;
|
|
1912
1965
|
map.set(type, targetFn);
|
|
@@ -1927,17 +1980,17 @@ var FSM = class {
|
|
|
1927
1980
|
*/
|
|
1928
1981
|
addTimedTransition(stateOrPattern, after2, target) {
|
|
1929
1982
|
return this.onEnter(stateOrPattern, () => {
|
|
1930
|
-
const ms = typeof after2 === "function" ? after2(this
|
|
1983
|
+
const ms = typeof after2 === "function" ? after2(this.#currentContext.current) : after2;
|
|
1931
1984
|
const timeoutID = setTimeout(() => {
|
|
1932
|
-
this
|
|
1985
|
+
this.#transition({ type: "TIMER" }, target);
|
|
1933
1986
|
}, ms);
|
|
1934
1987
|
return () => {
|
|
1935
1988
|
clearTimeout(timeoutID);
|
|
1936
1989
|
};
|
|
1937
1990
|
});
|
|
1938
1991
|
}
|
|
1939
|
-
getTargetFn(eventName) {
|
|
1940
|
-
return this
|
|
1992
|
+
#getTargetFn(eventName) {
|
|
1993
|
+
return this.#allowedTransitions.get(this.currentState)?.get(eventName);
|
|
1941
1994
|
}
|
|
1942
1995
|
/**
|
|
1943
1996
|
* Exits the current state, and executes any necessary cleanup functions.
|
|
@@ -1949,12 +2002,12 @@ var FSM = class {
|
|
|
1949
2002
|
* `foo.bar.qux` to `bla.bla`, then the level is 3.
|
|
1950
2003
|
* If `null`, it will exit all levels.
|
|
1951
2004
|
*/
|
|
1952
|
-
exit(levels) {
|
|
1953
|
-
this
|
|
1954
|
-
this
|
|
1955
|
-
levels = levels ?? this
|
|
2005
|
+
#exit(levels) {
|
|
2006
|
+
this.#eventHub.willExitState.notify(this.currentState);
|
|
2007
|
+
this.#currentContext.allowPatching((patchableContext) => {
|
|
2008
|
+
levels = levels ?? this.#cleanupStack.length;
|
|
1956
2009
|
for (let i = 0; i < levels; i++) {
|
|
1957
|
-
this
|
|
2010
|
+
this.#cleanupStack.pop()?.(patchableContext);
|
|
1958
2011
|
}
|
|
1959
2012
|
});
|
|
1960
2013
|
}
|
|
@@ -1962,51 +2015,51 @@ var FSM = class {
|
|
|
1962
2015
|
* Enters the current state, and executes any necessary onEnter handlers.
|
|
1963
2016
|
* Call this directly _after_ setting the current state to the next state.
|
|
1964
2017
|
*/
|
|
1965
|
-
enter(levels) {
|
|
2018
|
+
#enter(levels) {
|
|
1966
2019
|
const enterPatterns = patterns(
|
|
1967
2020
|
this.currentState,
|
|
1968
2021
|
levels ?? this.currentState.split(".").length + 1
|
|
1969
2022
|
);
|
|
1970
|
-
this
|
|
2023
|
+
this.#currentContext.allowPatching((patchableContext) => {
|
|
1971
2024
|
for (const pattern of enterPatterns) {
|
|
1972
|
-
const enterFn = this
|
|
2025
|
+
const enterFn = this.#enterFns.get(pattern);
|
|
1973
2026
|
const cleanupFn = enterFn?.(patchableContext);
|
|
1974
2027
|
if (typeof cleanupFn === "function") {
|
|
1975
|
-
this
|
|
2028
|
+
this.#cleanupStack.push(cleanupFn);
|
|
1976
2029
|
} else {
|
|
1977
|
-
this
|
|
2030
|
+
this.#cleanupStack.push(null);
|
|
1978
2031
|
}
|
|
1979
2032
|
}
|
|
1980
2033
|
});
|
|
1981
|
-
this
|
|
2034
|
+
this.#eventHub.didEnterState.notify(this.currentState);
|
|
1982
2035
|
}
|
|
1983
2036
|
/**
|
|
1984
2037
|
* Sends an event to the machine, which may cause an internal state
|
|
1985
2038
|
* transition to happen. When that happens, will trigger side effects.
|
|
1986
2039
|
*/
|
|
1987
2040
|
send(event) {
|
|
1988
|
-
if (!this
|
|
2041
|
+
if (!this.#knownEventTypes.has(event.type)) {
|
|
1989
2042
|
throw new Error(`Invalid event ${JSON.stringify(event.type)}`);
|
|
1990
2043
|
}
|
|
1991
|
-
if (this
|
|
2044
|
+
if (this.#runningState === 2 /* STOPPED */) {
|
|
1992
2045
|
return;
|
|
1993
2046
|
}
|
|
1994
|
-
const targetFn = this
|
|
2047
|
+
const targetFn = this.#getTargetFn(event.type);
|
|
1995
2048
|
if (targetFn !== void 0) {
|
|
1996
|
-
return this
|
|
2049
|
+
return this.#transition(event, targetFn);
|
|
1997
2050
|
} else {
|
|
1998
|
-
this
|
|
2051
|
+
this.#eventHub.didIgnoreEvent.notify(event);
|
|
1999
2052
|
}
|
|
2000
2053
|
}
|
|
2001
|
-
transition(event, target) {
|
|
2002
|
-
this
|
|
2054
|
+
#transition(event, target) {
|
|
2055
|
+
this.#eventHub.didReceiveEvent.notify(event);
|
|
2003
2056
|
const oldState = this.currentState;
|
|
2004
2057
|
const targetFn = typeof target === "function" ? target : () => target;
|
|
2005
|
-
const nextTarget = targetFn(event, this
|
|
2058
|
+
const nextTarget = targetFn(event, this.#currentContext.current);
|
|
2006
2059
|
let nextState;
|
|
2007
2060
|
let effects = void 0;
|
|
2008
2061
|
if (nextTarget === null) {
|
|
2009
|
-
this
|
|
2062
|
+
this.#eventHub.didIgnoreEvent.notify(event);
|
|
2010
2063
|
return;
|
|
2011
2064
|
}
|
|
2012
2065
|
if (typeof nextTarget === "string") {
|
|
@@ -2015,18 +2068,18 @@ var FSM = class {
|
|
|
2015
2068
|
nextState = nextTarget.target;
|
|
2016
2069
|
effects = Array.isArray(nextTarget.effect) ? nextTarget.effect : [nextTarget.effect];
|
|
2017
2070
|
}
|
|
2018
|
-
if (!this
|
|
2071
|
+
if (!this.#states.has(nextState)) {
|
|
2019
2072
|
throw new Error(`Invalid next state name: ${JSON.stringify(nextState)}`);
|
|
2020
2073
|
}
|
|
2021
|
-
this
|
|
2074
|
+
this.#eventHub.willTransition.notify({ from: oldState, to: nextState });
|
|
2022
2075
|
const [up, down] = distance(this.currentState, nextState);
|
|
2023
2076
|
if (up > 0) {
|
|
2024
|
-
this
|
|
2077
|
+
this.#exit(up);
|
|
2025
2078
|
}
|
|
2026
|
-
this
|
|
2079
|
+
this.#currentStateOrNull = nextState;
|
|
2027
2080
|
if (effects !== void 0) {
|
|
2028
2081
|
const effectsToRun = effects;
|
|
2029
|
-
this
|
|
2082
|
+
this.#currentContext.allowPatching((patchableContext) => {
|
|
2030
2083
|
for (const effect of effectsToRun) {
|
|
2031
2084
|
if (typeof effect === "function") {
|
|
2032
2085
|
effect(patchableContext, event);
|
|
@@ -2037,7 +2090,7 @@ var FSM = class {
|
|
|
2037
2090
|
});
|
|
2038
2091
|
}
|
|
2039
2092
|
if (down > 0) {
|
|
2040
|
-
this
|
|
2093
|
+
this.#enter(down);
|
|
2041
2094
|
}
|
|
2042
2095
|
}
|
|
2043
2096
|
};
|
|
@@ -2243,7 +2296,7 @@ function defineConnectivityEvents(machine) {
|
|
|
2243
2296
|
}
|
|
2244
2297
|
var assign = (patch) => (ctx) => ctx.patch(patch);
|
|
2245
2298
|
function createConnectionStateMachine(delegates, options) {
|
|
2246
|
-
const onMessage =
|
|
2299
|
+
const onMessage = makeBufferableEventSource();
|
|
2247
2300
|
onMessage.pause();
|
|
2248
2301
|
const onLiveblocksError = makeEventSource();
|
|
2249
2302
|
function fireErrorEvent(errmsg, errcode) {
|
|
@@ -2612,18 +2665,21 @@ function createConnectionStateMachine(delegates, options) {
|
|
|
2612
2665
|
};
|
|
2613
2666
|
}
|
|
2614
2667
|
var ManagedSocket = class {
|
|
2668
|
+
#machine;
|
|
2669
|
+
#cleanups;
|
|
2670
|
+
events;
|
|
2615
2671
|
constructor(delegates, enableDebugLogging = false, waitForActorId = true) {
|
|
2616
2672
|
const { machine, events, cleanups } = createConnectionStateMachine(
|
|
2617
2673
|
delegates,
|
|
2618
2674
|
{ waitForActorId, enableDebugLogging }
|
|
2619
2675
|
);
|
|
2620
|
-
this
|
|
2676
|
+
this.#machine = machine;
|
|
2621
2677
|
this.events = events;
|
|
2622
|
-
this
|
|
2678
|
+
this.#cleanups = cleanups;
|
|
2623
2679
|
}
|
|
2624
2680
|
getStatus() {
|
|
2625
2681
|
try {
|
|
2626
|
-
return toNewConnectionStatus(this
|
|
2682
|
+
return toNewConnectionStatus(this.#machine);
|
|
2627
2683
|
} catch {
|
|
2628
2684
|
return "initial";
|
|
2629
2685
|
}
|
|
@@ -2632,28 +2688,28 @@ var ManagedSocket = class {
|
|
|
2632
2688
|
* Returns the current auth authValue.
|
|
2633
2689
|
*/
|
|
2634
2690
|
get authValue() {
|
|
2635
|
-
return this
|
|
2691
|
+
return this.#machine.context.authValue;
|
|
2636
2692
|
}
|
|
2637
2693
|
/**
|
|
2638
2694
|
* Call this method to try to connect to a WebSocket. This only has an effect
|
|
2639
2695
|
* if the machine is idle at the moment, otherwise this is a no-op.
|
|
2640
2696
|
*/
|
|
2641
2697
|
connect() {
|
|
2642
|
-
this
|
|
2698
|
+
this.#machine.send({ type: "CONNECT" });
|
|
2643
2699
|
}
|
|
2644
2700
|
/**
|
|
2645
2701
|
* If idle, will try to connect. Otherwise, it will attempt to reconnect to
|
|
2646
2702
|
* the socket, potentially obtaining a new authValue first, if needed.
|
|
2647
2703
|
*/
|
|
2648
2704
|
reconnect() {
|
|
2649
|
-
this
|
|
2705
|
+
this.#machine.send({ type: "RECONNECT" });
|
|
2650
2706
|
}
|
|
2651
2707
|
/**
|
|
2652
2708
|
* Call this method to disconnect from the current WebSocket. Is going to be
|
|
2653
2709
|
* a no-op if there is no active connection.
|
|
2654
2710
|
*/
|
|
2655
2711
|
disconnect() {
|
|
2656
|
-
this
|
|
2712
|
+
this.#machine.send({ type: "DISCONNECT" });
|
|
2657
2713
|
}
|
|
2658
2714
|
/**
|
|
2659
2715
|
* Call this to stop the machine and run necessary cleanup functions. After
|
|
@@ -2661,9 +2717,9 @@ var ManagedSocket = class {
|
|
|
2661
2717
|
* letting the instance get garbage collected.
|
|
2662
2718
|
*/
|
|
2663
2719
|
destroy() {
|
|
2664
|
-
this
|
|
2720
|
+
this.#machine.stop();
|
|
2665
2721
|
let cleanup;
|
|
2666
|
-
while (cleanup = this
|
|
2722
|
+
while (cleanup = this.#cleanups.pop()) {
|
|
2667
2723
|
cleanup();
|
|
2668
2724
|
}
|
|
2669
2725
|
}
|
|
@@ -2672,7 +2728,7 @@ var ManagedSocket = class {
|
|
|
2672
2728
|
* message if this is somehow impossible.
|
|
2673
2729
|
*/
|
|
2674
2730
|
send(data) {
|
|
2675
|
-
const socket = this
|
|
2731
|
+
const socket = this.#machine.context?.socket;
|
|
2676
2732
|
if (socket === null) {
|
|
2677
2733
|
warn("Cannot send: not connected yet", data);
|
|
2678
2734
|
} else if (socket.readyState !== 1) {
|
|
@@ -2686,7 +2742,7 @@ var ManagedSocket = class {
|
|
|
2686
2742
|
* Not ideal to keep exposed :(
|
|
2687
2743
|
*/
|
|
2688
2744
|
_privateSendMachineEvent(event) {
|
|
2689
|
-
this
|
|
2745
|
+
this.#machine.send(event);
|
|
2690
2746
|
}
|
|
2691
2747
|
};
|
|
2692
2748
|
|
|
@@ -3158,68 +3214,35 @@ function unlinkDevTools(roomId) {
|
|
|
3158
3214
|
});
|
|
3159
3215
|
}
|
|
3160
3216
|
|
|
3161
|
-
// src/lib/create-store.ts
|
|
3162
|
-
function createStore(initialState) {
|
|
3163
|
-
let notifyImmediately = true;
|
|
3164
|
-
let dirty = false;
|
|
3165
|
-
let state = initialState;
|
|
3166
|
-
const subscribers = /* @__PURE__ */ new Set();
|
|
3167
|
-
function get() {
|
|
3168
|
-
return state;
|
|
3169
|
-
}
|
|
3170
|
-
function set(callback) {
|
|
3171
|
-
const oldState = state;
|
|
3172
|
-
const newState = callback(oldState);
|
|
3173
|
-
if (newState !== oldState) {
|
|
3174
|
-
state = newState;
|
|
3175
|
-
dirty = true;
|
|
3176
|
-
}
|
|
3177
|
-
if (notifyImmediately) {
|
|
3178
|
-
notify();
|
|
3179
|
-
}
|
|
3180
|
-
}
|
|
3181
|
-
function notify() {
|
|
3182
|
-
if (!dirty) {
|
|
3183
|
-
return;
|
|
3184
|
-
}
|
|
3185
|
-
dirty = false;
|
|
3186
|
-
for (const subscriber of subscribers) {
|
|
3187
|
-
subscriber(state);
|
|
3188
|
-
}
|
|
3189
|
-
}
|
|
3190
|
-
function batch(cb) {
|
|
3191
|
-
if (notifyImmediately === false) {
|
|
3192
|
-
return cb();
|
|
3193
|
-
}
|
|
3194
|
-
notifyImmediately = false;
|
|
3195
|
-
try {
|
|
3196
|
-
cb();
|
|
3197
|
-
} finally {
|
|
3198
|
-
notifyImmediately = true;
|
|
3199
|
-
notify();
|
|
3200
|
-
}
|
|
3201
|
-
}
|
|
3202
|
-
function subscribe(callback) {
|
|
3203
|
-
subscribers.add(callback);
|
|
3204
|
-
return () => {
|
|
3205
|
-
subscribers.delete(callback);
|
|
3206
|
-
};
|
|
3207
|
-
}
|
|
3208
|
-
return {
|
|
3209
|
-
get,
|
|
3210
|
-
set,
|
|
3211
|
-
batch,
|
|
3212
|
-
subscribe
|
|
3213
|
-
};
|
|
3214
|
-
}
|
|
3215
|
-
|
|
3216
3217
|
// src/lib/freeze.ts
|
|
3217
3218
|
var freeze = process.env.NODE_ENV === "production" ? (
|
|
3218
3219
|
/* istanbul ignore next */
|
|
3219
3220
|
(x) => x
|
|
3220
3221
|
) : Object.freeze;
|
|
3221
3222
|
|
|
3222
|
-
// src/
|
|
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
|
+
}
|
|
3223
3246
|
function merge(target, patch) {
|
|
3224
3247
|
let updated = false;
|
|
3225
3248
|
const newValue = { ...target };
|
|
@@ -3237,57 +3260,218 @@ function merge(target, patch) {
|
|
|
3237
3260
|
});
|
|
3238
3261
|
return updated ? newValue : target;
|
|
3239
3262
|
}
|
|
3240
|
-
var
|
|
3241
|
-
|
|
3242
|
-
|
|
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;
|
|
3243
3290
|
}
|
|
3244
|
-
|
|
3245
|
-
|
|
3291
|
+
[kTrigger]() {
|
|
3292
|
+
this.#eventSource.notify();
|
|
3293
|
+
for (const sink of this[kSinks]) {
|
|
3294
|
+
enqueueTrigger(sink);
|
|
3295
|
+
}
|
|
3246
3296
|
}
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
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();
|
|
3251
3313
|
}
|
|
3252
3314
|
}
|
|
3253
|
-
|
|
3254
|
-
|
|
3315
|
+
addSink(sink) {
|
|
3316
|
+
this[kSinks].add(sink);
|
|
3317
|
+
}
|
|
3318
|
+
removeSink(sink) {
|
|
3319
|
+
this[kSinks].delete(sink);
|
|
3320
|
+
}
|
|
3321
|
+
asReadonly() {
|
|
3322
|
+
return this;
|
|
3255
3323
|
}
|
|
3256
3324
|
};
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
this._value = freeze(initialValue);
|
|
3325
|
+
var Signal = class extends AbstractSignal {
|
|
3326
|
+
#value;
|
|
3327
|
+
constructor(value, equals) {
|
|
3328
|
+
super(equals);
|
|
3329
|
+
this.#value = freeze(value);
|
|
3263
3330
|
}
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3331
|
+
[Symbol.dispose]() {
|
|
3332
|
+
super[Symbol.dispose]();
|
|
3333
|
+
this.#value = "(disposed)";
|
|
3334
|
+
}
|
|
3335
|
+
get() {
|
|
3336
|
+
return this.#value;
|
|
3267
3337
|
}
|
|
3268
3338
|
set(newValue) {
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
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]();
|
|
3272
3441
|
}
|
|
3273
3442
|
}
|
|
3274
3443
|
};
|
|
3275
|
-
var
|
|
3276
|
-
|
|
3444
|
+
var MutableSignal = class extends AbstractSignal {
|
|
3445
|
+
#state;
|
|
3446
|
+
constructor(initialState) {
|
|
3277
3447
|
super();
|
|
3278
|
-
|
|
3279
|
-
const otherRefs = args;
|
|
3280
|
-
this._refs = otherRefs;
|
|
3281
|
-
this._refs.forEach((ref) => {
|
|
3282
|
-
ref.didInvalidate.subscribe(() => this.invalidate());
|
|
3283
|
-
});
|
|
3284
|
-
this._transform = transformFn;
|
|
3448
|
+
this.#state = initialState;
|
|
3285
3449
|
}
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
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
|
+
});
|
|
3291
3475
|
}
|
|
3292
3476
|
};
|
|
3293
3477
|
|
|
@@ -3455,10 +3639,10 @@ function Orphaned(oldKey, oldPos = asPos(oldKey)) {
|
|
|
3455
3639
|
return Object.freeze({ type: "Orphaned", oldKey, oldPos });
|
|
3456
3640
|
}
|
|
3457
3641
|
var AbstractCrdt = class {
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3642
|
+
// ^^^^^^^^^^^^ TODO: Make this an interface
|
|
3643
|
+
#pool;
|
|
3644
|
+
#id;
|
|
3645
|
+
#parent = NoParent;
|
|
3462
3646
|
/** @internal */
|
|
3463
3647
|
_getParentKeyOrThrow() {
|
|
3464
3648
|
switch (this.parent.type) {
|
|
@@ -3487,18 +3671,18 @@ var AbstractCrdt = class {
|
|
|
3487
3671
|
}
|
|
3488
3672
|
/** @internal */
|
|
3489
3673
|
get _pool() {
|
|
3490
|
-
return this
|
|
3674
|
+
return this.#pool;
|
|
3491
3675
|
}
|
|
3492
3676
|
get roomId() {
|
|
3493
|
-
return this
|
|
3677
|
+
return this.#pool ? this.#pool.roomId : null;
|
|
3494
3678
|
}
|
|
3495
3679
|
/** @internal */
|
|
3496
3680
|
get _id() {
|
|
3497
|
-
return this
|
|
3681
|
+
return this.#id;
|
|
3498
3682
|
}
|
|
3499
3683
|
/** @internal */
|
|
3500
3684
|
get parent() {
|
|
3501
|
-
return this
|
|
3685
|
+
return this.#parent;
|
|
3502
3686
|
}
|
|
3503
3687
|
/** @internal */
|
|
3504
3688
|
get _parentKey() {
|
|
@@ -3532,12 +3716,12 @@ var AbstractCrdt = class {
|
|
|
3532
3716
|
if (this.parent.node !== newParentNode) {
|
|
3533
3717
|
throw new Error("Cannot set parent: node already has a parent");
|
|
3534
3718
|
} else {
|
|
3535
|
-
this
|
|
3719
|
+
this.#parent = HasParent(newParentNode, newParentKey);
|
|
3536
3720
|
return;
|
|
3537
3721
|
}
|
|
3538
3722
|
case "Orphaned":
|
|
3539
3723
|
case "NoParent": {
|
|
3540
|
-
this
|
|
3724
|
+
this.#parent = HasParent(newParentNode, newParentKey);
|
|
3541
3725
|
return;
|
|
3542
3726
|
}
|
|
3543
3727
|
default:
|
|
@@ -3546,25 +3730,25 @@ var AbstractCrdt = class {
|
|
|
3546
3730
|
}
|
|
3547
3731
|
/** @internal */
|
|
3548
3732
|
_attach(id, pool) {
|
|
3549
|
-
if (this
|
|
3733
|
+
if (this.#id || this.#pool) {
|
|
3550
3734
|
throw new Error("Cannot attach node: already attached");
|
|
3551
3735
|
}
|
|
3552
3736
|
pool.addNode(id, crdtAsLiveNode(this));
|
|
3553
|
-
this
|
|
3554
|
-
this
|
|
3737
|
+
this.#id = id;
|
|
3738
|
+
this.#pool = pool;
|
|
3555
3739
|
}
|
|
3556
3740
|
/** @internal */
|
|
3557
3741
|
_detach() {
|
|
3558
|
-
if (this
|
|
3559
|
-
this.
|
|
3742
|
+
if (this.#pool && this.#id) {
|
|
3743
|
+
this.#pool.deleteNode(this.#id);
|
|
3560
3744
|
}
|
|
3561
3745
|
switch (this.parent.type) {
|
|
3562
3746
|
case "HasParent": {
|
|
3563
|
-
this
|
|
3747
|
+
this.#parent = Orphaned(this.parent.key, this.parent.pos);
|
|
3564
3748
|
break;
|
|
3565
3749
|
}
|
|
3566
3750
|
case "NoParent": {
|
|
3567
|
-
this
|
|
3751
|
+
this.#parent = NoParent;
|
|
3568
3752
|
break;
|
|
3569
3753
|
}
|
|
3570
3754
|
case "Orphaned": {
|
|
@@ -3573,8 +3757,13 @@ var AbstractCrdt = class {
|
|
|
3573
3757
|
default:
|
|
3574
3758
|
assertNever(this.parent, "Unknown state");
|
|
3575
3759
|
}
|
|
3576
|
-
this
|
|
3760
|
+
this.#pool = void 0;
|
|
3577
3761
|
}
|
|
3762
|
+
/** This caches the result of the last .toImmutable() call for this Live node. */
|
|
3763
|
+
#cachedImmutable;
|
|
3764
|
+
#cachedTreeNodeKey;
|
|
3765
|
+
/** This caches the result of the last .toTreeNode() call for this Live node. */
|
|
3766
|
+
#cachedTreeNode;
|
|
3578
3767
|
/**
|
|
3579
3768
|
* @internal
|
|
3580
3769
|
*
|
|
@@ -3583,9 +3772,9 @@ var AbstractCrdt = class {
|
|
|
3583
3772
|
* mutation to the Live node.
|
|
3584
3773
|
*/
|
|
3585
3774
|
invalidate() {
|
|
3586
|
-
if (this
|
|
3587
|
-
this
|
|
3588
|
-
this
|
|
3775
|
+
if (this.#cachedImmutable !== void 0 || this.#cachedTreeNode !== void 0) {
|
|
3776
|
+
this.#cachedImmutable = void 0;
|
|
3777
|
+
this.#cachedTreeNode = void 0;
|
|
3589
3778
|
if (this.parent.type === "HasParent") {
|
|
3590
3779
|
this.parent.node.invalidate();
|
|
3591
3780
|
}
|
|
@@ -3597,20 +3786,20 @@ var AbstractCrdt = class {
|
|
|
3597
3786
|
* Return an snapshot of this Live tree for use in DevTools.
|
|
3598
3787
|
*/
|
|
3599
3788
|
toTreeNode(key) {
|
|
3600
|
-
if (this
|
|
3601
|
-
this
|
|
3602
|
-
this
|
|
3789
|
+
if (this.#cachedTreeNode === void 0 || this.#cachedTreeNodeKey !== key) {
|
|
3790
|
+
this.#cachedTreeNodeKey = key;
|
|
3791
|
+
this.#cachedTreeNode = this._toTreeNode(key);
|
|
3603
3792
|
}
|
|
3604
|
-
return this
|
|
3793
|
+
return this.#cachedTreeNode;
|
|
3605
3794
|
}
|
|
3606
3795
|
/**
|
|
3607
3796
|
* Return an immutable snapshot of this Live node and its children.
|
|
3608
3797
|
*/
|
|
3609
3798
|
toImmutable() {
|
|
3610
|
-
if (this
|
|
3611
|
-
this
|
|
3799
|
+
if (this.#cachedImmutable === void 0) {
|
|
3800
|
+
this.#cachedImmutable = this._toImmutable();
|
|
3612
3801
|
}
|
|
3613
|
-
return this
|
|
3802
|
+
return this.#cachedImmutable;
|
|
3614
3803
|
}
|
|
3615
3804
|
};
|
|
3616
3805
|
|
|
@@ -3631,12 +3820,13 @@ function isChildCrdt(crdt) {
|
|
|
3631
3820
|
|
|
3632
3821
|
// src/crdts/LiveRegister.ts
|
|
3633
3822
|
var LiveRegister = class _LiveRegister extends AbstractCrdt {
|
|
3823
|
+
#data;
|
|
3634
3824
|
constructor(data) {
|
|
3635
3825
|
super();
|
|
3636
|
-
this
|
|
3826
|
+
this.#data = data;
|
|
3637
3827
|
}
|
|
3638
3828
|
get data() {
|
|
3639
|
-
return this
|
|
3829
|
+
return this.#data;
|
|
3640
3830
|
}
|
|
3641
3831
|
/** @internal */
|
|
3642
3832
|
static _deserialize([id, item], _parentToChildren, pool) {
|
|
@@ -3692,12 +3882,12 @@ var LiveRegister = class _LiveRegister extends AbstractCrdt {
|
|
|
3692
3882
|
type: "Json",
|
|
3693
3883
|
id: this._id ?? nanoid(),
|
|
3694
3884
|
key,
|
|
3695
|
-
payload: this
|
|
3885
|
+
payload: this.#data
|
|
3696
3886
|
};
|
|
3697
3887
|
}
|
|
3698
3888
|
/** @internal */
|
|
3699
3889
|
_toImmutable() {
|
|
3700
|
-
return this
|
|
3890
|
+
return this.#data;
|
|
3701
3891
|
}
|
|
3702
3892
|
clone() {
|
|
3703
3893
|
return deepClone(this.data);
|
|
@@ -3711,17 +3901,21 @@ function compareNodePosition(itemA, itemB) {
|
|
|
3711
3901
|
return posA === posB ? 0 : posA < posB ? -1 : 1;
|
|
3712
3902
|
}
|
|
3713
3903
|
var LiveList = class _LiveList extends AbstractCrdt {
|
|
3904
|
+
// TODO: Naive array at first, find a better data structure. Maybe an Order statistics tree?
|
|
3905
|
+
#items;
|
|
3906
|
+
#implicitlyDeletedItems;
|
|
3907
|
+
#unacknowledgedSets;
|
|
3714
3908
|
constructor(items) {
|
|
3715
3909
|
super();
|
|
3716
|
-
this
|
|
3717
|
-
this
|
|
3718
|
-
this
|
|
3910
|
+
this.#items = [];
|
|
3911
|
+
this.#implicitlyDeletedItems = /* @__PURE__ */ new WeakSet();
|
|
3912
|
+
this.#unacknowledgedSets = /* @__PURE__ */ new Map();
|
|
3719
3913
|
let position = void 0;
|
|
3720
3914
|
for (const item of items) {
|
|
3721
3915
|
const newPosition = makePosition(position);
|
|
3722
3916
|
const node = lsonToLiveNode(item);
|
|
3723
3917
|
node._setParentLink(this, newPosition);
|
|
3724
|
-
this.
|
|
3918
|
+
this.#items.push(node);
|
|
3725
3919
|
position = newPosition;
|
|
3726
3920
|
}
|
|
3727
3921
|
}
|
|
@@ -3762,7 +3956,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3762
3956
|
parentKey
|
|
3763
3957
|
};
|
|
3764
3958
|
ops.push(op);
|
|
3765
|
-
for (const item of this
|
|
3959
|
+
for (const item of this.#items) {
|
|
3766
3960
|
const parentKey2 = item._getParentKeyOrThrow();
|
|
3767
3961
|
const childOps = HACK_addIntentAndDeletedIdToOperation(
|
|
3768
3962
|
item._toOps(this._id, parentKey2, pool),
|
|
@@ -3770,7 +3964,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3770
3964
|
);
|
|
3771
3965
|
const childOpId = childOps[0].opId;
|
|
3772
3966
|
if (childOpId !== void 0) {
|
|
3773
|
-
this.
|
|
3967
|
+
this.#unacknowledgedSets.set(parentKey2, childOpId);
|
|
3774
3968
|
}
|
|
3775
3969
|
ops.push(...childOps);
|
|
3776
3970
|
}
|
|
@@ -3782,36 +3976,35 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3782
3976
|
* Adds a new item into the sorted list, in the correct position.
|
|
3783
3977
|
*/
|
|
3784
3978
|
_insertAndSort(item) {
|
|
3785
|
-
this.
|
|
3979
|
+
this.#items.push(item);
|
|
3786
3980
|
this._sortItems();
|
|
3787
3981
|
}
|
|
3788
3982
|
/** @internal */
|
|
3789
3983
|
_sortItems() {
|
|
3790
|
-
this.
|
|
3984
|
+
this.#items.sort(compareNodePosition);
|
|
3791
3985
|
this.invalidate();
|
|
3792
3986
|
}
|
|
3793
3987
|
/** @internal */
|
|
3794
3988
|
_indexOfPosition(position) {
|
|
3795
|
-
return this.
|
|
3989
|
+
return this.#items.findIndex(
|
|
3796
3990
|
(item) => item._getParentKeyOrThrow() === position
|
|
3797
3991
|
);
|
|
3798
3992
|
}
|
|
3799
3993
|
/** @internal */
|
|
3800
3994
|
_attach(id, pool) {
|
|
3801
3995
|
super._attach(id, pool);
|
|
3802
|
-
for (const item of this
|
|
3996
|
+
for (const item of this.#items) {
|
|
3803
3997
|
item._attach(pool.generateId(), pool);
|
|
3804
3998
|
}
|
|
3805
3999
|
}
|
|
3806
4000
|
/** @internal */
|
|
3807
4001
|
_detach() {
|
|
3808
4002
|
super._detach();
|
|
3809
|
-
for (const item of this
|
|
4003
|
+
for (const item of this.#items) {
|
|
3810
4004
|
item._detach();
|
|
3811
4005
|
}
|
|
3812
4006
|
}
|
|
3813
|
-
|
|
3814
|
-
_applySetRemote(op) {
|
|
4007
|
+
#applySetRemote(op) {
|
|
3815
4008
|
if (this._pool === void 0) {
|
|
3816
4009
|
throw new Error("Can't attach child if managed pool is not present");
|
|
3817
4010
|
}
|
|
@@ -3822,10 +4015,10 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3822
4015
|
const deletedId = op.deletedId;
|
|
3823
4016
|
const indexOfItemWithSamePosition = this._indexOfPosition(key);
|
|
3824
4017
|
if (indexOfItemWithSamePosition !== -1) {
|
|
3825
|
-
const itemWithSamePosition = this
|
|
4018
|
+
const itemWithSamePosition = this.#items[indexOfItemWithSamePosition];
|
|
3826
4019
|
if (itemWithSamePosition._id === deletedId) {
|
|
3827
4020
|
itemWithSamePosition._detach();
|
|
3828
|
-
this
|
|
4021
|
+
this.#items[indexOfItemWithSamePosition] = child;
|
|
3829
4022
|
return {
|
|
3830
4023
|
modified: makeUpdate(this, [
|
|
3831
4024
|
setDelta(indexOfItemWithSamePosition, child)
|
|
@@ -3833,12 +4026,12 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3833
4026
|
reverse: []
|
|
3834
4027
|
};
|
|
3835
4028
|
} else {
|
|
3836
|
-
this.
|
|
3837
|
-
this
|
|
4029
|
+
this.#implicitlyDeletedItems.add(itemWithSamePosition);
|
|
4030
|
+
this.#items[indexOfItemWithSamePosition] = child;
|
|
3838
4031
|
const delta = [
|
|
3839
4032
|
setDelta(indexOfItemWithSamePosition, child)
|
|
3840
4033
|
];
|
|
3841
|
-
const deleteDelta2 = this
|
|
4034
|
+
const deleteDelta2 = this.#detachItemAssociatedToSetOperation(
|
|
3842
4035
|
op.deletedId
|
|
3843
4036
|
);
|
|
3844
4037
|
if (deleteDelta2) {
|
|
@@ -3851,7 +4044,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3851
4044
|
}
|
|
3852
4045
|
} else {
|
|
3853
4046
|
const updates = [];
|
|
3854
|
-
const deleteDelta2 = this
|
|
4047
|
+
const deleteDelta2 = this.#detachItemAssociatedToSetOperation(
|
|
3855
4048
|
op.deletedId
|
|
3856
4049
|
);
|
|
3857
4050
|
if (deleteDelta2) {
|
|
@@ -3865,26 +4058,25 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3865
4058
|
};
|
|
3866
4059
|
}
|
|
3867
4060
|
}
|
|
3868
|
-
|
|
3869
|
-
_applySetAck(op) {
|
|
4061
|
+
#applySetAck(op) {
|
|
3870
4062
|
if (this._pool === void 0) {
|
|
3871
4063
|
throw new Error("Can't attach child if managed pool is not present");
|
|
3872
4064
|
}
|
|
3873
4065
|
const delta = [];
|
|
3874
|
-
const deletedDelta = this
|
|
4066
|
+
const deletedDelta = this.#detachItemAssociatedToSetOperation(op.deletedId);
|
|
3875
4067
|
if (deletedDelta) {
|
|
3876
4068
|
delta.push(deletedDelta);
|
|
3877
4069
|
}
|
|
3878
|
-
const unacknowledgedOpId = this.
|
|
4070
|
+
const unacknowledgedOpId = this.#unacknowledgedSets.get(op.parentKey);
|
|
3879
4071
|
if (unacknowledgedOpId !== void 0) {
|
|
3880
4072
|
if (unacknowledgedOpId !== op.opId) {
|
|
3881
4073
|
return delta.length === 0 ? { modified: false } : { modified: makeUpdate(this, delta), reverse: [] };
|
|
3882
4074
|
} else {
|
|
3883
|
-
this.
|
|
4075
|
+
this.#unacknowledgedSets.delete(op.parentKey);
|
|
3884
4076
|
}
|
|
3885
4077
|
}
|
|
3886
4078
|
const indexOfItemWithSamePosition = this._indexOfPosition(op.parentKey);
|
|
3887
|
-
const existingItem = this.
|
|
4079
|
+
const existingItem = this.#items.find((item) => item._id === op.id);
|
|
3888
4080
|
if (existingItem !== void 0) {
|
|
3889
4081
|
if (existingItem._parentKey === op.parentKey) {
|
|
3890
4082
|
return {
|
|
@@ -3893,16 +4085,16 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3893
4085
|
};
|
|
3894
4086
|
}
|
|
3895
4087
|
if (indexOfItemWithSamePosition !== -1) {
|
|
3896
|
-
this.
|
|
3897
|
-
this
|
|
4088
|
+
this.#implicitlyDeletedItems.add(
|
|
4089
|
+
this.#items[indexOfItemWithSamePosition]
|
|
3898
4090
|
);
|
|
3899
|
-
const [prevNode] = this.
|
|
4091
|
+
const [prevNode] = this.#items.splice(indexOfItemWithSamePosition, 1);
|
|
3900
4092
|
delta.push(deleteDelta(indexOfItemWithSamePosition, prevNode));
|
|
3901
4093
|
}
|
|
3902
|
-
const prevIndex = this.
|
|
4094
|
+
const prevIndex = this.#items.indexOf(existingItem);
|
|
3903
4095
|
existingItem._setParentLink(this, op.parentKey);
|
|
3904
4096
|
this._sortItems();
|
|
3905
|
-
const newIndex = this.
|
|
4097
|
+
const newIndex = this.#items.indexOf(existingItem);
|
|
3906
4098
|
if (newIndex !== prevIndex) {
|
|
3907
4099
|
delta.push(moveDelta(prevIndex, newIndex, existingItem));
|
|
3908
4100
|
}
|
|
@@ -3912,11 +4104,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3912
4104
|
};
|
|
3913
4105
|
} else {
|
|
3914
4106
|
const orphan = this._pool.getNode(op.id);
|
|
3915
|
-
if (orphan && this.
|
|
4107
|
+
if (orphan && this.#implicitlyDeletedItems.has(orphan)) {
|
|
3916
4108
|
orphan._setParentLink(this, op.parentKey);
|
|
3917
|
-
this.
|
|
4109
|
+
this.#implicitlyDeletedItems.delete(orphan);
|
|
3918
4110
|
this._insertAndSort(orphan);
|
|
3919
|
-
const recreatedItemIndex = this.
|
|
4111
|
+
const recreatedItemIndex = this.#items.indexOf(orphan);
|
|
3920
4112
|
return {
|
|
3921
4113
|
modified: makeUpdate(this, [
|
|
3922
4114
|
// If there is an item at this position, update is a set, else it's an insert
|
|
@@ -3927,9 +4119,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3927
4119
|
};
|
|
3928
4120
|
} else {
|
|
3929
4121
|
if (indexOfItemWithSamePosition !== -1) {
|
|
3930
|
-
this.
|
|
4122
|
+
this.#items.splice(indexOfItemWithSamePosition, 1);
|
|
3931
4123
|
}
|
|
3932
|
-
const { newItem, newIndex } = this
|
|
4124
|
+
const { newItem, newIndex } = this.#createAttachItemAndSort(
|
|
3933
4125
|
op,
|
|
3934
4126
|
op.parentKey
|
|
3935
4127
|
);
|
|
@@ -3946,9 +4138,8 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3946
4138
|
}
|
|
3947
4139
|
/**
|
|
3948
4140
|
* Returns the update delta of the deletion or null
|
|
3949
|
-
* @internal
|
|
3950
4141
|
*/
|
|
3951
|
-
|
|
4142
|
+
#detachItemAssociatedToSetOperation(deletedId) {
|
|
3952
4143
|
if (deletedId === void 0 || this._pool === void 0) {
|
|
3953
4144
|
return null;
|
|
3954
4145
|
}
|
|
@@ -3962,25 +4153,23 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3962
4153
|
}
|
|
3963
4154
|
return result.modified.updates[0];
|
|
3964
4155
|
}
|
|
3965
|
-
|
|
3966
|
-
_applyRemoteInsert(op) {
|
|
4156
|
+
#applyRemoteInsert(op) {
|
|
3967
4157
|
if (this._pool === void 0) {
|
|
3968
4158
|
throw new Error("Can't attach child if managed pool is not present");
|
|
3969
4159
|
}
|
|
3970
4160
|
const key = asPos(op.parentKey);
|
|
3971
4161
|
const existingItemIndex = this._indexOfPosition(key);
|
|
3972
4162
|
if (existingItemIndex !== -1) {
|
|
3973
|
-
this
|
|
4163
|
+
this.#shiftItemPosition(existingItemIndex, key);
|
|
3974
4164
|
}
|
|
3975
|
-
const { newItem, newIndex } = this
|
|
4165
|
+
const { newItem, newIndex } = this.#createAttachItemAndSort(op, key);
|
|
3976
4166
|
return {
|
|
3977
4167
|
modified: makeUpdate(this, [insertDelta(newIndex, newItem)]),
|
|
3978
4168
|
reverse: []
|
|
3979
4169
|
};
|
|
3980
4170
|
}
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
const existingItem = this._items.find((item) => item._id === op.id);
|
|
4171
|
+
#applyInsertAck(op) {
|
|
4172
|
+
const existingItem = this.#items.find((item) => item._id === op.id);
|
|
3984
4173
|
const key = asPos(op.parentKey);
|
|
3985
4174
|
const itemIndexAtPosition = this._indexOfPosition(key);
|
|
3986
4175
|
if (existingItem) {
|
|
@@ -3989,9 +4178,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3989
4178
|
modified: false
|
|
3990
4179
|
};
|
|
3991
4180
|
} else {
|
|
3992
|
-
const oldPositionIndex = this.
|
|
4181
|
+
const oldPositionIndex = this.#items.indexOf(existingItem);
|
|
3993
4182
|
if (itemIndexAtPosition !== -1) {
|
|
3994
|
-
this
|
|
4183
|
+
this.#shiftItemPosition(itemIndexAtPosition, key);
|
|
3995
4184
|
}
|
|
3996
4185
|
existingItem._setParentLink(this, key);
|
|
3997
4186
|
this._sortItems();
|
|
@@ -4008,9 +4197,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4008
4197
|
}
|
|
4009
4198
|
} else {
|
|
4010
4199
|
const orphan = nn(this._pool).getNode(op.id);
|
|
4011
|
-
if (orphan && this.
|
|
4200
|
+
if (orphan && this.#implicitlyDeletedItems.has(orphan)) {
|
|
4012
4201
|
orphan._setParentLink(this, key);
|
|
4013
|
-
this.
|
|
4202
|
+
this.#implicitlyDeletedItems.delete(orphan);
|
|
4014
4203
|
this._insertAndSort(orphan);
|
|
4015
4204
|
const newIndex = this._indexOfPosition(key);
|
|
4016
4205
|
return {
|
|
@@ -4019,9 +4208,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4019
4208
|
};
|
|
4020
4209
|
} else {
|
|
4021
4210
|
if (itemIndexAtPosition !== -1) {
|
|
4022
|
-
this
|
|
4211
|
+
this.#shiftItemPosition(itemIndexAtPosition, key);
|
|
4023
4212
|
}
|
|
4024
|
-
const { newItem, newIndex } = this
|
|
4213
|
+
const { newItem, newIndex } = this.#createAttachItemAndSort(op, key);
|
|
4025
4214
|
return {
|
|
4026
4215
|
modified: makeUpdate(this, [insertDelta(newIndex, newItem)]),
|
|
4027
4216
|
reverse: []
|
|
@@ -4029,8 +4218,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4029
4218
|
}
|
|
4030
4219
|
}
|
|
4031
4220
|
}
|
|
4032
|
-
|
|
4033
|
-
_applyInsertUndoRedo(op) {
|
|
4221
|
+
#applyInsertUndoRedo(op) {
|
|
4034
4222
|
const { id, parentKey: key } = op;
|
|
4035
4223
|
const child = creationOpToLiveNode(op);
|
|
4036
4224
|
if (this._pool?.getNode(id) !== void 0) {
|
|
@@ -4041,8 +4229,8 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4041
4229
|
const existingItemIndex = this._indexOfPosition(key);
|
|
4042
4230
|
let newKey = key;
|
|
4043
4231
|
if (existingItemIndex !== -1) {
|
|
4044
|
-
const before2 = this
|
|
4045
|
-
const after2 = this
|
|
4232
|
+
const before2 = this.#items[existingItemIndex]?._parentPos;
|
|
4233
|
+
const after2 = this.#items[existingItemIndex + 1]?._parentPos;
|
|
4046
4234
|
newKey = makePosition(before2, after2);
|
|
4047
4235
|
child._setParentLink(this, newKey);
|
|
4048
4236
|
}
|
|
@@ -4053,28 +4241,27 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4053
4241
|
reverse: [{ type: 5 /* DELETE_CRDT */, id }]
|
|
4054
4242
|
};
|
|
4055
4243
|
}
|
|
4056
|
-
|
|
4057
|
-
_applySetUndoRedo(op) {
|
|
4244
|
+
#applySetUndoRedo(op) {
|
|
4058
4245
|
const { id, parentKey: key } = op;
|
|
4059
4246
|
const child = creationOpToLiveNode(op);
|
|
4060
4247
|
if (this._pool?.getNode(id) !== void 0) {
|
|
4061
4248
|
return { modified: false };
|
|
4062
4249
|
}
|
|
4063
|
-
this.
|
|
4250
|
+
this.#unacknowledgedSets.set(key, nn(op.opId));
|
|
4064
4251
|
const indexOfItemWithSameKey = this._indexOfPosition(key);
|
|
4065
4252
|
child._attach(id, nn(this._pool));
|
|
4066
4253
|
child._setParentLink(this, key);
|
|
4067
4254
|
const newKey = key;
|
|
4068
4255
|
if (indexOfItemWithSameKey !== -1) {
|
|
4069
|
-
const existingItem = this
|
|
4256
|
+
const existingItem = this.#items[indexOfItemWithSameKey];
|
|
4070
4257
|
existingItem._detach();
|
|
4071
|
-
this
|
|
4258
|
+
this.#items[indexOfItemWithSameKey] = child;
|
|
4072
4259
|
const reverse = HACK_addIntentAndDeletedIdToOperation(
|
|
4073
4260
|
existingItem._toOps(nn(this._id), key, this._pool),
|
|
4074
4261
|
op.id
|
|
4075
4262
|
);
|
|
4076
4263
|
const delta = [setDelta(indexOfItemWithSameKey, child)];
|
|
4077
|
-
const deletedDelta = this
|
|
4264
|
+
const deletedDelta = this.#detachItemAssociatedToSetOperation(
|
|
4078
4265
|
op.deletedId
|
|
4079
4266
|
);
|
|
4080
4267
|
if (deletedDelta) {
|
|
@@ -4086,7 +4273,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4086
4273
|
};
|
|
4087
4274
|
} else {
|
|
4088
4275
|
this._insertAndSort(child);
|
|
4089
|
-
this
|
|
4276
|
+
this.#detachItemAssociatedToSetOperation(op.deletedId);
|
|
4090
4277
|
const newIndex = this._indexOfPosition(newKey);
|
|
4091
4278
|
return {
|
|
4092
4279
|
reverse: [{ type: 5 /* DELETE_CRDT */, id }],
|
|
@@ -4102,19 +4289,19 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4102
4289
|
let result;
|
|
4103
4290
|
if (op.intent === "set") {
|
|
4104
4291
|
if (source === 1 /* REMOTE */) {
|
|
4105
|
-
result = this
|
|
4292
|
+
result = this.#applySetRemote(op);
|
|
4106
4293
|
} else if (source === 2 /* ACK */) {
|
|
4107
|
-
result = this
|
|
4294
|
+
result = this.#applySetAck(op);
|
|
4108
4295
|
} else {
|
|
4109
|
-
result = this
|
|
4296
|
+
result = this.#applySetUndoRedo(op);
|
|
4110
4297
|
}
|
|
4111
4298
|
} else {
|
|
4112
4299
|
if (source === 1 /* REMOTE */) {
|
|
4113
|
-
result = this
|
|
4300
|
+
result = this.#applyRemoteInsert(op);
|
|
4114
4301
|
} else if (source === 2 /* ACK */) {
|
|
4115
|
-
result = this
|
|
4302
|
+
result = this.#applyInsertAck(op);
|
|
4116
4303
|
} else {
|
|
4117
|
-
result = this
|
|
4304
|
+
result = this.#applyInsertUndoRedo(op);
|
|
4118
4305
|
}
|
|
4119
4306
|
}
|
|
4120
4307
|
if (result.modified !== false) {
|
|
@@ -4127,13 +4314,13 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4127
4314
|
if (child) {
|
|
4128
4315
|
const parentKey = nn(child._parentKey);
|
|
4129
4316
|
const reverse = child._toOps(nn(this._id), parentKey, this._pool);
|
|
4130
|
-
const indexToDelete = this.
|
|
4317
|
+
const indexToDelete = this.#items.indexOf(child);
|
|
4131
4318
|
if (indexToDelete === -1) {
|
|
4132
4319
|
return {
|
|
4133
4320
|
modified: false
|
|
4134
4321
|
};
|
|
4135
4322
|
}
|
|
4136
|
-
const [previousNode] = this.
|
|
4323
|
+
const [previousNode] = this.#items.splice(indexToDelete, 1);
|
|
4137
4324
|
this.invalidate();
|
|
4138
4325
|
child._detach();
|
|
4139
4326
|
return {
|
|
@@ -4143,13 +4330,12 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4143
4330
|
}
|
|
4144
4331
|
return { modified: false };
|
|
4145
4332
|
}
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
this._implicitlyDeletedItems.delete(child);
|
|
4333
|
+
#applySetChildKeyRemote(newKey, child) {
|
|
4334
|
+
if (this.#implicitlyDeletedItems.has(child)) {
|
|
4335
|
+
this.#implicitlyDeletedItems.delete(child);
|
|
4150
4336
|
child._setParentLink(this, newKey);
|
|
4151
4337
|
this._insertAndSort(child);
|
|
4152
|
-
const newIndex = this.
|
|
4338
|
+
const newIndex = this.#items.indexOf(child);
|
|
4153
4339
|
return {
|
|
4154
4340
|
modified: makeUpdate(this, [insertDelta(newIndex, child)]),
|
|
4155
4341
|
reverse: []
|
|
@@ -4163,10 +4349,10 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4163
4349
|
}
|
|
4164
4350
|
const existingItemIndex = this._indexOfPosition(newKey);
|
|
4165
4351
|
if (existingItemIndex === -1) {
|
|
4166
|
-
const previousIndex = this.
|
|
4352
|
+
const previousIndex = this.#items.indexOf(child);
|
|
4167
4353
|
child._setParentLink(this, newKey);
|
|
4168
4354
|
this._sortItems();
|
|
4169
|
-
const newIndex = this.
|
|
4355
|
+
const newIndex = this.#items.indexOf(child);
|
|
4170
4356
|
if (newIndex === previousIndex) {
|
|
4171
4357
|
return {
|
|
4172
4358
|
modified: false
|
|
@@ -4177,14 +4363,14 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4177
4363
|
reverse: []
|
|
4178
4364
|
};
|
|
4179
4365
|
} else {
|
|
4180
|
-
this
|
|
4366
|
+
this.#items[existingItemIndex]._setParentLink(
|
|
4181
4367
|
this,
|
|
4182
|
-
makePosition(newKey, this
|
|
4368
|
+
makePosition(newKey, this.#items[existingItemIndex + 1]?._parentPos)
|
|
4183
4369
|
);
|
|
4184
|
-
const previousIndex = this.
|
|
4370
|
+
const previousIndex = this.#items.indexOf(child);
|
|
4185
4371
|
child._setParentLink(this, newKey);
|
|
4186
4372
|
this._sortItems();
|
|
4187
|
-
const newIndex = this.
|
|
4373
|
+
const newIndex = this.#items.indexOf(child);
|
|
4188
4374
|
if (newIndex === previousIndex) {
|
|
4189
4375
|
return {
|
|
4190
4376
|
modified: false
|
|
@@ -4196,16 +4382,15 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4196
4382
|
};
|
|
4197
4383
|
}
|
|
4198
4384
|
}
|
|
4199
|
-
|
|
4200
|
-
_applySetChildKeyAck(newKey, child) {
|
|
4385
|
+
#applySetChildKeyAck(newKey, child) {
|
|
4201
4386
|
const previousKey = nn(child._parentKey);
|
|
4202
|
-
if (this.
|
|
4387
|
+
if (this.#implicitlyDeletedItems.has(child)) {
|
|
4203
4388
|
const existingItemIndex = this._indexOfPosition(newKey);
|
|
4204
|
-
this.
|
|
4389
|
+
this.#implicitlyDeletedItems.delete(child);
|
|
4205
4390
|
if (existingItemIndex !== -1) {
|
|
4206
|
-
this
|
|
4391
|
+
this.#items[existingItemIndex]._setParentLink(
|
|
4207
4392
|
this,
|
|
4208
|
-
makePosition(newKey, this
|
|
4393
|
+
makePosition(newKey, this.#items[existingItemIndex + 1]?._parentPos)
|
|
4209
4394
|
);
|
|
4210
4395
|
}
|
|
4211
4396
|
child._setParentLink(this, newKey);
|
|
@@ -4219,17 +4404,17 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4219
4404
|
modified: false
|
|
4220
4405
|
};
|
|
4221
4406
|
}
|
|
4222
|
-
const previousIndex = this.
|
|
4407
|
+
const previousIndex = this.#items.indexOf(child);
|
|
4223
4408
|
const existingItemIndex = this._indexOfPosition(newKey);
|
|
4224
4409
|
if (existingItemIndex !== -1) {
|
|
4225
|
-
this
|
|
4410
|
+
this.#items[existingItemIndex]._setParentLink(
|
|
4226
4411
|
this,
|
|
4227
|
-
makePosition(newKey, this
|
|
4412
|
+
makePosition(newKey, this.#items[existingItemIndex + 1]?._parentPos)
|
|
4228
4413
|
);
|
|
4229
4414
|
}
|
|
4230
4415
|
child._setParentLink(this, newKey);
|
|
4231
4416
|
this._sortItems();
|
|
4232
|
-
const newIndex = this.
|
|
4417
|
+
const newIndex = this.#items.indexOf(child);
|
|
4233
4418
|
if (previousIndex === newIndex) {
|
|
4234
4419
|
return {
|
|
4235
4420
|
modified: false
|
|
@@ -4244,20 +4429,19 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4244
4429
|
}
|
|
4245
4430
|
}
|
|
4246
4431
|
}
|
|
4247
|
-
|
|
4248
|
-
_applySetChildKeyUndoRedo(newKey, child) {
|
|
4432
|
+
#applySetChildKeyUndoRedo(newKey, child) {
|
|
4249
4433
|
const previousKey = nn(child._parentKey);
|
|
4250
|
-
const previousIndex = this.
|
|
4434
|
+
const previousIndex = this.#items.indexOf(child);
|
|
4251
4435
|
const existingItemIndex = this._indexOfPosition(newKey);
|
|
4252
4436
|
if (existingItemIndex !== -1) {
|
|
4253
|
-
this
|
|
4437
|
+
this.#items[existingItemIndex]._setParentLink(
|
|
4254
4438
|
this,
|
|
4255
|
-
makePosition(newKey, this
|
|
4439
|
+
makePosition(newKey, this.#items[existingItemIndex + 1]?._parentPos)
|
|
4256
4440
|
);
|
|
4257
4441
|
}
|
|
4258
4442
|
child._setParentLink(this, newKey);
|
|
4259
4443
|
this._sortItems();
|
|
4260
|
-
const newIndex = this.
|
|
4444
|
+
const newIndex = this.#items.indexOf(child);
|
|
4261
4445
|
if (previousIndex === newIndex) {
|
|
4262
4446
|
return {
|
|
4263
4447
|
modified: false
|
|
@@ -4277,11 +4461,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4277
4461
|
/** @internal */
|
|
4278
4462
|
_setChildKey(newKey, child, source) {
|
|
4279
4463
|
if (source === 1 /* REMOTE */) {
|
|
4280
|
-
return this
|
|
4464
|
+
return this.#applySetChildKeyRemote(newKey, child);
|
|
4281
4465
|
} else if (source === 2 /* ACK */) {
|
|
4282
|
-
return this
|
|
4466
|
+
return this.#applySetChildKeyAck(newKey, child);
|
|
4283
4467
|
} else {
|
|
4284
|
-
return this
|
|
4468
|
+
return this.#applySetChildKeyUndoRedo(newKey, child);
|
|
4285
4469
|
}
|
|
4286
4470
|
}
|
|
4287
4471
|
/** @internal */
|
|
@@ -4303,7 +4487,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4303
4487
|
* Returns the number of elements.
|
|
4304
4488
|
*/
|
|
4305
4489
|
get length() {
|
|
4306
|
-
return this.
|
|
4490
|
+
return this.#items.length;
|
|
4307
4491
|
}
|
|
4308
4492
|
/**
|
|
4309
4493
|
* Adds one element to the end of the LiveList.
|
|
@@ -4320,13 +4504,13 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4320
4504
|
*/
|
|
4321
4505
|
insert(element, index) {
|
|
4322
4506
|
this._pool?.assertStorageIsWritable();
|
|
4323
|
-
if (index < 0 || index > this.
|
|
4507
|
+
if (index < 0 || index > this.#items.length) {
|
|
4324
4508
|
throw new Error(
|
|
4325
|
-
`Cannot insert list item at index "${index}". index should be between 0 and ${this.
|
|
4509
|
+
`Cannot insert list item at index "${index}". index should be between 0 and ${this.#items.length}`
|
|
4326
4510
|
);
|
|
4327
4511
|
}
|
|
4328
|
-
const before2 = this
|
|
4329
|
-
const after2 = this
|
|
4512
|
+
const before2 = this.#items[index - 1] ? this.#items[index - 1]._parentPos : void 0;
|
|
4513
|
+
const after2 = this.#items[index] ? this.#items[index]._parentPos : void 0;
|
|
4330
4514
|
const position = makePosition(before2, after2);
|
|
4331
4515
|
const value = lsonToLiveNode(element);
|
|
4332
4516
|
value._setParentLink(this, position);
|
|
@@ -4353,7 +4537,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4353
4537
|
if (targetIndex < 0) {
|
|
4354
4538
|
throw new Error("targetIndex cannot be less than 0");
|
|
4355
4539
|
}
|
|
4356
|
-
if (targetIndex >= this.
|
|
4540
|
+
if (targetIndex >= this.#items.length) {
|
|
4357
4541
|
throw new Error(
|
|
4358
4542
|
"targetIndex cannot be greater or equal than the list length"
|
|
4359
4543
|
);
|
|
@@ -4361,20 +4545,20 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4361
4545
|
if (index < 0) {
|
|
4362
4546
|
throw new Error("index cannot be less than 0");
|
|
4363
4547
|
}
|
|
4364
|
-
if (index >= this.
|
|
4548
|
+
if (index >= this.#items.length) {
|
|
4365
4549
|
throw new Error("index cannot be greater or equal than the list length");
|
|
4366
4550
|
}
|
|
4367
4551
|
let beforePosition = null;
|
|
4368
4552
|
let afterPosition = null;
|
|
4369
4553
|
if (index < targetIndex) {
|
|
4370
|
-
afterPosition = targetIndex === this.
|
|
4371
|
-
beforePosition = this
|
|
4554
|
+
afterPosition = targetIndex === this.#items.length - 1 ? void 0 : this.#items[targetIndex + 1]._parentPos;
|
|
4555
|
+
beforePosition = this.#items[targetIndex]._parentPos;
|
|
4372
4556
|
} else {
|
|
4373
|
-
afterPosition = this
|
|
4374
|
-
beforePosition = targetIndex === 0 ? void 0 : this
|
|
4557
|
+
afterPosition = this.#items[targetIndex]._parentPos;
|
|
4558
|
+
beforePosition = targetIndex === 0 ? void 0 : this.#items[targetIndex - 1]._parentPos;
|
|
4375
4559
|
}
|
|
4376
4560
|
const position = makePosition(beforePosition, afterPosition);
|
|
4377
|
-
const item = this
|
|
4561
|
+
const item = this.#items[index];
|
|
4378
4562
|
const previousPosition = item._getParentKeyOrThrow();
|
|
4379
4563
|
item._setParentLink(this, position);
|
|
4380
4564
|
this._sortItems();
|
|
@@ -4408,14 +4592,14 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4408
4592
|
*/
|
|
4409
4593
|
delete(index) {
|
|
4410
4594
|
this._pool?.assertStorageIsWritable();
|
|
4411
|
-
if (index < 0 || index >= this.
|
|
4595
|
+
if (index < 0 || index >= this.#items.length) {
|
|
4412
4596
|
throw new Error(
|
|
4413
|
-
`Cannot delete list item at index "${index}". index should be between 0 and ${this.
|
|
4597
|
+
`Cannot delete list item at index "${index}". index should be between 0 and ${this.#items.length - 1}`
|
|
4414
4598
|
);
|
|
4415
4599
|
}
|
|
4416
|
-
const item = this
|
|
4600
|
+
const item = this.#items[index];
|
|
4417
4601
|
item._detach();
|
|
4418
|
-
const [prev] = this.
|
|
4602
|
+
const [prev] = this.#items.splice(index, 1);
|
|
4419
4603
|
this.invalidate();
|
|
4420
4604
|
if (this._pool) {
|
|
4421
4605
|
const childRecordId = item._id;
|
|
@@ -4445,7 +4629,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4445
4629
|
const ops = [];
|
|
4446
4630
|
const reverseOps = [];
|
|
4447
4631
|
const updateDelta = [];
|
|
4448
|
-
for (const item of this
|
|
4632
|
+
for (const item of this.#items) {
|
|
4449
4633
|
item._detach();
|
|
4450
4634
|
const childId = item._id;
|
|
4451
4635
|
if (childId) {
|
|
@@ -4460,33 +4644,33 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4460
4644
|
updateDelta.push(deleteDelta(0, item));
|
|
4461
4645
|
}
|
|
4462
4646
|
}
|
|
4463
|
-
this
|
|
4647
|
+
this.#items = [];
|
|
4464
4648
|
this.invalidate();
|
|
4465
4649
|
const storageUpdates = /* @__PURE__ */ new Map();
|
|
4466
4650
|
storageUpdates.set(nn(this._id), makeUpdate(this, updateDelta));
|
|
4467
4651
|
this._pool.dispatch(ops, reverseOps, storageUpdates);
|
|
4468
4652
|
} else {
|
|
4469
|
-
for (const item of this
|
|
4653
|
+
for (const item of this.#items) {
|
|
4470
4654
|
item._detach();
|
|
4471
4655
|
}
|
|
4472
|
-
this
|
|
4656
|
+
this.#items = [];
|
|
4473
4657
|
this.invalidate();
|
|
4474
4658
|
}
|
|
4475
4659
|
}
|
|
4476
4660
|
set(index, item) {
|
|
4477
4661
|
this._pool?.assertStorageIsWritable();
|
|
4478
|
-
if (index < 0 || index >= this.
|
|
4662
|
+
if (index < 0 || index >= this.#items.length) {
|
|
4479
4663
|
throw new Error(
|
|
4480
|
-
`Cannot set list item at index "${index}". index should be between 0 and ${this.
|
|
4664
|
+
`Cannot set list item at index "${index}". index should be between 0 and ${this.#items.length - 1}`
|
|
4481
4665
|
);
|
|
4482
4666
|
}
|
|
4483
|
-
const existingItem = this
|
|
4667
|
+
const existingItem = this.#items[index];
|
|
4484
4668
|
const position = existingItem._getParentKeyOrThrow();
|
|
4485
4669
|
const existingId = existingItem._id;
|
|
4486
4670
|
existingItem._detach();
|
|
4487
4671
|
const value = lsonToLiveNode(item);
|
|
4488
4672
|
value._setParentLink(this, position);
|
|
4489
|
-
this
|
|
4673
|
+
this.#items[index] = value;
|
|
4490
4674
|
this.invalidate();
|
|
4491
4675
|
if (this._pool && this._id) {
|
|
4492
4676
|
const id = this._pool.generateId();
|
|
@@ -4497,7 +4681,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4497
4681
|
value._toOps(this._id, position, this._pool),
|
|
4498
4682
|
existingId
|
|
4499
4683
|
);
|
|
4500
|
-
this.
|
|
4684
|
+
this.#unacknowledgedSets.set(position, nn(ops[0].opId));
|
|
4501
4685
|
const reverseOps = HACK_addIntentAndDeletedIdToOperation(
|
|
4502
4686
|
existingItem._toOps(this._id, position, void 0),
|
|
4503
4687
|
id
|
|
@@ -4509,7 +4693,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4509
4693
|
* Returns an Array of all the elements in the LiveList.
|
|
4510
4694
|
*/
|
|
4511
4695
|
toArray() {
|
|
4512
|
-
return this.
|
|
4696
|
+
return this.#items.map(
|
|
4513
4697
|
(entry) => liveNodeToLson(entry)
|
|
4514
4698
|
// ^^^^^^^^
|
|
4515
4699
|
// FIXME! This isn't safe.
|
|
@@ -4560,10 +4744,10 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4560
4744
|
* @returns The element at the specified index or undefined.
|
|
4561
4745
|
*/
|
|
4562
4746
|
get(index) {
|
|
4563
|
-
if (index < 0 || index >= this.
|
|
4747
|
+
if (index < 0 || index >= this.#items.length) {
|
|
4564
4748
|
return void 0;
|
|
4565
4749
|
}
|
|
4566
|
-
return liveNodeToLson(this
|
|
4750
|
+
return liveNodeToLson(this.#items[index]);
|
|
4567
4751
|
}
|
|
4568
4752
|
/**
|
|
4569
4753
|
* Returns the first index at which a given element can be found in the LiveList, or -1 if it is not present.
|
|
@@ -4589,7 +4773,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4589
4773
|
* @returns An array with each element being the result of the callback function.
|
|
4590
4774
|
*/
|
|
4591
4775
|
map(callback) {
|
|
4592
|
-
return this.
|
|
4776
|
+
return this.#items.map(
|
|
4593
4777
|
(entry, i) => callback(
|
|
4594
4778
|
liveNodeToLson(entry),
|
|
4595
4779
|
// ^^^^^^^^
|
|
@@ -4607,10 +4791,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4607
4791
|
return this.toArray().some(predicate);
|
|
4608
4792
|
}
|
|
4609
4793
|
[Symbol.iterator]() {
|
|
4610
|
-
return new LiveListIterator(this
|
|
4794
|
+
return new LiveListIterator(this.#items);
|
|
4611
4795
|
}
|
|
4612
|
-
|
|
4613
|
-
_createAttachItemAndSort(op, key) {
|
|
4796
|
+
#createAttachItemAndSort(op, key) {
|
|
4614
4797
|
const newItem = creationOpToLiveNode(op);
|
|
4615
4798
|
newItem._attach(op.id, nn(this._pool));
|
|
4616
4799
|
newItem._setParentLink(this, key);
|
|
@@ -4618,13 +4801,12 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4618
4801
|
const newIndex = this._indexOfPosition(key);
|
|
4619
4802
|
return { newItem, newIndex };
|
|
4620
4803
|
}
|
|
4621
|
-
|
|
4622
|
-
_shiftItemPosition(index, key) {
|
|
4804
|
+
#shiftItemPosition(index, key) {
|
|
4623
4805
|
const shiftedPosition = makePosition(
|
|
4624
4806
|
key,
|
|
4625
|
-
this.
|
|
4807
|
+
this.#items.length > index + 1 ? this.#items[index + 1]?._parentPos : void 0
|
|
4626
4808
|
);
|
|
4627
|
-
this
|
|
4809
|
+
this.#items[index]._setParentLink(this, shiftedPosition);
|
|
4628
4810
|
}
|
|
4629
4811
|
/** @internal */
|
|
4630
4812
|
_toTreeNode(key) {
|
|
@@ -4632,7 +4814,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4632
4814
|
type: "LiveList",
|
|
4633
4815
|
id: this._id ?? nanoid(),
|
|
4634
4816
|
key,
|
|
4635
|
-
payload: this.
|
|
4817
|
+
payload: this.#items.map(
|
|
4636
4818
|
(item, index) => item.toTreeNode(index.toString())
|
|
4637
4819
|
)
|
|
4638
4820
|
};
|
|
@@ -4642,22 +4824,23 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4642
4824
|
}
|
|
4643
4825
|
/** @internal */
|
|
4644
4826
|
_toImmutable() {
|
|
4645
|
-
const result = this.
|
|
4827
|
+
const result = this.#items.map((node) => node.toImmutable());
|
|
4646
4828
|
return process.env.NODE_ENV === "production" ? result : Object.freeze(result);
|
|
4647
4829
|
}
|
|
4648
4830
|
clone() {
|
|
4649
|
-
return new _LiveList(this.
|
|
4831
|
+
return new _LiveList(this.#items.map((item) => item.clone()));
|
|
4650
4832
|
}
|
|
4651
4833
|
};
|
|
4652
4834
|
var LiveListIterator = class {
|
|
4835
|
+
#innerIterator;
|
|
4653
4836
|
constructor(items) {
|
|
4654
|
-
this
|
|
4837
|
+
this.#innerIterator = items[Symbol.iterator]();
|
|
4655
4838
|
}
|
|
4656
4839
|
[Symbol.iterator]() {
|
|
4657
4840
|
return this;
|
|
4658
4841
|
}
|
|
4659
4842
|
next() {
|
|
4660
|
-
const result = this.
|
|
4843
|
+
const result = this.#innerIterator.next();
|
|
4661
4844
|
if (result.done) {
|
|
4662
4845
|
return {
|
|
4663
4846
|
done: true,
|
|
@@ -4721,9 +4904,11 @@ function HACK_addIntentAndDeletedIdToOperation(ops, deletedId) {
|
|
|
4721
4904
|
|
|
4722
4905
|
// src/crdts/LiveMap.ts
|
|
4723
4906
|
var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
4907
|
+
#map;
|
|
4908
|
+
#unacknowledgedSet;
|
|
4724
4909
|
constructor(entries2) {
|
|
4725
4910
|
super();
|
|
4726
|
-
this
|
|
4911
|
+
this.#unacknowledgedSet = /* @__PURE__ */ new Map();
|
|
4727
4912
|
if (entries2) {
|
|
4728
4913
|
const mappedEntries = [];
|
|
4729
4914
|
for (const [key, value] of entries2) {
|
|
@@ -4731,14 +4916,12 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4731
4916
|
node._setParentLink(this, key);
|
|
4732
4917
|
mappedEntries.push([key, node]);
|
|
4733
4918
|
}
|
|
4734
|
-
this
|
|
4919
|
+
this.#map = new Map(mappedEntries);
|
|
4735
4920
|
} else {
|
|
4736
|
-
this
|
|
4921
|
+
this.#map = /* @__PURE__ */ new Map();
|
|
4737
4922
|
}
|
|
4738
4923
|
}
|
|
4739
|
-
/**
|
|
4740
|
-
* @internal
|
|
4741
|
-
*/
|
|
4924
|
+
/** @internal */
|
|
4742
4925
|
_toOps(parentId, parentKey, pool) {
|
|
4743
4926
|
if (this._id === void 0) {
|
|
4744
4927
|
throw new Error("Cannot serialize item is not attached");
|
|
@@ -4752,14 +4935,12 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4752
4935
|
parentKey
|
|
4753
4936
|
};
|
|
4754
4937
|
ops.push(op);
|
|
4755
|
-
for (const [key, value] of this
|
|
4938
|
+
for (const [key, value] of this.#map) {
|
|
4756
4939
|
ops.push(...value._toOps(this._id, key, pool));
|
|
4757
4940
|
}
|
|
4758
4941
|
return ops;
|
|
4759
4942
|
}
|
|
4760
|
-
/**
|
|
4761
|
-
* @internal
|
|
4762
|
-
*/
|
|
4943
|
+
/** @internal */
|
|
4763
4944
|
static _deserialize([id, _item], parentToChildren, pool) {
|
|
4764
4945
|
const map = new _LiveMap();
|
|
4765
4946
|
map._attach(id, pool);
|
|
@@ -4770,25 +4951,21 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4770
4951
|
for (const [id2, crdt] of children) {
|
|
4771
4952
|
const child = deserialize([id2, crdt], parentToChildren, pool);
|
|
4772
4953
|
child._setParentLink(map, crdt.parentKey);
|
|
4773
|
-
map.
|
|
4954
|
+
map.#map.set(crdt.parentKey, child);
|
|
4774
4955
|
map.invalidate();
|
|
4775
4956
|
}
|
|
4776
4957
|
return map;
|
|
4777
4958
|
}
|
|
4778
|
-
/**
|
|
4779
|
-
* @internal
|
|
4780
|
-
*/
|
|
4959
|
+
/** @internal */
|
|
4781
4960
|
_attach(id, pool) {
|
|
4782
4961
|
super._attach(id, pool);
|
|
4783
|
-
for (const [_key, value] of this
|
|
4962
|
+
for (const [_key, value] of this.#map) {
|
|
4784
4963
|
if (isLiveNode(value)) {
|
|
4785
4964
|
value._attach(pool.generateId(), pool);
|
|
4786
4965
|
}
|
|
4787
4966
|
}
|
|
4788
4967
|
}
|
|
4789
|
-
/**
|
|
4790
|
-
* @internal
|
|
4791
|
-
*/
|
|
4968
|
+
/** @internal */
|
|
4792
4969
|
_attachChild(op, source) {
|
|
4793
4970
|
if (this._pool === void 0) {
|
|
4794
4971
|
throw new Error("Can't attach child if managed pool is not present");
|
|
@@ -4800,17 +4977,17 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4800
4977
|
return { modified: false };
|
|
4801
4978
|
}
|
|
4802
4979
|
if (source === 2 /* ACK */) {
|
|
4803
|
-
const lastUpdateOpId = this
|
|
4980
|
+
const lastUpdateOpId = this.#unacknowledgedSet.get(key);
|
|
4804
4981
|
if (lastUpdateOpId === opId) {
|
|
4805
|
-
this
|
|
4982
|
+
this.#unacknowledgedSet.delete(key);
|
|
4806
4983
|
return { modified: false };
|
|
4807
4984
|
} else if (lastUpdateOpId !== void 0) {
|
|
4808
4985
|
return { modified: false };
|
|
4809
4986
|
}
|
|
4810
4987
|
} else if (source === 1 /* REMOTE */) {
|
|
4811
|
-
this
|
|
4988
|
+
this.#unacknowledgedSet.delete(key);
|
|
4812
4989
|
}
|
|
4813
|
-
const previousValue = this.
|
|
4990
|
+
const previousValue = this.#map.get(key);
|
|
4814
4991
|
let reverse;
|
|
4815
4992
|
if (previousValue) {
|
|
4816
4993
|
const thisId = nn(this._id);
|
|
@@ -4821,7 +4998,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4821
4998
|
}
|
|
4822
4999
|
child._setParentLink(this, key);
|
|
4823
5000
|
child._attach(id, this._pool);
|
|
4824
|
-
this.
|
|
5001
|
+
this.#map.set(key, child);
|
|
4825
5002
|
this.invalidate();
|
|
4826
5003
|
return {
|
|
4827
5004
|
modified: {
|
|
@@ -4832,25 +5009,21 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4832
5009
|
reverse
|
|
4833
5010
|
};
|
|
4834
5011
|
}
|
|
4835
|
-
/**
|
|
4836
|
-
* @internal
|
|
4837
|
-
*/
|
|
5012
|
+
/** @internal */
|
|
4838
5013
|
_detach() {
|
|
4839
5014
|
super._detach();
|
|
4840
|
-
for (const item of this.
|
|
5015
|
+
for (const item of this.#map.values()) {
|
|
4841
5016
|
item._detach();
|
|
4842
5017
|
}
|
|
4843
5018
|
}
|
|
4844
|
-
/**
|
|
4845
|
-
* @internal
|
|
4846
|
-
*/
|
|
5019
|
+
/** @internal */
|
|
4847
5020
|
_detachChild(child) {
|
|
4848
5021
|
const id = nn(this._id);
|
|
4849
5022
|
const parentKey = nn(child._parentKey);
|
|
4850
5023
|
const reverse = child._toOps(id, parentKey, this._pool);
|
|
4851
|
-
for (const [key, value] of this
|
|
5024
|
+
for (const [key, value] of this.#map) {
|
|
4852
5025
|
if (value === child) {
|
|
4853
|
-
this.
|
|
5026
|
+
this.#map.delete(key);
|
|
4854
5027
|
this.invalidate();
|
|
4855
5028
|
}
|
|
4856
5029
|
}
|
|
@@ -4862,9 +5035,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4862
5035
|
};
|
|
4863
5036
|
return { modified: storageUpdate, reverse };
|
|
4864
5037
|
}
|
|
4865
|
-
/**
|
|
4866
|
-
* @internal
|
|
4867
|
-
*/
|
|
5038
|
+
/** @internal */
|
|
4868
5039
|
_serialize() {
|
|
4869
5040
|
if (this.parent.type !== "HasParent") {
|
|
4870
5041
|
throw new Error("Cannot serialize LiveMap if parent is missing");
|
|
@@ -4881,7 +5052,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4881
5052
|
* @returns The element associated with the specified key, or undefined if the key can't be found in the LiveMap.
|
|
4882
5053
|
*/
|
|
4883
5054
|
get(key) {
|
|
4884
|
-
const value = this.
|
|
5055
|
+
const value = this.#map.get(key);
|
|
4885
5056
|
if (value === void 0) {
|
|
4886
5057
|
return void 0;
|
|
4887
5058
|
}
|
|
@@ -4894,13 +5065,13 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4894
5065
|
*/
|
|
4895
5066
|
set(key, value) {
|
|
4896
5067
|
this._pool?.assertStorageIsWritable();
|
|
4897
|
-
const oldValue = this.
|
|
5068
|
+
const oldValue = this.#map.get(key);
|
|
4898
5069
|
if (oldValue) {
|
|
4899
5070
|
oldValue._detach();
|
|
4900
5071
|
}
|
|
4901
5072
|
const item = lsonToLiveNode(value);
|
|
4902
5073
|
item._setParentLink(this, key);
|
|
4903
|
-
this.
|
|
5074
|
+
this.#map.set(key, item);
|
|
4904
5075
|
this.invalidate();
|
|
4905
5076
|
if (this._pool && this._id) {
|
|
4906
5077
|
const id = this._pool.generateId();
|
|
@@ -4912,7 +5083,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4912
5083
|
updates: { [key]: { type: "update" } }
|
|
4913
5084
|
});
|
|
4914
5085
|
const ops = item._toOps(this._id, key, this._pool);
|
|
4915
|
-
this
|
|
5086
|
+
this.#unacknowledgedSet.set(key, nn(ops[0].opId));
|
|
4916
5087
|
this._pool.dispatch(
|
|
4917
5088
|
item._toOps(this._id, key, this._pool),
|
|
4918
5089
|
oldValue ? oldValue._toOps(this._id, key) : [{ type: 5 /* DELETE_CRDT */, id }],
|
|
@@ -4924,14 +5095,14 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4924
5095
|
* Returns the number of elements in the LiveMap.
|
|
4925
5096
|
*/
|
|
4926
5097
|
get size() {
|
|
4927
|
-
return this.
|
|
5098
|
+
return this.#map.size;
|
|
4928
5099
|
}
|
|
4929
5100
|
/**
|
|
4930
5101
|
* Returns a boolean indicating whether an element with the specified key exists or not.
|
|
4931
5102
|
* @param key The key of the element to test for presence.
|
|
4932
5103
|
*/
|
|
4933
5104
|
has(key) {
|
|
4934
|
-
return this.
|
|
5105
|
+
return this.#map.has(key);
|
|
4935
5106
|
}
|
|
4936
5107
|
/**
|
|
4937
5108
|
* Removes the specified element by key.
|
|
@@ -4940,12 +5111,12 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4940
5111
|
*/
|
|
4941
5112
|
delete(key) {
|
|
4942
5113
|
this._pool?.assertStorageIsWritable();
|
|
4943
|
-
const item = this.
|
|
5114
|
+
const item = this.#map.get(key);
|
|
4944
5115
|
if (item === void 0) {
|
|
4945
5116
|
return false;
|
|
4946
5117
|
}
|
|
4947
5118
|
item._detach();
|
|
4948
|
-
this.
|
|
5119
|
+
this.#map.delete(key);
|
|
4949
5120
|
this.invalidate();
|
|
4950
5121
|
if (this._pool && item._id) {
|
|
4951
5122
|
const thisId = nn(this._id);
|
|
@@ -4973,7 +5144,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4973
5144
|
* Returns a new Iterator object that contains the [key, value] pairs for each element.
|
|
4974
5145
|
*/
|
|
4975
5146
|
entries() {
|
|
4976
|
-
const innerIterator = this.
|
|
5147
|
+
const innerIterator = this.#map.entries();
|
|
4977
5148
|
return {
|
|
4978
5149
|
[Symbol.iterator]() {
|
|
4979
5150
|
return this;
|
|
@@ -5005,13 +5176,13 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
5005
5176
|
* Returns a new Iterator object that contains the keys for each element.
|
|
5006
5177
|
*/
|
|
5007
5178
|
keys() {
|
|
5008
|
-
return this.
|
|
5179
|
+
return this.#map.keys();
|
|
5009
5180
|
}
|
|
5010
5181
|
/**
|
|
5011
5182
|
* Returns a new Iterator object that contains the values for each element.
|
|
5012
5183
|
*/
|
|
5013
5184
|
values() {
|
|
5014
|
-
const innerIterator = this.
|
|
5185
|
+
const innerIterator = this.#map.values();
|
|
5015
5186
|
return {
|
|
5016
5187
|
[Symbol.iterator]() {
|
|
5017
5188
|
return this;
|
|
@@ -5044,7 +5215,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
5044
5215
|
type: "LiveMap",
|
|
5045
5216
|
id: this._id ?? nanoid(),
|
|
5046
5217
|
key,
|
|
5047
|
-
payload: Array.from(this.
|
|
5218
|
+
payload: Array.from(this.#map.entries()).map(
|
|
5048
5219
|
([key2, val]) => val.toTreeNode(key2)
|
|
5049
5220
|
)
|
|
5050
5221
|
};
|
|
@@ -5055,22 +5226,23 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
5055
5226
|
/** @internal */
|
|
5056
5227
|
_toImmutable() {
|
|
5057
5228
|
const result = /* @__PURE__ */ new Map();
|
|
5058
|
-
for (const [key, value] of this
|
|
5229
|
+
for (const [key, value] of this.#map) {
|
|
5059
5230
|
result.set(key, value.toImmutable());
|
|
5060
5231
|
}
|
|
5061
5232
|
return freeze(result);
|
|
5062
5233
|
}
|
|
5063
5234
|
clone() {
|
|
5064
5235
|
return new _LiveMap(
|
|
5065
|
-
Array.from(this
|
|
5236
|
+
Array.from(this.#map).map(([key, node]) => [key, node.clone()])
|
|
5066
5237
|
);
|
|
5067
5238
|
}
|
|
5068
5239
|
};
|
|
5069
5240
|
|
|
5070
5241
|
// src/crdts/LiveObject.ts
|
|
5071
5242
|
var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
5072
|
-
|
|
5073
|
-
|
|
5243
|
+
#map;
|
|
5244
|
+
#propToLastUpdate;
|
|
5245
|
+
static #buildRootAndParentToChildren(items) {
|
|
5074
5246
|
const parentToChildren = /* @__PURE__ */ new Map();
|
|
5075
5247
|
let root = null;
|
|
5076
5248
|
for (const [id, crdt] of items) {
|
|
@@ -5093,7 +5265,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5093
5265
|
}
|
|
5094
5266
|
/** @internal */
|
|
5095
5267
|
static _fromItems(items, pool) {
|
|
5096
|
-
const [root, parentToChildren] = _LiveObject
|
|
5268
|
+
const [root, parentToChildren] = _LiveObject.#buildRootAndParentToChildren(items);
|
|
5097
5269
|
return _LiveObject._deserialize(
|
|
5098
5270
|
root,
|
|
5099
5271
|
parentToChildren,
|
|
@@ -5102,7 +5274,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5102
5274
|
}
|
|
5103
5275
|
constructor(obj = {}) {
|
|
5104
5276
|
super();
|
|
5105
|
-
this
|
|
5277
|
+
this.#propToLastUpdate = /* @__PURE__ */ new Map();
|
|
5106
5278
|
const o = compactObject(obj);
|
|
5107
5279
|
for (const key of Object.keys(o)) {
|
|
5108
5280
|
const value = o[key];
|
|
@@ -5110,7 +5282,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5110
5282
|
value._setParentLink(this, key);
|
|
5111
5283
|
}
|
|
5112
5284
|
}
|
|
5113
|
-
this
|
|
5285
|
+
this.#map = new Map(Object.entries(o));
|
|
5114
5286
|
}
|
|
5115
5287
|
/** @internal */
|
|
5116
5288
|
_toOps(parentId, parentKey, pool) {
|
|
@@ -5128,7 +5300,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5128
5300
|
data: {}
|
|
5129
5301
|
};
|
|
5130
5302
|
ops.push(op);
|
|
5131
|
-
for (const [key, value] of this
|
|
5303
|
+
for (const [key, value] of this.#map) {
|
|
5132
5304
|
if (isLiveNode(value)) {
|
|
5133
5305
|
ops.push(...value._toOps(this._id, key, pool));
|
|
5134
5306
|
} else {
|
|
@@ -5154,7 +5326,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5154
5326
|
if (isLiveStructure(child)) {
|
|
5155
5327
|
child._setParentLink(liveObj, crdt.parentKey);
|
|
5156
5328
|
}
|
|
5157
|
-
liveObj.
|
|
5329
|
+
liveObj.#map.set(crdt.parentKey, child);
|
|
5158
5330
|
liveObj.invalidate();
|
|
5159
5331
|
}
|
|
5160
5332
|
return liveObj;
|
|
@@ -5162,7 +5334,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5162
5334
|
/** @internal */
|
|
5163
5335
|
_attach(id, pool) {
|
|
5164
5336
|
super._attach(id, pool);
|
|
5165
|
-
for (const [_key, value] of this
|
|
5337
|
+
for (const [_key, value] of this.#map) {
|
|
5166
5338
|
if (isLiveNode(value)) {
|
|
5167
5339
|
value._attach(pool.generateId(), pool);
|
|
5168
5340
|
}
|
|
@@ -5176,22 +5348,22 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5176
5348
|
const { id, opId, parentKey: key } = op;
|
|
5177
5349
|
const child = creationOpToLson(op);
|
|
5178
5350
|
if (this._pool.getNode(id) !== void 0) {
|
|
5179
|
-
if (this.
|
|
5180
|
-
this.
|
|
5351
|
+
if (this.#propToLastUpdate.get(key) === opId) {
|
|
5352
|
+
this.#propToLastUpdate.delete(key);
|
|
5181
5353
|
}
|
|
5182
5354
|
return { modified: false };
|
|
5183
5355
|
}
|
|
5184
5356
|
if (source === 0 /* UNDOREDO_RECONNECT */) {
|
|
5185
|
-
this.
|
|
5186
|
-
} else if (this.
|
|
5187
|
-
} else if (this.
|
|
5188
|
-
this.
|
|
5357
|
+
this.#propToLastUpdate.set(key, nn(opId));
|
|
5358
|
+
} else if (this.#propToLastUpdate.get(key) === void 0) {
|
|
5359
|
+
} else if (this.#propToLastUpdate.get(key) === opId) {
|
|
5360
|
+
this.#propToLastUpdate.delete(key);
|
|
5189
5361
|
return { modified: false };
|
|
5190
5362
|
} else {
|
|
5191
5363
|
return { modified: false };
|
|
5192
5364
|
}
|
|
5193
5365
|
const thisId = nn(this._id);
|
|
5194
|
-
const previousValue = this.
|
|
5366
|
+
const previousValue = this.#map.get(key);
|
|
5195
5367
|
let reverse;
|
|
5196
5368
|
if (isLiveNode(previousValue)) {
|
|
5197
5369
|
reverse = previousValue._toOps(thisId, key);
|
|
@@ -5207,7 +5379,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5207
5379
|
}
|
|
5208
5380
|
];
|
|
5209
5381
|
}
|
|
5210
|
-
this.
|
|
5382
|
+
this.#map.set(key, child);
|
|
5211
5383
|
this.invalidate();
|
|
5212
5384
|
if (isLiveStructure(child)) {
|
|
5213
5385
|
child._setParentLink(this, key);
|
|
@@ -5228,9 +5400,9 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5228
5400
|
const id = nn(this._id);
|
|
5229
5401
|
const parentKey = nn(child._parentKey);
|
|
5230
5402
|
const reverse = child._toOps(id, parentKey, this._pool);
|
|
5231
|
-
for (const [key, value] of this
|
|
5403
|
+
for (const [key, value] of this.#map) {
|
|
5232
5404
|
if (value === child) {
|
|
5233
|
-
this.
|
|
5405
|
+
this.#map.delete(key);
|
|
5234
5406
|
this.invalidate();
|
|
5235
5407
|
}
|
|
5236
5408
|
}
|
|
@@ -5246,12 +5418,10 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5246
5418
|
}
|
|
5247
5419
|
return { modified: false };
|
|
5248
5420
|
}
|
|
5249
|
-
/**
|
|
5250
|
-
* @internal
|
|
5251
|
-
*/
|
|
5421
|
+
/** @internal */
|
|
5252
5422
|
_detach() {
|
|
5253
5423
|
super._detach();
|
|
5254
|
-
for (const value of this.
|
|
5424
|
+
for (const value of this.#map.values()) {
|
|
5255
5425
|
if (isLiveNode(value)) {
|
|
5256
5426
|
value._detach();
|
|
5257
5427
|
}
|
|
@@ -5260,18 +5430,16 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5260
5430
|
/** @internal */
|
|
5261
5431
|
_apply(op, isLocal) {
|
|
5262
5432
|
if (op.type === 3 /* UPDATE_OBJECT */) {
|
|
5263
|
-
return this
|
|
5433
|
+
return this.#applyUpdate(op, isLocal);
|
|
5264
5434
|
} else if (op.type === 6 /* DELETE_OBJECT_KEY */) {
|
|
5265
|
-
return this
|
|
5435
|
+
return this.#applyDeleteObjectKey(op, isLocal);
|
|
5266
5436
|
}
|
|
5267
5437
|
return super._apply(op, isLocal);
|
|
5268
5438
|
}
|
|
5269
|
-
/**
|
|
5270
|
-
* @internal
|
|
5271
|
-
*/
|
|
5439
|
+
/** @internal */
|
|
5272
5440
|
_serialize() {
|
|
5273
5441
|
const data = {};
|
|
5274
|
-
for (const [key, value] of this
|
|
5442
|
+
for (const [key, value] of this.#map) {
|
|
5275
5443
|
if (!isLiveNode(value)) {
|
|
5276
5444
|
data[key] = value;
|
|
5277
5445
|
}
|
|
@@ -5290,8 +5458,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5290
5458
|
};
|
|
5291
5459
|
}
|
|
5292
5460
|
}
|
|
5293
|
-
|
|
5294
|
-
_applyUpdate(op, isLocal) {
|
|
5461
|
+
#applyUpdate(op, isLocal) {
|
|
5295
5462
|
let isModified = false;
|
|
5296
5463
|
const id = nn(this._id);
|
|
5297
5464
|
const reverse = [];
|
|
@@ -5301,7 +5468,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5301
5468
|
data: {}
|
|
5302
5469
|
};
|
|
5303
5470
|
for (const key in op.data) {
|
|
5304
|
-
const oldValue = this.
|
|
5471
|
+
const oldValue = this.#map.get(key);
|
|
5305
5472
|
if (isLiveNode(oldValue)) {
|
|
5306
5473
|
reverse.push(...oldValue._toOps(id, key));
|
|
5307
5474
|
oldValue._detach();
|
|
@@ -5318,22 +5485,22 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5318
5485
|
continue;
|
|
5319
5486
|
}
|
|
5320
5487
|
if (isLocal) {
|
|
5321
|
-
this.
|
|
5322
|
-
} else if (this.
|
|
5488
|
+
this.#propToLastUpdate.set(key, nn(op.opId));
|
|
5489
|
+
} else if (this.#propToLastUpdate.get(key) === void 0) {
|
|
5323
5490
|
isModified = true;
|
|
5324
|
-
} else if (this.
|
|
5325
|
-
this.
|
|
5491
|
+
} else if (this.#propToLastUpdate.get(key) === op.opId) {
|
|
5492
|
+
this.#propToLastUpdate.delete(key);
|
|
5326
5493
|
continue;
|
|
5327
5494
|
} else {
|
|
5328
5495
|
continue;
|
|
5329
5496
|
}
|
|
5330
|
-
const oldValue = this.
|
|
5497
|
+
const oldValue = this.#map.get(key);
|
|
5331
5498
|
if (isLiveNode(oldValue)) {
|
|
5332
5499
|
oldValue._detach();
|
|
5333
5500
|
}
|
|
5334
5501
|
isModified = true;
|
|
5335
5502
|
updateDelta[key] = { type: "update" };
|
|
5336
|
-
this.
|
|
5503
|
+
this.#map.set(key, value);
|
|
5337
5504
|
this.invalidate();
|
|
5338
5505
|
}
|
|
5339
5506
|
if (Object.keys(reverseUpdate.data).length !== 0) {
|
|
@@ -5348,16 +5515,15 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5348
5515
|
reverse
|
|
5349
5516
|
} : { modified: false };
|
|
5350
5517
|
}
|
|
5351
|
-
|
|
5352
|
-
_applyDeleteObjectKey(op, isLocal) {
|
|
5518
|
+
#applyDeleteObjectKey(op, isLocal) {
|
|
5353
5519
|
const key = op.key;
|
|
5354
|
-
if (this.
|
|
5520
|
+
if (this.#map.has(key) === false) {
|
|
5355
5521
|
return { modified: false };
|
|
5356
5522
|
}
|
|
5357
|
-
if (!isLocal && this.
|
|
5523
|
+
if (!isLocal && this.#propToLastUpdate.get(key) !== void 0) {
|
|
5358
5524
|
return { modified: false };
|
|
5359
5525
|
}
|
|
5360
|
-
const oldValue = this.
|
|
5526
|
+
const oldValue = this.#map.get(key);
|
|
5361
5527
|
const id = nn(this._id);
|
|
5362
5528
|
let reverse = [];
|
|
5363
5529
|
if (isLiveNode(oldValue)) {
|
|
@@ -5372,7 +5538,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5372
5538
|
}
|
|
5373
5539
|
];
|
|
5374
5540
|
}
|
|
5375
|
-
this.
|
|
5541
|
+
this.#map.delete(key);
|
|
5376
5542
|
this.invalidate();
|
|
5377
5543
|
return {
|
|
5378
5544
|
modified: {
|
|
@@ -5387,7 +5553,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5387
5553
|
* Transform the LiveObject into a javascript object
|
|
5388
5554
|
*/
|
|
5389
5555
|
toObject() {
|
|
5390
|
-
return Object.fromEntries(this
|
|
5556
|
+
return Object.fromEntries(this.#map);
|
|
5391
5557
|
}
|
|
5392
5558
|
/**
|
|
5393
5559
|
* Adds or updates a property with a specified key and a value.
|
|
@@ -5403,7 +5569,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5403
5569
|
* @param key The key of the property to get
|
|
5404
5570
|
*/
|
|
5405
5571
|
get(key) {
|
|
5406
|
-
return this.
|
|
5572
|
+
return this.#map.get(key);
|
|
5407
5573
|
}
|
|
5408
5574
|
/**
|
|
5409
5575
|
* Deletes a key from the LiveObject
|
|
@@ -5412,7 +5578,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5412
5578
|
delete(key) {
|
|
5413
5579
|
this._pool?.assertStorageIsWritable();
|
|
5414
5580
|
const keyAsString = key;
|
|
5415
|
-
const oldValue = this.
|
|
5581
|
+
const oldValue = this.#map.get(keyAsString);
|
|
5416
5582
|
if (oldValue === void 0) {
|
|
5417
5583
|
return;
|
|
5418
5584
|
}
|
|
@@ -5420,7 +5586,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5420
5586
|
if (isLiveNode(oldValue)) {
|
|
5421
5587
|
oldValue._detach();
|
|
5422
5588
|
}
|
|
5423
|
-
this.
|
|
5589
|
+
this.#map.delete(keyAsString);
|
|
5424
5590
|
this.invalidate();
|
|
5425
5591
|
return;
|
|
5426
5592
|
}
|
|
@@ -5437,7 +5603,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5437
5603
|
}
|
|
5438
5604
|
];
|
|
5439
5605
|
}
|
|
5440
|
-
this.
|
|
5606
|
+
this.#map.delete(keyAsString);
|
|
5441
5607
|
this.invalidate();
|
|
5442
5608
|
const storageUpdates = /* @__PURE__ */ new Map();
|
|
5443
5609
|
storageUpdates.set(this._id, {
|
|
@@ -5470,14 +5636,14 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5470
5636
|
if (newValue === void 0) {
|
|
5471
5637
|
continue;
|
|
5472
5638
|
}
|
|
5473
|
-
const oldValue = this.
|
|
5639
|
+
const oldValue = this.#map.get(key);
|
|
5474
5640
|
if (isLiveNode(oldValue)) {
|
|
5475
5641
|
oldValue._detach();
|
|
5476
5642
|
}
|
|
5477
5643
|
if (isLiveNode(newValue)) {
|
|
5478
5644
|
newValue._setParentLink(this, key);
|
|
5479
5645
|
}
|
|
5480
|
-
this.
|
|
5646
|
+
this.#map.set(key, newValue);
|
|
5481
5647
|
this.invalidate();
|
|
5482
5648
|
}
|
|
5483
5649
|
return;
|
|
@@ -5497,7 +5663,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5497
5663
|
if (newValue === void 0) {
|
|
5498
5664
|
continue;
|
|
5499
5665
|
}
|
|
5500
|
-
const oldValue = this.
|
|
5666
|
+
const oldValue = this.#map.get(key);
|
|
5501
5667
|
if (isLiveNode(oldValue)) {
|
|
5502
5668
|
reverseOps.push(...oldValue._toOps(this._id, key));
|
|
5503
5669
|
oldValue._detach();
|
|
@@ -5514,14 +5680,14 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5514
5680
|
(op) => op.parentId === this._id
|
|
5515
5681
|
);
|
|
5516
5682
|
if (createCrdtOp) {
|
|
5517
|
-
this.
|
|
5683
|
+
this.#propToLastUpdate.set(key, nn(createCrdtOp.opId));
|
|
5518
5684
|
}
|
|
5519
5685
|
ops.push(...newAttachChildOps);
|
|
5520
5686
|
} else {
|
|
5521
5687
|
updatedProps[key] = newValue;
|
|
5522
|
-
this.
|
|
5688
|
+
this.#propToLastUpdate.set(key, opId);
|
|
5523
5689
|
}
|
|
5524
|
-
this.
|
|
5690
|
+
this.#map.set(key, newValue);
|
|
5525
5691
|
this.invalidate();
|
|
5526
5692
|
updateDelta[key] = { type: "update" };
|
|
5527
5693
|
}
|
|
@@ -5558,7 +5724,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5558
5724
|
type: "LiveObject",
|
|
5559
5725
|
id: nodeId,
|
|
5560
5726
|
key,
|
|
5561
|
-
payload: Array.from(this.
|
|
5727
|
+
payload: Array.from(this.#map.entries()).map(
|
|
5562
5728
|
([key2, value]) => isLiveNode(value) ? value.toTreeNode(key2) : { type: "Json", id: `${nodeId}:${key2}`, key: key2, payload: value }
|
|
5563
5729
|
)
|
|
5564
5730
|
};
|
|
@@ -5566,7 +5732,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5566
5732
|
/** @internal */
|
|
5567
5733
|
_toImmutable() {
|
|
5568
5734
|
const result = {};
|
|
5569
|
-
for (const [key, val] of this
|
|
5735
|
+
for (const [key, val] of this.#map) {
|
|
5570
5736
|
result[key] = isLiveStructure(val) ? val.toImmutable() : val;
|
|
5571
5737
|
}
|
|
5572
5738
|
return process.env.NODE_ENV === "production" ? result : Object.freeze(result);
|
|
@@ -5574,7 +5740,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5574
5740
|
clone() {
|
|
5575
5741
|
return new _LiveObject(
|
|
5576
5742
|
Object.fromEntries(
|
|
5577
|
-
Array.from(this
|
|
5743
|
+
Array.from(this.#map).map(([key, value]) => [
|
|
5578
5744
|
key,
|
|
5579
5745
|
isLiveStructure(value) ? value.clone() : deepClone(value)
|
|
5580
5746
|
])
|
|
@@ -5868,7 +6034,7 @@ var ClientMsgCode = /* @__PURE__ */ ((ClientMsgCode2) => {
|
|
|
5868
6034
|
return ClientMsgCode2;
|
|
5869
6035
|
})(ClientMsgCode || {});
|
|
5870
6036
|
|
|
5871
|
-
// src/refs/
|
|
6037
|
+
// src/refs/ManagedOthers.ts
|
|
5872
6038
|
function makeUser(conn, presence) {
|
|
5873
6039
|
const { connectionId, id, info } = conn;
|
|
5874
6040
|
const canWrite = canWriteStorage(conn.scopes);
|
|
@@ -5885,98 +6051,110 @@ function makeUser(conn, presence) {
|
|
|
5885
6051
|
})
|
|
5886
6052
|
);
|
|
5887
6053
|
}
|
|
5888
|
-
var
|
|
5889
|
-
//
|
|
5890
|
-
//
|
|
5891
|
-
|
|
6054
|
+
var ManagedOthers = class {
|
|
6055
|
+
// Track mutable state internally, but signal to the outside when the
|
|
6056
|
+
// observable derived state changes only
|
|
6057
|
+
#internal;
|
|
6058
|
+
#userCache;
|
|
6059
|
+
// The "clean" signal that is exposed to the outside world
|
|
6060
|
+
signal;
|
|
5892
6061
|
constructor() {
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
const users = compact(
|
|
5904
|
-
Array.from(this._presences.keys()).map(
|
|
5905
|
-
(connectionId) => this.getUser(Number(connectionId))
|
|
6062
|
+
this.#internal = new MutableSignal({
|
|
6063
|
+
connections: /* @__PURE__ */ new Map(),
|
|
6064
|
+
presences: /* @__PURE__ */ new Map()
|
|
6065
|
+
});
|
|
6066
|
+
this.signal = DerivedSignal.from(
|
|
6067
|
+
this.#internal,
|
|
6068
|
+
(_ignore) => compact(
|
|
6069
|
+
Array.from(this.#internal.get().presences.keys()).map(
|
|
6070
|
+
(connectionId) => this.getUser(Number(connectionId))
|
|
6071
|
+
)
|
|
5906
6072
|
)
|
|
5907
6073
|
);
|
|
5908
|
-
|
|
6074
|
+
this.#userCache = /* @__PURE__ */ new Map();
|
|
6075
|
+
}
|
|
6076
|
+
// Shorthand for .signal.get()
|
|
6077
|
+
get() {
|
|
6078
|
+
return this.signal.get();
|
|
6079
|
+
}
|
|
6080
|
+
connectionIds() {
|
|
6081
|
+
return this.#internal.get().connections.keys();
|
|
5909
6082
|
}
|
|
5910
6083
|
clearOthers() {
|
|
5911
|
-
this.
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
6084
|
+
this.#internal.mutate((state) => {
|
|
6085
|
+
state.connections.clear();
|
|
6086
|
+
state.presences.clear();
|
|
6087
|
+
this.#userCache.clear();
|
|
6088
|
+
});
|
|
5915
6089
|
}
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
const conn =
|
|
5919
|
-
const presence =
|
|
6090
|
+
#_getUser(connectionId) {
|
|
6091
|
+
const state = this.#internal.get();
|
|
6092
|
+
const conn = state.connections.get(connectionId);
|
|
6093
|
+
const presence = state.presences.get(connectionId);
|
|
5920
6094
|
if (conn !== void 0 && presence !== void 0) {
|
|
5921
6095
|
return makeUser(conn, presence);
|
|
5922
6096
|
}
|
|
5923
6097
|
return void 0;
|
|
5924
6098
|
}
|
|
5925
6099
|
getUser(connectionId) {
|
|
5926
|
-
const cachedUser = this.
|
|
6100
|
+
const cachedUser = this.#userCache.get(connectionId);
|
|
5927
6101
|
if (cachedUser) {
|
|
5928
6102
|
return cachedUser;
|
|
5929
6103
|
}
|
|
5930
|
-
const computedUser = this
|
|
6104
|
+
const computedUser = this.#_getUser(connectionId);
|
|
5931
6105
|
if (computedUser) {
|
|
5932
|
-
this.
|
|
6106
|
+
this.#userCache.set(connectionId, computedUser);
|
|
5933
6107
|
return computedUser;
|
|
5934
6108
|
}
|
|
5935
6109
|
return void 0;
|
|
5936
6110
|
}
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
if (this._users.has(connectionId)) {
|
|
5940
|
-
this._users.delete(connectionId);
|
|
5941
|
-
}
|
|
5942
|
-
this.invalidate();
|
|
6111
|
+
#invalidateUser(connectionId) {
|
|
6112
|
+
this.#userCache.delete(connectionId);
|
|
5943
6113
|
}
|
|
5944
6114
|
/**
|
|
5945
6115
|
* Records a known connection. This records the connection ID and the
|
|
5946
6116
|
* associated metadata.
|
|
5947
6117
|
*/
|
|
5948
6118
|
setConnection(connectionId, metaUserId, metaUserInfo, scopes) {
|
|
5949
|
-
this.
|
|
5950
|
-
|
|
5951
|
-
freeze({
|
|
6119
|
+
this.#internal.mutate((state) => {
|
|
6120
|
+
state.connections.set(
|
|
5952
6121
|
connectionId,
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
6122
|
+
freeze({
|
|
6123
|
+
connectionId,
|
|
6124
|
+
id: metaUserId,
|
|
6125
|
+
info: metaUserInfo,
|
|
6126
|
+
scopes
|
|
6127
|
+
})
|
|
6128
|
+
);
|
|
6129
|
+
if (!state.presences.has(connectionId)) {
|
|
6130
|
+
return false;
|
|
6131
|
+
}
|
|
6132
|
+
return this.#invalidateUser(connectionId);
|
|
6133
|
+
});
|
|
5961
6134
|
}
|
|
5962
6135
|
/**
|
|
5963
6136
|
* Removes a known connectionId. Removes both the connection's metadata and
|
|
5964
6137
|
* the presence information.
|
|
5965
6138
|
*/
|
|
5966
6139
|
removeConnection(connectionId) {
|
|
5967
|
-
this.
|
|
5968
|
-
|
|
5969
|
-
|
|
6140
|
+
this.#internal.mutate((state) => {
|
|
6141
|
+
state.connections.delete(connectionId);
|
|
6142
|
+
state.presences.delete(connectionId);
|
|
6143
|
+
this.#invalidateUser(connectionId);
|
|
6144
|
+
});
|
|
5970
6145
|
}
|
|
5971
6146
|
/**
|
|
5972
6147
|
* Stores a new user from a full presence update. If the user already exists,
|
|
5973
6148
|
* its known presence data is overwritten.
|
|
5974
6149
|
*/
|
|
5975
6150
|
setOther(connectionId, presence) {
|
|
5976
|
-
this.
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
6151
|
+
this.#internal.mutate((state) => {
|
|
6152
|
+
state.presences.set(connectionId, freeze(compactObject(presence)));
|
|
6153
|
+
if (!state.connections.has(connectionId)) {
|
|
6154
|
+
return false;
|
|
6155
|
+
}
|
|
6156
|
+
return this.#invalidateUser(connectionId);
|
|
6157
|
+
});
|
|
5980
6158
|
}
|
|
5981
6159
|
/**
|
|
5982
6160
|
* Patches the presence data for an existing "other". If we don't know the
|
|
@@ -5984,38 +6162,18 @@ var OthersRef = class extends ImmutableRef {
|
|
|
5984
6162
|
* full .setOther() call first.
|
|
5985
6163
|
*/
|
|
5986
6164
|
patchOther(connectionId, patch) {
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
// src/refs/PatchableRef.ts
|
|
6000
|
-
var PatchableRef = class extends ImmutableRef {
|
|
6001
|
-
constructor(data) {
|
|
6002
|
-
super();
|
|
6003
|
-
this._data = freeze(compactObject(data));
|
|
6004
|
-
}
|
|
6005
|
-
/** @internal */
|
|
6006
|
-
_toImmutable() {
|
|
6007
|
-
return this._data;
|
|
6008
|
-
}
|
|
6009
|
-
/**
|
|
6010
|
-
* Patches the current object.
|
|
6011
|
-
*/
|
|
6012
|
-
patch(patch) {
|
|
6013
|
-
const oldData = this._data;
|
|
6014
|
-
const newData = merge(oldData, patch);
|
|
6015
|
-
if (oldData !== newData) {
|
|
6016
|
-
this._data = freeze(newData);
|
|
6017
|
-
this.invalidate();
|
|
6018
|
-
}
|
|
6165
|
+
this.#internal.mutate((state) => {
|
|
6166
|
+
const oldPresence = state.presences.get(connectionId);
|
|
6167
|
+
if (oldPresence === void 0) {
|
|
6168
|
+
return false;
|
|
6169
|
+
}
|
|
6170
|
+
const newPresence = merge(oldPresence, patch);
|
|
6171
|
+
if (oldPresence === newPresence) {
|
|
6172
|
+
return false;
|
|
6173
|
+
}
|
|
6174
|
+
state.presences.set(connectionId, freeze(newPresence));
|
|
6175
|
+
return this.#invalidateUser(connectionId);
|
|
6176
|
+
});
|
|
6019
6177
|
}
|
|
6020
6178
|
};
|
|
6021
6179
|
|
|
@@ -6092,10 +6250,10 @@ function createRoom(options, config) {
|
|
|
6092
6250
|
messages: [],
|
|
6093
6251
|
storageOperations: []
|
|
6094
6252
|
},
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
myPresence: new
|
|
6098
|
-
others: new
|
|
6253
|
+
staticSessionInfoSig: new Signal(null),
|
|
6254
|
+
dynamicSessionInfoSig: new Signal(null),
|
|
6255
|
+
myPresence: new PatchableSignal(initialPresence),
|
|
6256
|
+
others: new ManagedOthers(),
|
|
6099
6257
|
initialStorage,
|
|
6100
6258
|
idFactory: null,
|
|
6101
6259
|
// The Yjs provider associated to this room
|
|
@@ -6114,8 +6272,6 @@ function createRoom(options, config) {
|
|
|
6114
6272
|
// Debug
|
|
6115
6273
|
opStackTraces: process.env.NODE_ENV !== "production" ? /* @__PURE__ */ new Map() : void 0
|
|
6116
6274
|
};
|
|
6117
|
-
const doNotBatchUpdates = (cb) => cb();
|
|
6118
|
-
const batchUpdates = config.unstable_batchedUpdates ?? doNotBatchUpdates;
|
|
6119
6275
|
let lastTokenKey;
|
|
6120
6276
|
function onStatusDidChange(newStatus) {
|
|
6121
6277
|
const authValue = managedSocket.authValue;
|
|
@@ -6125,46 +6281,38 @@ function createRoom(options, config) {
|
|
|
6125
6281
|
lastTokenKey = tokenKey;
|
|
6126
6282
|
if (authValue.type === "secret") {
|
|
6127
6283
|
const token = authValue.token.parsed;
|
|
6128
|
-
context.
|
|
6284
|
+
context.staticSessionInfoSig.set({
|
|
6129
6285
|
userId: token.k === "sec-legacy" /* SECRET_LEGACY */ ? token.id : token.uid,
|
|
6130
6286
|
userInfo: token.k === "sec-legacy" /* SECRET_LEGACY */ ? token.info : token.ui
|
|
6131
6287
|
});
|
|
6132
6288
|
} else {
|
|
6133
|
-
context.
|
|
6289
|
+
context.staticSessionInfoSig.set({
|
|
6134
6290
|
userId: void 0,
|
|
6135
6291
|
userInfo: void 0
|
|
6136
6292
|
});
|
|
6137
6293
|
}
|
|
6138
6294
|
}
|
|
6139
6295
|
}
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
notifySelfChanged(doNotBatchUpdates);
|
|
6143
|
-
});
|
|
6296
|
+
eventHub.status.notify(newStatus);
|
|
6297
|
+
notifySelfChanged();
|
|
6144
6298
|
}
|
|
6145
6299
|
let _connectionLossTimerId;
|
|
6146
6300
|
let _hasLostConnection = false;
|
|
6147
6301
|
function handleConnectionLossEvent(newStatus) {
|
|
6148
6302
|
if (newStatus === "reconnecting") {
|
|
6149
6303
|
_connectionLossTimerId = setTimeout(() => {
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
notify({ others: [{ type: "reset" }] }, doNotBatchUpdates);
|
|
6155
|
-
});
|
|
6304
|
+
eventHub.lostConnection.notify("lost");
|
|
6305
|
+
_hasLostConnection = true;
|
|
6306
|
+
context.others.clearOthers();
|
|
6307
|
+
notify({ others: [{ type: "reset" }] });
|
|
6156
6308
|
}, config.lostConnectionTimeout);
|
|
6157
6309
|
} else {
|
|
6158
6310
|
clearTimeout(_connectionLossTimerId);
|
|
6159
6311
|
if (_hasLostConnection) {
|
|
6160
6312
|
if (newStatus === "disconnected") {
|
|
6161
|
-
|
|
6162
|
-
eventHub.lostConnection.notify("failed");
|
|
6163
|
-
});
|
|
6313
|
+
eventHub.lostConnection.notify("failed");
|
|
6164
6314
|
} else {
|
|
6165
|
-
|
|
6166
|
-
eventHub.lostConnection.notify("restored");
|
|
6167
|
-
});
|
|
6315
|
+
eventHub.lostConnection.notify("restored");
|
|
6168
6316
|
}
|
|
6169
6317
|
_hasLostConnection = false;
|
|
6170
6318
|
}
|
|
@@ -6177,7 +6325,7 @@ function createRoom(options, config) {
|
|
|
6177
6325
|
// Because context.me.current is a readonly object, we'll have to
|
|
6178
6326
|
// make a copy here. Otherwise, type errors happen later when
|
|
6179
6327
|
// "patching" my presence.
|
|
6180
|
-
{ ...context.myPresence.
|
|
6328
|
+
{ ...context.myPresence.get() }
|
|
6181
6329
|
)
|
|
6182
6330
|
};
|
|
6183
6331
|
if (_getStorage$ !== null) {
|
|
@@ -6194,14 +6342,12 @@ function createRoom(options, config) {
|
|
|
6194
6342
|
managedSocket.events.didConnect.subscribe(onDidConnect);
|
|
6195
6343
|
managedSocket.events.didDisconnect.subscribe(onDidDisconnect);
|
|
6196
6344
|
managedSocket.events.onLiveblocksError.subscribe((err) => {
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
eventHub.error.notify(err);
|
|
6204
|
-
});
|
|
6345
|
+
if (process.env.NODE_ENV !== "production") {
|
|
6346
|
+
error2(
|
|
6347
|
+
`Connection to websocket server closed. Reason: ${err.message} (code: ${err.code}).`
|
|
6348
|
+
);
|
|
6349
|
+
}
|
|
6350
|
+
eventHub.error.notify(err);
|
|
6205
6351
|
});
|
|
6206
6352
|
const pool = {
|
|
6207
6353
|
roomId: config.roomId,
|
|
@@ -6237,16 +6383,14 @@ function createRoom(options, config) {
|
|
|
6237
6383
|
}
|
|
6238
6384
|
activeBatch.reverseOps.unshift(...reverse);
|
|
6239
6385
|
} else {
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
notify({ storageUpdates }, doNotBatchUpdates);
|
|
6245
|
-
});
|
|
6386
|
+
addToUndoStack(reverse);
|
|
6387
|
+
context.redoStack.length = 0;
|
|
6388
|
+
dispatchOps(ops);
|
|
6389
|
+
notify({ storageUpdates });
|
|
6246
6390
|
}
|
|
6247
6391
|
},
|
|
6248
6392
|
assertStorageIsWritable: () => {
|
|
6249
|
-
const scopes = context.
|
|
6393
|
+
const scopes = context.dynamicSessionInfoSig.get()?.scopes;
|
|
6250
6394
|
if (scopes === void 0) {
|
|
6251
6395
|
return;
|
|
6252
6396
|
}
|
|
@@ -6302,7 +6446,7 @@ function createRoom(options, config) {
|
|
|
6302
6446
|
}
|
|
6303
6447
|
function sendMessages(messages) {
|
|
6304
6448
|
const serializedPayload = JSON.stringify(messages);
|
|
6305
|
-
const nonce = context.
|
|
6449
|
+
const nonce = context.dynamicSessionInfoSig.get()?.nonce;
|
|
6306
6450
|
if (config.unstable_fallbackToHTTP && nonce) {
|
|
6307
6451
|
const size = new TextEncoder().encode(serializedPayload).length;
|
|
6308
6452
|
if (size > MAX_SOCKET_MESSAGE_SIZE) {
|
|
@@ -6319,9 +6463,9 @@ function createRoom(options, config) {
|
|
|
6319
6463
|
}
|
|
6320
6464
|
managedSocket.send(serializedPayload);
|
|
6321
6465
|
}
|
|
6322
|
-
const self =
|
|
6323
|
-
context.
|
|
6324
|
-
context.
|
|
6466
|
+
const self = DerivedSignal.from(
|
|
6467
|
+
context.staticSessionInfoSig,
|
|
6468
|
+
context.dynamicSessionInfoSig,
|
|
6325
6469
|
context.myPresence,
|
|
6326
6470
|
(staticSession, dynamicSession, myPresence) => {
|
|
6327
6471
|
if (staticSession === null || dynamicSession === null) {
|
|
@@ -6340,29 +6484,27 @@ function createRoom(options, config) {
|
|
|
6340
6484
|
}
|
|
6341
6485
|
);
|
|
6342
6486
|
let _lastSelf;
|
|
6343
|
-
function notifySelfChanged(
|
|
6344
|
-
const currSelf = self.
|
|
6487
|
+
function notifySelfChanged() {
|
|
6488
|
+
const currSelf = self.get();
|
|
6345
6489
|
if (currSelf !== null && currSelf !== _lastSelf) {
|
|
6346
|
-
|
|
6347
|
-
eventHub.self.notify(currSelf);
|
|
6348
|
-
});
|
|
6490
|
+
eventHub.self.notify(currSelf);
|
|
6349
6491
|
_lastSelf = currSelf;
|
|
6350
6492
|
}
|
|
6351
6493
|
}
|
|
6352
|
-
const selfAsTreeNode =
|
|
6494
|
+
const selfAsTreeNode = DerivedSignal.from(
|
|
6353
6495
|
self,
|
|
6354
6496
|
(me) => me !== null ? userToTreeNode("Me", me) : null
|
|
6355
6497
|
);
|
|
6356
|
-
function createOrUpdateRootFromMessage(message
|
|
6498
|
+
function createOrUpdateRootFromMessage(message) {
|
|
6357
6499
|
if (message.items.length === 0) {
|
|
6358
6500
|
throw new Error("Internal error: cannot load storage without items");
|
|
6359
6501
|
}
|
|
6360
6502
|
if (context.root !== void 0) {
|
|
6361
|
-
updateRoot(message.items
|
|
6503
|
+
updateRoot(message.items);
|
|
6362
6504
|
} else {
|
|
6363
6505
|
context.root = LiveObject._fromItems(message.items, pool);
|
|
6364
6506
|
}
|
|
6365
|
-
const canWrite = self.
|
|
6507
|
+
const canWrite = self.get()?.canWrite ?? true;
|
|
6366
6508
|
const stackSizeBefore = context.undoStack.length;
|
|
6367
6509
|
for (const key in context.initialStorage) {
|
|
6368
6510
|
if (context.root.get(key) === void 0) {
|
|
@@ -6377,7 +6519,7 @@ function createRoom(options, config) {
|
|
|
6377
6519
|
}
|
|
6378
6520
|
context.undoStack.length = stackSizeBefore;
|
|
6379
6521
|
}
|
|
6380
|
-
function updateRoot(items
|
|
6522
|
+
function updateRoot(items) {
|
|
6381
6523
|
if (context.root === void 0) {
|
|
6382
6524
|
return;
|
|
6383
6525
|
}
|
|
@@ -6387,45 +6529,43 @@ function createRoom(options, config) {
|
|
|
6387
6529
|
}
|
|
6388
6530
|
const ops = getTreesDiffOperations(currentItems, new Map(items));
|
|
6389
6531
|
const result = applyOps(ops, false);
|
|
6390
|
-
notify(result.updates
|
|
6532
|
+
notify(result.updates);
|
|
6391
6533
|
}
|
|
6392
|
-
function _addToRealUndoStack(historyOps
|
|
6534
|
+
function _addToRealUndoStack(historyOps) {
|
|
6393
6535
|
if (context.undoStack.length >= 50) {
|
|
6394
6536
|
context.undoStack.shift();
|
|
6395
6537
|
}
|
|
6396
6538
|
context.undoStack.push(historyOps);
|
|
6397
|
-
onHistoryChange(
|
|
6539
|
+
onHistoryChange();
|
|
6398
6540
|
}
|
|
6399
|
-
function addToUndoStack(historyOps
|
|
6541
|
+
function addToUndoStack(historyOps) {
|
|
6400
6542
|
if (context.pausedHistory !== null) {
|
|
6401
6543
|
context.pausedHistory.unshift(...historyOps);
|
|
6402
6544
|
} else {
|
|
6403
|
-
_addToRealUndoStack(historyOps
|
|
6545
|
+
_addToRealUndoStack(historyOps);
|
|
6404
6546
|
}
|
|
6405
6547
|
}
|
|
6406
|
-
function notify(updates
|
|
6548
|
+
function notify(updates) {
|
|
6407
6549
|
const storageUpdates = updates.storageUpdates;
|
|
6408
6550
|
const othersUpdates = updates.others;
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
eventHub.others.notify({ ...event, others });
|
|
6414
|
-
}
|
|
6415
|
-
}
|
|
6416
|
-
if (updates.presence ?? false) {
|
|
6417
|
-
notifySelfChanged(doNotBatchUpdates);
|
|
6418
|
-
eventHub.myPresence.notify(context.myPresence.current);
|
|
6551
|
+
if (othersUpdates !== void 0 && othersUpdates.length > 0) {
|
|
6552
|
+
const others = context.others.get();
|
|
6553
|
+
for (const event of othersUpdates) {
|
|
6554
|
+
eventHub.others.notify({ ...event, others });
|
|
6419
6555
|
}
|
|
6420
|
-
|
|
6421
|
-
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6556
|
+
}
|
|
6557
|
+
if (updates.presence ?? false) {
|
|
6558
|
+
notifySelfChanged();
|
|
6559
|
+
eventHub.myPresence.notify(context.myPresence.get());
|
|
6560
|
+
}
|
|
6561
|
+
if (storageUpdates !== void 0 && storageUpdates.size > 0) {
|
|
6562
|
+
const updates2 = Array.from(storageUpdates.values());
|
|
6563
|
+
eventHub.storageBatch.notify(updates2);
|
|
6564
|
+
}
|
|
6565
|
+
notifyStorageStatus();
|
|
6426
6566
|
}
|
|
6427
6567
|
function getConnectionId() {
|
|
6428
|
-
const info = context.
|
|
6568
|
+
const info = context.dynamicSessionInfoSig.get();
|
|
6429
6569
|
if (info) {
|
|
6430
6570
|
return info.actor;
|
|
6431
6571
|
}
|
|
@@ -6454,7 +6594,7 @@ function createRoom(options, config) {
|
|
|
6454
6594
|
data: {}
|
|
6455
6595
|
};
|
|
6456
6596
|
for (const key in op.data) {
|
|
6457
|
-
reverse.data[key] = context.myPresence.
|
|
6597
|
+
reverse.data[key] = context.myPresence.get()[key];
|
|
6458
6598
|
}
|
|
6459
6599
|
context.myPresence.patch(op.data);
|
|
6460
6600
|
if (context.buffer.presenceUpdates === null) {
|
|
@@ -6563,7 +6703,7 @@ function createRoom(options, config) {
|
|
|
6563
6703
|
continue;
|
|
6564
6704
|
}
|
|
6565
6705
|
context.buffer.presenceUpdates.data[key] = overrideValue;
|
|
6566
|
-
oldValues[key] = context.myPresence.
|
|
6706
|
+
oldValues[key] = context.myPresence.get()[key];
|
|
6567
6707
|
}
|
|
6568
6708
|
context.myPresence.patch(patch);
|
|
6569
6709
|
if (context.activeBatch) {
|
|
@@ -6576,15 +6716,10 @@ function createRoom(options, config) {
|
|
|
6576
6716
|
context.activeBatch.updates.presence = true;
|
|
6577
6717
|
} else {
|
|
6578
6718
|
flushNowOrSoon();
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
doNotBatchUpdates
|
|
6584
|
-
);
|
|
6585
|
-
}
|
|
6586
|
-
notify({ presence: true }, doNotBatchUpdates);
|
|
6587
|
-
});
|
|
6719
|
+
if (options2?.addToHistory) {
|
|
6720
|
+
addToUndoStack([{ type: "presence", data: oldValues }]);
|
|
6721
|
+
}
|
|
6722
|
+
notify({ presence: true });
|
|
6588
6723
|
}
|
|
6589
6724
|
}
|
|
6590
6725
|
function onUpdatePresenceMessage(message) {
|
|
@@ -6617,14 +6752,14 @@ function createRoom(options, config) {
|
|
|
6617
6752
|
}
|
|
6618
6753
|
return null;
|
|
6619
6754
|
}
|
|
6620
|
-
function onRoomStateMessage(message
|
|
6621
|
-
context.
|
|
6755
|
+
function onRoomStateMessage(message) {
|
|
6756
|
+
context.dynamicSessionInfoSig.set({
|
|
6622
6757
|
actor: message.actor,
|
|
6623
6758
|
nonce: message.nonce,
|
|
6624
6759
|
scopes: message.scopes
|
|
6625
6760
|
});
|
|
6626
6761
|
context.idFactory = makeIdFactory(message.actor);
|
|
6627
|
-
notifySelfChanged(
|
|
6762
|
+
notifySelfChanged();
|
|
6628
6763
|
for (const connectionId of context.others.connectionIds()) {
|
|
6629
6764
|
const user = message.users[connectionId];
|
|
6630
6765
|
if (user === void 0) {
|
|
@@ -6649,10 +6784,8 @@ function createRoom(options, config) {
|
|
|
6649
6784
|
function canRedo() {
|
|
6650
6785
|
return context.redoStack.length > 0;
|
|
6651
6786
|
}
|
|
6652
|
-
function onHistoryChange(
|
|
6653
|
-
|
|
6654
|
-
eventHub.history.notify({ canUndo: canUndo(), canRedo: canRedo() });
|
|
6655
|
-
});
|
|
6787
|
+
function onHistoryChange() {
|
|
6788
|
+
eventHub.history.notify({ canUndo: canUndo(), canRedo: canRedo() });
|
|
6656
6789
|
}
|
|
6657
6790
|
function onUserJoinedMessage(message) {
|
|
6658
6791
|
context.others.setConnection(
|
|
@@ -6663,7 +6796,7 @@ function createRoom(options, config) {
|
|
|
6663
6796
|
);
|
|
6664
6797
|
context.buffer.messages.push({
|
|
6665
6798
|
type: 100 /* UPDATE_PRESENCE */,
|
|
6666
|
-
data: context.myPresence.
|
|
6799
|
+
data: context.myPresence.get(),
|
|
6667
6800
|
targetActor: message.actor
|
|
6668
6801
|
});
|
|
6669
6802
|
flushNowOrSoon();
|
|
@@ -6686,7 +6819,7 @@ function createRoom(options, config) {
|
|
|
6686
6819
|
return compact([parseServerMessage(data)]);
|
|
6687
6820
|
}
|
|
6688
6821
|
}
|
|
6689
|
-
function applyAndSendOps(offlineOps
|
|
6822
|
+
function applyAndSendOps(offlineOps) {
|
|
6690
6823
|
if (offlineOps.size === 0) {
|
|
6691
6824
|
return;
|
|
6692
6825
|
}
|
|
@@ -6697,7 +6830,7 @@ function createRoom(options, config) {
|
|
|
6697
6830
|
type: 201 /* UPDATE_STORAGE */,
|
|
6698
6831
|
ops: result.ops
|
|
6699
6832
|
});
|
|
6700
|
-
notify(result.updates
|
|
6833
|
+
notify(result.updates);
|
|
6701
6834
|
sendMessages(messages);
|
|
6702
6835
|
}
|
|
6703
6836
|
function handleServerMessage(event) {
|
|
@@ -6712,104 +6845,102 @@ function createRoom(options, config) {
|
|
|
6712
6845
|
storageUpdates: /* @__PURE__ */ new Map(),
|
|
6713
6846
|
others: []
|
|
6714
6847
|
};
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
updates.others.push(userJoinedUpdate);
|
|
6722
|
-
}
|
|
6723
|
-
break;
|
|
6724
|
-
}
|
|
6725
|
-
case 100 /* UPDATE_PRESENCE */: {
|
|
6726
|
-
const othersPresenceUpdate = onUpdatePresenceMessage(message);
|
|
6727
|
-
if (othersPresenceUpdate) {
|
|
6728
|
-
updates.others.push(othersPresenceUpdate);
|
|
6729
|
-
}
|
|
6730
|
-
break;
|
|
6731
|
-
}
|
|
6732
|
-
case 103 /* BROADCASTED_EVENT */: {
|
|
6733
|
-
const others = context.others.current;
|
|
6734
|
-
eventHub.customEvent.notify({
|
|
6735
|
-
connectionId: message.actor,
|
|
6736
|
-
user: message.actor < 0 ? null : others.find((u) => u.connectionId === message.actor) ?? null,
|
|
6737
|
-
event: message.event
|
|
6738
|
-
});
|
|
6739
|
-
break;
|
|
6740
|
-
}
|
|
6741
|
-
case 102 /* USER_LEFT */: {
|
|
6742
|
-
const event2 = onUserLeftMessage(message);
|
|
6743
|
-
if (event2) {
|
|
6744
|
-
updates.others.push(event2);
|
|
6745
|
-
}
|
|
6746
|
-
break;
|
|
6747
|
-
}
|
|
6748
|
-
case 300 /* UPDATE_YDOC */: {
|
|
6749
|
-
eventHub.ydoc.notify(message);
|
|
6750
|
-
break;
|
|
6751
|
-
}
|
|
6752
|
-
case 104 /* ROOM_STATE */: {
|
|
6753
|
-
updates.others.push(onRoomStateMessage(message, doNotBatchUpdates));
|
|
6754
|
-
break;
|
|
6848
|
+
for (const message of messages) {
|
|
6849
|
+
switch (message.type) {
|
|
6850
|
+
case 101 /* USER_JOINED */: {
|
|
6851
|
+
const userJoinedUpdate = onUserJoinedMessage(message);
|
|
6852
|
+
if (userJoinedUpdate) {
|
|
6853
|
+
updates.others.push(userJoinedUpdate);
|
|
6755
6854
|
}
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
6855
|
+
break;
|
|
6856
|
+
}
|
|
6857
|
+
case 100 /* UPDATE_PRESENCE */: {
|
|
6858
|
+
const othersPresenceUpdate = onUpdatePresenceMessage(message);
|
|
6859
|
+
if (othersPresenceUpdate) {
|
|
6860
|
+
updates.others.push(othersPresenceUpdate);
|
|
6759
6861
|
}
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6862
|
+
break;
|
|
6863
|
+
}
|
|
6864
|
+
case 103 /* BROADCASTED_EVENT */: {
|
|
6865
|
+
const others = context.others.get();
|
|
6866
|
+
eventHub.customEvent.notify({
|
|
6867
|
+
connectionId: message.actor,
|
|
6868
|
+
user: message.actor < 0 ? null : others.find((u) => u.connectionId === message.actor) ?? null,
|
|
6869
|
+
event: message.event
|
|
6870
|
+
});
|
|
6871
|
+
break;
|
|
6872
|
+
}
|
|
6873
|
+
case 102 /* USER_LEFT */: {
|
|
6874
|
+
const event2 = onUserLeftMessage(message);
|
|
6875
|
+
if (event2) {
|
|
6876
|
+
updates.others.push(event2);
|
|
6769
6877
|
}
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6878
|
+
break;
|
|
6879
|
+
}
|
|
6880
|
+
case 300 /* UPDATE_YDOC */: {
|
|
6881
|
+
eventHub.ydoc.notify(message);
|
|
6882
|
+
break;
|
|
6883
|
+
}
|
|
6884
|
+
case 104 /* ROOM_STATE */: {
|
|
6885
|
+
updates.others.push(onRoomStateMessage(message));
|
|
6886
|
+
break;
|
|
6887
|
+
}
|
|
6888
|
+
case 200 /* INITIAL_STORAGE_STATE */: {
|
|
6889
|
+
processInitialStorage(message);
|
|
6890
|
+
break;
|
|
6891
|
+
}
|
|
6892
|
+
case 201 /* UPDATE_STORAGE */: {
|
|
6893
|
+
const applyResult = applyOps(message.ops, false);
|
|
6894
|
+
for (const [key, value] of applyResult.updates.storageUpdates) {
|
|
6895
|
+
updates.storageUpdates.set(
|
|
6896
|
+
key,
|
|
6897
|
+
mergeStorageUpdates(updates.storageUpdates.get(key), value)
|
|
6774
6898
|
);
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
|
|
6899
|
+
}
|
|
6900
|
+
break;
|
|
6901
|
+
}
|
|
6902
|
+
case 299 /* REJECT_STORAGE_OP */: {
|
|
6903
|
+
errorWithTitle(
|
|
6904
|
+
"Storage mutation rejection error",
|
|
6905
|
+
message.reason
|
|
6906
|
+
);
|
|
6907
|
+
if (process.env.NODE_ENV !== "production") {
|
|
6908
|
+
const traces = /* @__PURE__ */ new Set();
|
|
6909
|
+
for (const opId of message.opIds) {
|
|
6910
|
+
const trace = context.opStackTraces?.get(opId);
|
|
6911
|
+
if (trace) {
|
|
6912
|
+
traces.add(trace);
|
|
6782
6913
|
}
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6914
|
+
}
|
|
6915
|
+
if (traces.size > 0) {
|
|
6916
|
+
warnWithTitle(
|
|
6917
|
+
"The following function calls caused the rejected storage mutations:",
|
|
6918
|
+
`
|
|
6787
6919
|
|
|
6788
6920
|
${Array.from(traces).join("\n\n")}`
|
|
6789
|
-
);
|
|
6790
|
-
}
|
|
6791
|
-
throw new Error(
|
|
6792
|
-
`Storage mutations rejected by server: ${message.reason}`
|
|
6793
6921
|
);
|
|
6794
6922
|
}
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
case 407 /* THREAD_DELETED */:
|
|
6799
|
-
case 401 /* THREAD_METADATA_UPDATED */:
|
|
6800
|
-
case 408 /* THREAD_UPDATED */:
|
|
6801
|
-
case 405 /* COMMENT_REACTION_ADDED */:
|
|
6802
|
-
case 406 /* COMMENT_REACTION_REMOVED */:
|
|
6803
|
-
case 402 /* COMMENT_CREATED */:
|
|
6804
|
-
case 403 /* COMMENT_EDITED */:
|
|
6805
|
-
case 404 /* COMMENT_DELETED */: {
|
|
6806
|
-
eventHub.comments.notify(message);
|
|
6807
|
-
break;
|
|
6923
|
+
throw new Error(
|
|
6924
|
+
`Storage mutations rejected by server: ${message.reason}`
|
|
6925
|
+
);
|
|
6808
6926
|
}
|
|
6927
|
+
break;
|
|
6928
|
+
}
|
|
6929
|
+
case 400 /* THREAD_CREATED */:
|
|
6930
|
+
case 407 /* THREAD_DELETED */:
|
|
6931
|
+
case 401 /* THREAD_METADATA_UPDATED */:
|
|
6932
|
+
case 408 /* THREAD_UPDATED */:
|
|
6933
|
+
case 405 /* COMMENT_REACTION_ADDED */:
|
|
6934
|
+
case 406 /* COMMENT_REACTION_REMOVED */:
|
|
6935
|
+
case 402 /* COMMENT_CREATED */:
|
|
6936
|
+
case 403 /* COMMENT_EDITED */:
|
|
6937
|
+
case 404 /* COMMENT_DELETED */: {
|
|
6938
|
+
eventHub.comments.notify(message);
|
|
6939
|
+
break;
|
|
6809
6940
|
}
|
|
6810
6941
|
}
|
|
6811
|
-
|
|
6812
|
-
|
|
6942
|
+
}
|
|
6943
|
+
notify(updates);
|
|
6813
6944
|
}
|
|
6814
6945
|
function flushNowOrSoon() {
|
|
6815
6946
|
const storageOps = context.buffer.storageOperations;
|
|
@@ -6907,8 +7038,8 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6907
7038
|
let _resolveStoragePromise = null;
|
|
6908
7039
|
function processInitialStorage(message) {
|
|
6909
7040
|
const unacknowledgedOps = new Map(context.unacknowledgedOps);
|
|
6910
|
-
createOrUpdateRootFromMessage(message
|
|
6911
|
-
applyAndSendOps(unacknowledgedOps
|
|
7041
|
+
createOrUpdateRootFromMessage(message);
|
|
7042
|
+
applyAndSendOps(unacknowledgedOps);
|
|
6912
7043
|
_resolveStoragePromise?.();
|
|
6913
7044
|
notifyStorageStatus();
|
|
6914
7045
|
eventHub.storageDidLoad.notify();
|
|
@@ -6981,11 +7112,9 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6981
7112
|
}
|
|
6982
7113
|
context.pausedHistory = null;
|
|
6983
7114
|
const result = applyOps(historyOps, true);
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
onHistoryChange(doNotBatchUpdates);
|
|
6988
|
-
});
|
|
7115
|
+
notify(result.updates);
|
|
7116
|
+
context.redoStack.push(result.reverse);
|
|
7117
|
+
onHistoryChange();
|
|
6989
7118
|
for (const op of result.ops) {
|
|
6990
7119
|
if (op.type !== "presence") {
|
|
6991
7120
|
context.buffer.storageOperations.push(op);
|
|
@@ -7003,11 +7132,9 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7003
7132
|
}
|
|
7004
7133
|
context.pausedHistory = null;
|
|
7005
7134
|
const result = applyOps(historyOps, true);
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
onHistoryChange(doNotBatchUpdates);
|
|
7010
|
-
});
|
|
7135
|
+
notify(result.updates);
|
|
7136
|
+
context.undoStack.push(result.reverse);
|
|
7137
|
+
onHistoryChange();
|
|
7011
7138
|
for (const op of result.ops) {
|
|
7012
7139
|
if (op.type !== "presence") {
|
|
7013
7140
|
context.buffer.storageOperations.push(op);
|
|
@@ -7019,39 +7146,37 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7019
7146
|
context.undoStack.length = 0;
|
|
7020
7147
|
context.redoStack.length = 0;
|
|
7021
7148
|
}
|
|
7022
|
-
function
|
|
7149
|
+
function batch2(callback) {
|
|
7023
7150
|
if (context.activeBatch) {
|
|
7024
7151
|
return callback();
|
|
7025
7152
|
}
|
|
7026
7153
|
let returnValue = void 0;
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
addToUndoStack(currentBatch.reverseOps, doNotBatchUpdates);
|
|
7044
|
-
}
|
|
7045
|
-
if (currentBatch.ops.length > 0) {
|
|
7046
|
-
context.redoStack.length = 0;
|
|
7047
|
-
}
|
|
7048
|
-
if (currentBatch.ops.length > 0) {
|
|
7049
|
-
dispatchOps(currentBatch.ops);
|
|
7050
|
-
}
|
|
7051
|
-
notify(currentBatch.updates, doNotBatchUpdates);
|
|
7052
|
-
flushNowOrSoon();
|
|
7154
|
+
context.activeBatch = {
|
|
7155
|
+
ops: [],
|
|
7156
|
+
updates: {
|
|
7157
|
+
storageUpdates: /* @__PURE__ */ new Map(),
|
|
7158
|
+
presence: false,
|
|
7159
|
+
others: []
|
|
7160
|
+
},
|
|
7161
|
+
reverseOps: []
|
|
7162
|
+
};
|
|
7163
|
+
try {
|
|
7164
|
+
returnValue = callback();
|
|
7165
|
+
} finally {
|
|
7166
|
+
const currentBatch = context.activeBatch;
|
|
7167
|
+
context.activeBatch = null;
|
|
7168
|
+
if (currentBatch.reverseOps.length > 0) {
|
|
7169
|
+
addToUndoStack(currentBatch.reverseOps);
|
|
7053
7170
|
}
|
|
7054
|
-
|
|
7171
|
+
if (currentBatch.ops.length > 0) {
|
|
7172
|
+
context.redoStack.length = 0;
|
|
7173
|
+
}
|
|
7174
|
+
if (currentBatch.ops.length > 0) {
|
|
7175
|
+
dispatchOps(currentBatch.ops);
|
|
7176
|
+
}
|
|
7177
|
+
notify(currentBatch.updates);
|
|
7178
|
+
flushNowOrSoon();
|
|
7179
|
+
}
|
|
7055
7180
|
return returnValue;
|
|
7056
7181
|
}
|
|
7057
7182
|
function pauseHistory() {
|
|
@@ -7063,7 +7188,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7063
7188
|
const historyOps = context.pausedHistory;
|
|
7064
7189
|
context.pausedHistory = null;
|
|
7065
7190
|
if (historyOps !== null && historyOps.length > 0) {
|
|
7066
|
-
_addToRealUndoStack(historyOps
|
|
7191
|
+
_addToRealUndoStack(historyOps);
|
|
7067
7192
|
}
|
|
7068
7193
|
}
|
|
7069
7194
|
const syncSourceForStorage = config.createSyncSource();
|
|
@@ -7086,7 +7211,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7086
7211
|
);
|
|
7087
7212
|
}
|
|
7088
7213
|
function isPresenceReady() {
|
|
7089
|
-
return self.
|
|
7214
|
+
return self.get() !== null;
|
|
7090
7215
|
}
|
|
7091
7216
|
async function waitUntilPresenceReady() {
|
|
7092
7217
|
while (!isPresenceReady()) {
|
|
@@ -7106,8 +7231,8 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7106
7231
|
await getStorage();
|
|
7107
7232
|
}
|
|
7108
7233
|
}
|
|
7109
|
-
const others_forDevTools =
|
|
7110
|
-
context.others,
|
|
7234
|
+
const others_forDevTools = DerivedSignal.from(
|
|
7235
|
+
context.others.signal,
|
|
7111
7236
|
(others) => others.map((other, index) => userToTreeNode(`Other ${index}`, other))
|
|
7112
7237
|
);
|
|
7113
7238
|
const events = {
|
|
@@ -7297,8 +7422,8 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7297
7422
|
// create a version
|
|
7298
7423
|
createTextVersion,
|
|
7299
7424
|
// Support for the Liveblocks browser extension
|
|
7300
|
-
getSelf_forDevTools: () => selfAsTreeNode.
|
|
7301
|
-
getOthers_forDevTools: () => others_forDevTools.
|
|
7425
|
+
getSelf_forDevTools: () => selfAsTreeNode.get(),
|
|
7426
|
+
getOthers_forDevTools: () => others_forDevTools.get(),
|
|
7302
7427
|
// prettier-ignore
|
|
7303
7428
|
simulate: {
|
|
7304
7429
|
// These exist only for our E2E testing app
|
|
@@ -7324,7 +7449,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7324
7449
|
updateYDoc,
|
|
7325
7450
|
broadcastEvent,
|
|
7326
7451
|
// Storage
|
|
7327
|
-
batch,
|
|
7452
|
+
batch: batch2,
|
|
7328
7453
|
history: {
|
|
7329
7454
|
undo,
|
|
7330
7455
|
redo,
|
|
@@ -7345,10 +7470,10 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7345
7470
|
events,
|
|
7346
7471
|
// Core
|
|
7347
7472
|
getStatus: () => managedSocket.getStatus(),
|
|
7348
|
-
getSelf: () => self.
|
|
7473
|
+
getSelf: () => self.get(),
|
|
7349
7474
|
// Presence
|
|
7350
|
-
getPresence: () => context.myPresence.
|
|
7351
|
-
getOthers: () => context.others.
|
|
7475
|
+
getPresence: () => context.myPresence.get(),
|
|
7476
|
+
getOthers: () => context.others.get(),
|
|
7352
7477
|
// Comments
|
|
7353
7478
|
getThreads,
|
|
7354
7479
|
getThreadsSince,
|
|
@@ -7526,10 +7651,10 @@ function createClient(options) {
|
|
|
7526
7651
|
clientOptions.backgroundKeepAliveTimeout
|
|
7527
7652
|
);
|
|
7528
7653
|
const baseUrl = getBaseUrl(clientOptions.baseUrl);
|
|
7529
|
-
const
|
|
7654
|
+
const currentUserId = new Signal(void 0);
|
|
7530
7655
|
const authManager = createAuthManager(options, (token) => {
|
|
7531
7656
|
const userId = token.k === "sec-legacy" /* SECRET_LEGACY */ ? token.id : token.uid;
|
|
7532
|
-
|
|
7657
|
+
currentUserId.set(() => userId);
|
|
7533
7658
|
});
|
|
7534
7659
|
const fetchPolyfill = clientOptions.polyfills?.fetch || /* istanbul ignore next */
|
|
7535
7660
|
globalThis.fetch?.bind(globalThis);
|
|
@@ -7588,7 +7713,6 @@ function createClient(options) {
|
|
|
7588
7713
|
authenticate: makeAuthDelegateForRoom(roomId, authManager)
|
|
7589
7714
|
},
|
|
7590
7715
|
enableDebugLogging: clientOptions.enableDebugLogging,
|
|
7591
|
-
unstable_batchedUpdates: options2?.unstable_batchedUpdates,
|
|
7592
7716
|
baseUrl,
|
|
7593
7717
|
unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP,
|
|
7594
7718
|
unstable_streamData: !!clientOptions.unstable_streamData,
|
|
@@ -7623,7 +7747,7 @@ function createClient(options) {
|
|
|
7623
7747
|
}
|
|
7624
7748
|
function logout() {
|
|
7625
7749
|
authManager.reset();
|
|
7626
|
-
|
|
7750
|
+
currentUserId.set(() => void 0);
|
|
7627
7751
|
for (const { room } of roomsById.values()) {
|
|
7628
7752
|
if (!isIdle(room.getStatus())) {
|
|
7629
7753
|
room.reconnect();
|
|
@@ -7671,20 +7795,20 @@ function createClient(options) {
|
|
|
7671
7795
|
mentionSuggestionsCache.clear();
|
|
7672
7796
|
}
|
|
7673
7797
|
const syncStatusSources = [];
|
|
7674
|
-
const
|
|
7798
|
+
const syncStatusSignal = new Signal("synchronized");
|
|
7675
7799
|
function getSyncStatus() {
|
|
7676
|
-
const status =
|
|
7800
|
+
const status = syncStatusSignal.get();
|
|
7677
7801
|
return status === "synchronizing" ? status : "synchronized";
|
|
7678
7802
|
}
|
|
7679
7803
|
function recompute() {
|
|
7680
|
-
|
|
7681
|
-
syncStatusSources.some((src) => src.
|
|
7804
|
+
syncStatusSignal.set(
|
|
7805
|
+
syncStatusSources.some((src) => src.get() === "synchronizing") ? "synchronizing" : syncStatusSources.some((src) => src.get() === "has-local-changes") ? "has-local-changes" : "synchronized"
|
|
7682
7806
|
);
|
|
7683
7807
|
}
|
|
7684
7808
|
function createSyncSource() {
|
|
7685
|
-
const source = new
|
|
7809
|
+
const source = new Signal("synchronized");
|
|
7686
7810
|
syncStatusSources.push(source);
|
|
7687
|
-
const unsub = source.
|
|
7811
|
+
const unsub = source.subscribe(() => recompute());
|
|
7688
7812
|
function setSyncStatus(status) {
|
|
7689
7813
|
source.set(status);
|
|
7690
7814
|
}
|
|
@@ -7693,7 +7817,7 @@ function createClient(options) {
|
|
|
7693
7817
|
const index = syncStatusSources.findIndex((item) => item === source);
|
|
7694
7818
|
if (index > -1) {
|
|
7695
7819
|
const [ref] = syncStatusSources.splice(index, 1);
|
|
7696
|
-
const wasStillPending = ref.
|
|
7820
|
+
const wasStillPending = ref.get() !== "synchronized";
|
|
7697
7821
|
if (wasStillPending) {
|
|
7698
7822
|
recompute();
|
|
7699
7823
|
}
|
|
@@ -7703,7 +7827,7 @@ function createClient(options) {
|
|
|
7703
7827
|
}
|
|
7704
7828
|
{
|
|
7705
7829
|
const maybePreventClose = (e) => {
|
|
7706
|
-
if (clientOptions.preventUnsavedChanges &&
|
|
7830
|
+
if (clientOptions.preventUnsavedChanges && syncStatusSignal.get() !== "synchronized") {
|
|
7707
7831
|
e.preventDefault();
|
|
7708
7832
|
}
|
|
7709
7833
|
};
|
|
@@ -7731,11 +7855,11 @@ function createClient(options) {
|
|
|
7731
7855
|
},
|
|
7732
7856
|
getSyncStatus,
|
|
7733
7857
|
events: {
|
|
7734
|
-
syncStatus:
|
|
7858
|
+
syncStatus: syncStatusSignal
|
|
7735
7859
|
},
|
|
7736
7860
|
// Internal
|
|
7737
7861
|
[kInternal]: {
|
|
7738
|
-
|
|
7862
|
+
currentUserId,
|
|
7739
7863
|
mentionSuggestionsCache,
|
|
7740
7864
|
resolveMentionSuggestions: clientOptions.resolveMentionSuggestions,
|
|
7741
7865
|
usersStore,
|
|
@@ -7909,13 +8033,15 @@ function escapeHtml(value) {
|
|
|
7909
8033
|
);
|
|
7910
8034
|
}
|
|
7911
8035
|
var HtmlSafeString = class {
|
|
8036
|
+
#strings;
|
|
8037
|
+
#values;
|
|
7912
8038
|
constructor(strings, values) {
|
|
7913
|
-
this
|
|
7914
|
-
this
|
|
8039
|
+
this.#strings = strings;
|
|
8040
|
+
this.#values = values;
|
|
7915
8041
|
}
|
|
7916
8042
|
toString() {
|
|
7917
|
-
return this.
|
|
7918
|
-
return result + escapeHtml(nn(this
|
|
8043
|
+
return this.#strings.reduce((result, str, i) => {
|
|
8044
|
+
return result + escapeHtml(nn(this.#values[i - 1])) + str;
|
|
7919
8045
|
});
|
|
7920
8046
|
}
|
|
7921
8047
|
};
|
|
@@ -7963,13 +8089,15 @@ function escapeMarkdown(value) {
|
|
|
7963
8089
|
);
|
|
7964
8090
|
}
|
|
7965
8091
|
var MarkdownSafeString = class {
|
|
8092
|
+
#strings;
|
|
8093
|
+
#values;
|
|
7966
8094
|
constructor(strings, values) {
|
|
7967
|
-
this
|
|
7968
|
-
this
|
|
8095
|
+
this.#strings = strings;
|
|
8096
|
+
this.#values = values;
|
|
7969
8097
|
}
|
|
7970
8098
|
toString() {
|
|
7971
|
-
return this.
|
|
7972
|
-
return result + escapeMarkdown(nn(this
|
|
8099
|
+
return this.#strings.reduce((result, str, i) => {
|
|
8100
|
+
return result + escapeMarkdown(nn(this.#values[i - 1])) + str;
|
|
7973
8101
|
});
|
|
7974
8102
|
}
|
|
7975
8103
|
};
|
|
@@ -8642,9 +8770,11 @@ function bisectRight(arr, x, lt) {
|
|
|
8642
8770
|
return lo;
|
|
8643
8771
|
}
|
|
8644
8772
|
var SortedList = class _SortedList {
|
|
8773
|
+
#data;
|
|
8774
|
+
#lt;
|
|
8645
8775
|
constructor(alreadySortedList, lt) {
|
|
8646
|
-
this
|
|
8647
|
-
this
|
|
8776
|
+
this.#lt = lt;
|
|
8777
|
+
this.#data = alreadySortedList;
|
|
8648
8778
|
}
|
|
8649
8779
|
static from(arr, lt) {
|
|
8650
8780
|
const sorted = new _SortedList([], lt);
|
|
@@ -8660,14 +8790,14 @@ var SortedList = class _SortedList {
|
|
|
8660
8790
|
* Clones the sorted list to a new instance.
|
|
8661
8791
|
*/
|
|
8662
8792
|
clone() {
|
|
8663
|
-
return new _SortedList(this.
|
|
8793
|
+
return new _SortedList(this.#data.slice(), this.#lt);
|
|
8664
8794
|
}
|
|
8665
8795
|
/**
|
|
8666
8796
|
* Adds a new item to the sorted list, such that it remains sorted.
|
|
8667
8797
|
*/
|
|
8668
8798
|
add(value) {
|
|
8669
|
-
const idx = bisectRight(this
|
|
8670
|
-
this.
|
|
8799
|
+
const idx = bisectRight(this.#data, value, this.#lt);
|
|
8800
|
+
this.#data.splice(idx, 0, value);
|
|
8671
8801
|
}
|
|
8672
8802
|
/**
|
|
8673
8803
|
* Removes the given value from the sorted list, if it exists. The given
|
|
@@ -8675,25 +8805,25 @@ var SortedList = class _SortedList {
|
|
|
8675
8805
|
* removed if the element exists in the sorted list multiple times.
|
|
8676
8806
|
*/
|
|
8677
8807
|
remove(value) {
|
|
8678
|
-
const idx = this.
|
|
8808
|
+
const idx = this.#data.indexOf(value);
|
|
8679
8809
|
if (idx >= 0) {
|
|
8680
|
-
this.
|
|
8810
|
+
this.#data.splice(idx, 1);
|
|
8681
8811
|
return true;
|
|
8682
8812
|
}
|
|
8683
8813
|
return false;
|
|
8684
8814
|
}
|
|
8685
8815
|
get length() {
|
|
8686
|
-
return this.
|
|
8816
|
+
return this.#data.length;
|
|
8687
8817
|
}
|
|
8688
8818
|
*filter(predicate) {
|
|
8689
|
-
for (const item of this
|
|
8819
|
+
for (const item of this.#data) {
|
|
8690
8820
|
if (predicate(item)) {
|
|
8691
8821
|
yield item;
|
|
8692
8822
|
}
|
|
8693
8823
|
}
|
|
8694
8824
|
}
|
|
8695
8825
|
[Symbol.iterator]() {
|
|
8696
|
-
return this
|
|
8826
|
+
return this.#data[Symbol.iterator]();
|
|
8697
8827
|
}
|
|
8698
8828
|
};
|
|
8699
8829
|
|
|
@@ -8712,15 +8842,18 @@ export {
|
|
|
8712
8842
|
ClientMsgCode,
|
|
8713
8843
|
CommentsApiError,
|
|
8714
8844
|
CrdtType,
|
|
8845
|
+
DerivedSignal,
|
|
8715
8846
|
HttpError,
|
|
8716
8847
|
LiveList,
|
|
8717
8848
|
LiveMap,
|
|
8718
8849
|
LiveObject,
|
|
8850
|
+
MutableSignal,
|
|
8719
8851
|
NotificationsApiError,
|
|
8720
8852
|
OpCode,
|
|
8721
8853
|
Permission,
|
|
8722
8854
|
Promise_withResolvers,
|
|
8723
8855
|
ServerMsgCode,
|
|
8856
|
+
Signal,
|
|
8724
8857
|
SortedList,
|
|
8725
8858
|
TextEditorType,
|
|
8726
8859
|
WebsocketCloseCodes,
|
|
@@ -8730,6 +8863,7 @@ export {
|
|
|
8730
8863
|
assertNever,
|
|
8731
8864
|
autoRetry,
|
|
8732
8865
|
b64decode,
|
|
8866
|
+
batch,
|
|
8733
8867
|
chunk,
|
|
8734
8868
|
cloneLson,
|
|
8735
8869
|
compactObject,
|
|
@@ -8742,7 +8876,6 @@ export {
|
|
|
8742
8876
|
createCommentAttachmentId,
|
|
8743
8877
|
createCommentId,
|
|
8744
8878
|
createInboxNotificationId,
|
|
8745
|
-
createStore,
|
|
8746
8879
|
createThreadId,
|
|
8747
8880
|
deprecate,
|
|
8748
8881
|
deprecateIf,
|