@liveblocks/core 2.14.0 → 2.15.0-debug1
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 +102 -38
- package/dist/index.d.ts +102 -38
- package/dist/index.js +1100 -944
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1053 -897
- 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-debug1";
|
|
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 {
|
|
2615
|
-
|
|
2668
|
+
#machine;
|
|
2669
|
+
#cleanups;
|
|
2670
|
+
events;
|
|
2671
|
+
constructor(delegates, enableDebugLogging = true, 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,215 @@ 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);
|
|
3255
3320
|
}
|
|
3256
3321
|
};
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
this._value = freeze(initialValue);
|
|
3322
|
+
var Signal = class extends AbstractSignal {
|
|
3323
|
+
#value;
|
|
3324
|
+
constructor(value, equals) {
|
|
3325
|
+
super(equals);
|
|
3326
|
+
this.#value = freeze(value);
|
|
3263
3327
|
}
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3328
|
+
[Symbol.dispose]() {
|
|
3329
|
+
super[Symbol.dispose]();
|
|
3330
|
+
this.#value = "(disposed)";
|
|
3331
|
+
}
|
|
3332
|
+
get() {
|
|
3333
|
+
return this.#value;
|
|
3267
3334
|
}
|
|
3268
3335
|
set(newValue) {
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3336
|
+
batch(() => {
|
|
3337
|
+
if (typeof newValue === "function") {
|
|
3338
|
+
newValue = newValue(this.#value);
|
|
3339
|
+
}
|
|
3340
|
+
if (!this.equals(this.#value, newValue)) {
|
|
3341
|
+
this.#value = freeze(newValue);
|
|
3342
|
+
this.markSinksDirty();
|
|
3343
|
+
enqueueTrigger(this);
|
|
3344
|
+
}
|
|
3345
|
+
});
|
|
3346
|
+
}
|
|
3347
|
+
};
|
|
3348
|
+
var PatchableSignal = class extends Signal {
|
|
3349
|
+
constructor(data) {
|
|
3350
|
+
super(freeze(compactObject(data)));
|
|
3351
|
+
}
|
|
3352
|
+
set() {
|
|
3353
|
+
throw new Error("Don't call .set() directly, use .patch()");
|
|
3354
|
+
}
|
|
3355
|
+
/**
|
|
3356
|
+
* Patches the current object.
|
|
3357
|
+
*/
|
|
3358
|
+
patch(patch) {
|
|
3359
|
+
super.set((old) => merge(old, patch));
|
|
3360
|
+
}
|
|
3361
|
+
};
|
|
3362
|
+
var INITIAL = Symbol();
|
|
3363
|
+
var DerivedSignal = class _DerivedSignal extends AbstractSignal {
|
|
3364
|
+
#prevValue;
|
|
3365
|
+
#dirty;
|
|
3366
|
+
// When true, the value in #value may not be up-to-date and needs re-checking
|
|
3367
|
+
#parents;
|
|
3368
|
+
#transform;
|
|
3369
|
+
// prettier-ignore
|
|
3370
|
+
static from(...args) {
|
|
3371
|
+
const last = args.pop();
|
|
3372
|
+
if (typeof last !== "function")
|
|
3373
|
+
raise("Invalid .from() call, last argument expected to be a function");
|
|
3374
|
+
if (typeof args[args.length - 1] === "function") {
|
|
3375
|
+
const equals = last;
|
|
3376
|
+
const transform = args.pop();
|
|
3377
|
+
return new _DerivedSignal(args, transform, equals);
|
|
3378
|
+
} else {
|
|
3379
|
+
const transform = last;
|
|
3380
|
+
return new _DerivedSignal(args, transform);
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
constructor(parents, transform, equals) {
|
|
3384
|
+
super(equals);
|
|
3385
|
+
this.#dirty = true;
|
|
3386
|
+
this.#prevValue = INITIAL;
|
|
3387
|
+
this.#parents = parents;
|
|
3388
|
+
this.#transform = transform;
|
|
3389
|
+
for (const parent of parents) {
|
|
3390
|
+
parent.addSink(this);
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
[Symbol.dispose]() {
|
|
3394
|
+
for (const parent of this.#parents) {
|
|
3395
|
+
parent.removeSink(this);
|
|
3396
|
+
}
|
|
3397
|
+
this.#prevValue = "(disposed)";
|
|
3398
|
+
this.#parents = "(disposed)";
|
|
3399
|
+
this.#transform = "(disposed)";
|
|
3400
|
+
}
|
|
3401
|
+
get isDirty() {
|
|
3402
|
+
return this.#dirty;
|
|
3403
|
+
}
|
|
3404
|
+
#recompute() {
|
|
3405
|
+
const derived = this.#transform(...this.#parents.map((p) => p.get()));
|
|
3406
|
+
this.#dirty = false;
|
|
3407
|
+
if (!this.equals(this.#prevValue, derived)) {
|
|
3408
|
+
this.#prevValue = derived;
|
|
3409
|
+
return true;
|
|
3410
|
+
}
|
|
3411
|
+
return false;
|
|
3412
|
+
}
|
|
3413
|
+
markDirty() {
|
|
3414
|
+
if (!this.#dirty) {
|
|
3415
|
+
this.#dirty = true;
|
|
3416
|
+
this.markSinksDirty();
|
|
3417
|
+
}
|
|
3418
|
+
}
|
|
3419
|
+
get() {
|
|
3420
|
+
if (this.#dirty) {
|
|
3421
|
+
this.#recompute();
|
|
3422
|
+
}
|
|
3423
|
+
return this.#prevValue;
|
|
3424
|
+
}
|
|
3425
|
+
/**
|
|
3426
|
+
* Called by the Signal system if one or more of the dependent signals have
|
|
3427
|
+
* changed. In the case of a DerivedSignal, we'll only want to re-evaluate
|
|
3428
|
+
* the actual value if it's being watched, or any of their sinks are being
|
|
3429
|
+
* watched actively.
|
|
3430
|
+
*/
|
|
3431
|
+
[kTrigger]() {
|
|
3432
|
+
if (!this.hasWatchers) {
|
|
3433
|
+
return;
|
|
3434
|
+
}
|
|
3435
|
+
const updated = this.#recompute();
|
|
3436
|
+
if (updated) {
|
|
3437
|
+
super[kTrigger]();
|
|
3272
3438
|
}
|
|
3273
3439
|
}
|
|
3274
3440
|
};
|
|
3275
|
-
var
|
|
3276
|
-
|
|
3441
|
+
var MutableSignal = class extends AbstractSignal {
|
|
3442
|
+
#state;
|
|
3443
|
+
constructor(initialState) {
|
|
3277
3444
|
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;
|
|
3445
|
+
this.#state = initialState;
|
|
3285
3446
|
}
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3447
|
+
[Symbol.dispose]() {
|
|
3448
|
+
super[Symbol.dispose]();
|
|
3449
|
+
this.#state = "(disposed)";
|
|
3450
|
+
}
|
|
3451
|
+
get() {
|
|
3452
|
+
return this.#state;
|
|
3453
|
+
}
|
|
3454
|
+
/**
|
|
3455
|
+
* Invokes a callback function that is allowed to mutate the given state
|
|
3456
|
+
* value. Do not change the value outside of the callback.
|
|
3457
|
+
*
|
|
3458
|
+
* If the callback explicitly returns `false`, it's assumed that the state
|
|
3459
|
+
* was not changed.
|
|
3460
|
+
*/
|
|
3461
|
+
mutate(callback) {
|
|
3462
|
+
batch(() => {
|
|
3463
|
+
const result = callback ? callback(this.#state) : true;
|
|
3464
|
+
if (result !== null && typeof result === "object" && "then" in result) {
|
|
3465
|
+
raise("MutableSignal.mutate() does not support async callbacks");
|
|
3466
|
+
}
|
|
3467
|
+
if (result !== false) {
|
|
3468
|
+
this.markSinksDirty();
|
|
3469
|
+
enqueueTrigger(this);
|
|
3470
|
+
}
|
|
3471
|
+
});
|
|
3291
3472
|
}
|
|
3292
3473
|
};
|
|
3293
3474
|
|
|
@@ -3455,10 +3636,10 @@ function Orphaned(oldKey, oldPos = asPos(oldKey)) {
|
|
|
3455
3636
|
return Object.freeze({ type: "Orphaned", oldKey, oldPos });
|
|
3456
3637
|
}
|
|
3457
3638
|
var AbstractCrdt = class {
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3639
|
+
// ^^^^^^^^^^^^ TODO: Make this an interface
|
|
3640
|
+
#pool;
|
|
3641
|
+
#id;
|
|
3642
|
+
#parent = NoParent;
|
|
3462
3643
|
/** @internal */
|
|
3463
3644
|
_getParentKeyOrThrow() {
|
|
3464
3645
|
switch (this.parent.type) {
|
|
@@ -3487,18 +3668,18 @@ var AbstractCrdt = class {
|
|
|
3487
3668
|
}
|
|
3488
3669
|
/** @internal */
|
|
3489
3670
|
get _pool() {
|
|
3490
|
-
return this
|
|
3671
|
+
return this.#pool;
|
|
3491
3672
|
}
|
|
3492
3673
|
get roomId() {
|
|
3493
|
-
return this
|
|
3674
|
+
return this.#pool ? this.#pool.roomId : null;
|
|
3494
3675
|
}
|
|
3495
3676
|
/** @internal */
|
|
3496
3677
|
get _id() {
|
|
3497
|
-
return this
|
|
3678
|
+
return this.#id;
|
|
3498
3679
|
}
|
|
3499
3680
|
/** @internal */
|
|
3500
3681
|
get parent() {
|
|
3501
|
-
return this
|
|
3682
|
+
return this.#parent;
|
|
3502
3683
|
}
|
|
3503
3684
|
/** @internal */
|
|
3504
3685
|
get _parentKey() {
|
|
@@ -3532,12 +3713,12 @@ var AbstractCrdt = class {
|
|
|
3532
3713
|
if (this.parent.node !== newParentNode) {
|
|
3533
3714
|
throw new Error("Cannot set parent: node already has a parent");
|
|
3534
3715
|
} else {
|
|
3535
|
-
this
|
|
3716
|
+
this.#parent = HasParent(newParentNode, newParentKey);
|
|
3536
3717
|
return;
|
|
3537
3718
|
}
|
|
3538
3719
|
case "Orphaned":
|
|
3539
3720
|
case "NoParent": {
|
|
3540
|
-
this
|
|
3721
|
+
this.#parent = HasParent(newParentNode, newParentKey);
|
|
3541
3722
|
return;
|
|
3542
3723
|
}
|
|
3543
3724
|
default:
|
|
@@ -3546,25 +3727,25 @@ var AbstractCrdt = class {
|
|
|
3546
3727
|
}
|
|
3547
3728
|
/** @internal */
|
|
3548
3729
|
_attach(id, pool) {
|
|
3549
|
-
if (this
|
|
3730
|
+
if (this.#id || this.#pool) {
|
|
3550
3731
|
throw new Error("Cannot attach node: already attached");
|
|
3551
3732
|
}
|
|
3552
3733
|
pool.addNode(id, crdtAsLiveNode(this));
|
|
3553
|
-
this
|
|
3554
|
-
this
|
|
3734
|
+
this.#id = id;
|
|
3735
|
+
this.#pool = pool;
|
|
3555
3736
|
}
|
|
3556
3737
|
/** @internal */
|
|
3557
3738
|
_detach() {
|
|
3558
|
-
if (this
|
|
3559
|
-
this.
|
|
3739
|
+
if (this.#pool && this.#id) {
|
|
3740
|
+
this.#pool.deleteNode(this.#id);
|
|
3560
3741
|
}
|
|
3561
3742
|
switch (this.parent.type) {
|
|
3562
3743
|
case "HasParent": {
|
|
3563
|
-
this
|
|
3744
|
+
this.#parent = Orphaned(this.parent.key, this.parent.pos);
|
|
3564
3745
|
break;
|
|
3565
3746
|
}
|
|
3566
3747
|
case "NoParent": {
|
|
3567
|
-
this
|
|
3748
|
+
this.#parent = NoParent;
|
|
3568
3749
|
break;
|
|
3569
3750
|
}
|
|
3570
3751
|
case "Orphaned": {
|
|
@@ -3573,8 +3754,13 @@ var AbstractCrdt = class {
|
|
|
3573
3754
|
default:
|
|
3574
3755
|
assertNever(this.parent, "Unknown state");
|
|
3575
3756
|
}
|
|
3576
|
-
this
|
|
3757
|
+
this.#pool = void 0;
|
|
3577
3758
|
}
|
|
3759
|
+
/** This caches the result of the last .toImmutable() call for this Live node. */
|
|
3760
|
+
#cachedImmutable;
|
|
3761
|
+
#cachedTreeNodeKey;
|
|
3762
|
+
/** This caches the result of the last .toTreeNode() call for this Live node. */
|
|
3763
|
+
#cachedTreeNode;
|
|
3578
3764
|
/**
|
|
3579
3765
|
* @internal
|
|
3580
3766
|
*
|
|
@@ -3583,9 +3769,9 @@ var AbstractCrdt = class {
|
|
|
3583
3769
|
* mutation to the Live node.
|
|
3584
3770
|
*/
|
|
3585
3771
|
invalidate() {
|
|
3586
|
-
if (this
|
|
3587
|
-
this
|
|
3588
|
-
this
|
|
3772
|
+
if (this.#cachedImmutable !== void 0 || this.#cachedTreeNode !== void 0) {
|
|
3773
|
+
this.#cachedImmutable = void 0;
|
|
3774
|
+
this.#cachedTreeNode = void 0;
|
|
3589
3775
|
if (this.parent.type === "HasParent") {
|
|
3590
3776
|
this.parent.node.invalidate();
|
|
3591
3777
|
}
|
|
@@ -3597,20 +3783,20 @@ var AbstractCrdt = class {
|
|
|
3597
3783
|
* Return an snapshot of this Live tree for use in DevTools.
|
|
3598
3784
|
*/
|
|
3599
3785
|
toTreeNode(key) {
|
|
3600
|
-
if (this
|
|
3601
|
-
this
|
|
3602
|
-
this
|
|
3786
|
+
if (this.#cachedTreeNode === void 0 || this.#cachedTreeNodeKey !== key) {
|
|
3787
|
+
this.#cachedTreeNodeKey = key;
|
|
3788
|
+
this.#cachedTreeNode = this._toTreeNode(key);
|
|
3603
3789
|
}
|
|
3604
|
-
return this
|
|
3790
|
+
return this.#cachedTreeNode;
|
|
3605
3791
|
}
|
|
3606
3792
|
/**
|
|
3607
3793
|
* Return an immutable snapshot of this Live node and its children.
|
|
3608
3794
|
*/
|
|
3609
3795
|
toImmutable() {
|
|
3610
|
-
if (this
|
|
3611
|
-
this
|
|
3796
|
+
if (this.#cachedImmutable === void 0) {
|
|
3797
|
+
this.#cachedImmutable = this._toImmutable();
|
|
3612
3798
|
}
|
|
3613
|
-
return this
|
|
3799
|
+
return this.#cachedImmutable;
|
|
3614
3800
|
}
|
|
3615
3801
|
};
|
|
3616
3802
|
|
|
@@ -3631,12 +3817,13 @@ function isChildCrdt(crdt) {
|
|
|
3631
3817
|
|
|
3632
3818
|
// src/crdts/LiveRegister.ts
|
|
3633
3819
|
var LiveRegister = class _LiveRegister extends AbstractCrdt {
|
|
3820
|
+
#data;
|
|
3634
3821
|
constructor(data) {
|
|
3635
3822
|
super();
|
|
3636
|
-
this
|
|
3823
|
+
this.#data = data;
|
|
3637
3824
|
}
|
|
3638
3825
|
get data() {
|
|
3639
|
-
return this
|
|
3826
|
+
return this.#data;
|
|
3640
3827
|
}
|
|
3641
3828
|
/** @internal */
|
|
3642
3829
|
static _deserialize([id, item], _parentToChildren, pool) {
|
|
@@ -3692,12 +3879,12 @@ var LiveRegister = class _LiveRegister extends AbstractCrdt {
|
|
|
3692
3879
|
type: "Json",
|
|
3693
3880
|
id: this._id ?? nanoid(),
|
|
3694
3881
|
key,
|
|
3695
|
-
payload: this
|
|
3882
|
+
payload: this.#data
|
|
3696
3883
|
};
|
|
3697
3884
|
}
|
|
3698
3885
|
/** @internal */
|
|
3699
3886
|
_toImmutable() {
|
|
3700
|
-
return this
|
|
3887
|
+
return this.#data;
|
|
3701
3888
|
}
|
|
3702
3889
|
clone() {
|
|
3703
3890
|
return deepClone(this.data);
|
|
@@ -3711,17 +3898,21 @@ function compareNodePosition(itemA, itemB) {
|
|
|
3711
3898
|
return posA === posB ? 0 : posA < posB ? -1 : 1;
|
|
3712
3899
|
}
|
|
3713
3900
|
var LiveList = class _LiveList extends AbstractCrdt {
|
|
3901
|
+
// TODO: Naive array at first, find a better data structure. Maybe an Order statistics tree?
|
|
3902
|
+
#items;
|
|
3903
|
+
#implicitlyDeletedItems;
|
|
3904
|
+
#unacknowledgedSets;
|
|
3714
3905
|
constructor(items) {
|
|
3715
3906
|
super();
|
|
3716
|
-
this
|
|
3717
|
-
this
|
|
3718
|
-
this
|
|
3907
|
+
this.#items = [];
|
|
3908
|
+
this.#implicitlyDeletedItems = /* @__PURE__ */ new WeakSet();
|
|
3909
|
+
this.#unacknowledgedSets = /* @__PURE__ */ new Map();
|
|
3719
3910
|
let position = void 0;
|
|
3720
3911
|
for (const item of items) {
|
|
3721
3912
|
const newPosition = makePosition(position);
|
|
3722
3913
|
const node = lsonToLiveNode(item);
|
|
3723
3914
|
node._setParentLink(this, newPosition);
|
|
3724
|
-
this.
|
|
3915
|
+
this.#items.push(node);
|
|
3725
3916
|
position = newPosition;
|
|
3726
3917
|
}
|
|
3727
3918
|
}
|
|
@@ -3762,7 +3953,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3762
3953
|
parentKey
|
|
3763
3954
|
};
|
|
3764
3955
|
ops.push(op);
|
|
3765
|
-
for (const item of this
|
|
3956
|
+
for (const item of this.#items) {
|
|
3766
3957
|
const parentKey2 = item._getParentKeyOrThrow();
|
|
3767
3958
|
const childOps = HACK_addIntentAndDeletedIdToOperation(
|
|
3768
3959
|
item._toOps(this._id, parentKey2, pool),
|
|
@@ -3770,7 +3961,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3770
3961
|
);
|
|
3771
3962
|
const childOpId = childOps[0].opId;
|
|
3772
3963
|
if (childOpId !== void 0) {
|
|
3773
|
-
this.
|
|
3964
|
+
this.#unacknowledgedSets.set(parentKey2, childOpId);
|
|
3774
3965
|
}
|
|
3775
3966
|
ops.push(...childOps);
|
|
3776
3967
|
}
|
|
@@ -3782,36 +3973,35 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3782
3973
|
* Adds a new item into the sorted list, in the correct position.
|
|
3783
3974
|
*/
|
|
3784
3975
|
_insertAndSort(item) {
|
|
3785
|
-
this.
|
|
3976
|
+
this.#items.push(item);
|
|
3786
3977
|
this._sortItems();
|
|
3787
3978
|
}
|
|
3788
3979
|
/** @internal */
|
|
3789
3980
|
_sortItems() {
|
|
3790
|
-
this.
|
|
3981
|
+
this.#items.sort(compareNodePosition);
|
|
3791
3982
|
this.invalidate();
|
|
3792
3983
|
}
|
|
3793
3984
|
/** @internal */
|
|
3794
3985
|
_indexOfPosition(position) {
|
|
3795
|
-
return this.
|
|
3986
|
+
return this.#items.findIndex(
|
|
3796
3987
|
(item) => item._getParentKeyOrThrow() === position
|
|
3797
3988
|
);
|
|
3798
3989
|
}
|
|
3799
3990
|
/** @internal */
|
|
3800
3991
|
_attach(id, pool) {
|
|
3801
3992
|
super._attach(id, pool);
|
|
3802
|
-
for (const item of this
|
|
3993
|
+
for (const item of this.#items) {
|
|
3803
3994
|
item._attach(pool.generateId(), pool);
|
|
3804
3995
|
}
|
|
3805
3996
|
}
|
|
3806
3997
|
/** @internal */
|
|
3807
3998
|
_detach() {
|
|
3808
3999
|
super._detach();
|
|
3809
|
-
for (const item of this
|
|
4000
|
+
for (const item of this.#items) {
|
|
3810
4001
|
item._detach();
|
|
3811
4002
|
}
|
|
3812
4003
|
}
|
|
3813
|
-
|
|
3814
|
-
_applySetRemote(op) {
|
|
4004
|
+
#applySetRemote(op) {
|
|
3815
4005
|
if (this._pool === void 0) {
|
|
3816
4006
|
throw new Error("Can't attach child if managed pool is not present");
|
|
3817
4007
|
}
|
|
@@ -3822,10 +4012,10 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3822
4012
|
const deletedId = op.deletedId;
|
|
3823
4013
|
const indexOfItemWithSamePosition = this._indexOfPosition(key);
|
|
3824
4014
|
if (indexOfItemWithSamePosition !== -1) {
|
|
3825
|
-
const itemWithSamePosition = this
|
|
4015
|
+
const itemWithSamePosition = this.#items[indexOfItemWithSamePosition];
|
|
3826
4016
|
if (itemWithSamePosition._id === deletedId) {
|
|
3827
4017
|
itemWithSamePosition._detach();
|
|
3828
|
-
this
|
|
4018
|
+
this.#items[indexOfItemWithSamePosition] = child;
|
|
3829
4019
|
return {
|
|
3830
4020
|
modified: makeUpdate(this, [
|
|
3831
4021
|
setDelta(indexOfItemWithSamePosition, child)
|
|
@@ -3833,12 +4023,12 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3833
4023
|
reverse: []
|
|
3834
4024
|
};
|
|
3835
4025
|
} else {
|
|
3836
|
-
this.
|
|
3837
|
-
this
|
|
4026
|
+
this.#implicitlyDeletedItems.add(itemWithSamePosition);
|
|
4027
|
+
this.#items[indexOfItemWithSamePosition] = child;
|
|
3838
4028
|
const delta = [
|
|
3839
4029
|
setDelta(indexOfItemWithSamePosition, child)
|
|
3840
4030
|
];
|
|
3841
|
-
const deleteDelta2 = this
|
|
4031
|
+
const deleteDelta2 = this.#detachItemAssociatedToSetOperation(
|
|
3842
4032
|
op.deletedId
|
|
3843
4033
|
);
|
|
3844
4034
|
if (deleteDelta2) {
|
|
@@ -3851,7 +4041,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3851
4041
|
}
|
|
3852
4042
|
} else {
|
|
3853
4043
|
const updates = [];
|
|
3854
|
-
const deleteDelta2 = this
|
|
4044
|
+
const deleteDelta2 = this.#detachItemAssociatedToSetOperation(
|
|
3855
4045
|
op.deletedId
|
|
3856
4046
|
);
|
|
3857
4047
|
if (deleteDelta2) {
|
|
@@ -3865,26 +4055,25 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3865
4055
|
};
|
|
3866
4056
|
}
|
|
3867
4057
|
}
|
|
3868
|
-
|
|
3869
|
-
_applySetAck(op) {
|
|
4058
|
+
#applySetAck(op) {
|
|
3870
4059
|
if (this._pool === void 0) {
|
|
3871
4060
|
throw new Error("Can't attach child if managed pool is not present");
|
|
3872
4061
|
}
|
|
3873
4062
|
const delta = [];
|
|
3874
|
-
const deletedDelta = this
|
|
4063
|
+
const deletedDelta = this.#detachItemAssociatedToSetOperation(op.deletedId);
|
|
3875
4064
|
if (deletedDelta) {
|
|
3876
4065
|
delta.push(deletedDelta);
|
|
3877
4066
|
}
|
|
3878
|
-
const unacknowledgedOpId = this.
|
|
4067
|
+
const unacknowledgedOpId = this.#unacknowledgedSets.get(op.parentKey);
|
|
3879
4068
|
if (unacknowledgedOpId !== void 0) {
|
|
3880
4069
|
if (unacknowledgedOpId !== op.opId) {
|
|
3881
4070
|
return delta.length === 0 ? { modified: false } : { modified: makeUpdate(this, delta), reverse: [] };
|
|
3882
4071
|
} else {
|
|
3883
|
-
this.
|
|
4072
|
+
this.#unacknowledgedSets.delete(op.parentKey);
|
|
3884
4073
|
}
|
|
3885
4074
|
}
|
|
3886
4075
|
const indexOfItemWithSamePosition = this._indexOfPosition(op.parentKey);
|
|
3887
|
-
const existingItem = this.
|
|
4076
|
+
const existingItem = this.#items.find((item) => item._id === op.id);
|
|
3888
4077
|
if (existingItem !== void 0) {
|
|
3889
4078
|
if (existingItem._parentKey === op.parentKey) {
|
|
3890
4079
|
return {
|
|
@@ -3893,16 +4082,16 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3893
4082
|
};
|
|
3894
4083
|
}
|
|
3895
4084
|
if (indexOfItemWithSamePosition !== -1) {
|
|
3896
|
-
this.
|
|
3897
|
-
this
|
|
4085
|
+
this.#implicitlyDeletedItems.add(
|
|
4086
|
+
this.#items[indexOfItemWithSamePosition]
|
|
3898
4087
|
);
|
|
3899
|
-
const [prevNode] = this.
|
|
4088
|
+
const [prevNode] = this.#items.splice(indexOfItemWithSamePosition, 1);
|
|
3900
4089
|
delta.push(deleteDelta(indexOfItemWithSamePosition, prevNode));
|
|
3901
4090
|
}
|
|
3902
|
-
const prevIndex = this.
|
|
4091
|
+
const prevIndex = this.#items.indexOf(existingItem);
|
|
3903
4092
|
existingItem._setParentLink(this, op.parentKey);
|
|
3904
4093
|
this._sortItems();
|
|
3905
|
-
const newIndex = this.
|
|
4094
|
+
const newIndex = this.#items.indexOf(existingItem);
|
|
3906
4095
|
if (newIndex !== prevIndex) {
|
|
3907
4096
|
delta.push(moveDelta(prevIndex, newIndex, existingItem));
|
|
3908
4097
|
}
|
|
@@ -3912,11 +4101,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3912
4101
|
};
|
|
3913
4102
|
} else {
|
|
3914
4103
|
const orphan = this._pool.getNode(op.id);
|
|
3915
|
-
if (orphan && this.
|
|
4104
|
+
if (orphan && this.#implicitlyDeletedItems.has(orphan)) {
|
|
3916
4105
|
orphan._setParentLink(this, op.parentKey);
|
|
3917
|
-
this.
|
|
4106
|
+
this.#implicitlyDeletedItems.delete(orphan);
|
|
3918
4107
|
this._insertAndSort(orphan);
|
|
3919
|
-
const recreatedItemIndex = this.
|
|
4108
|
+
const recreatedItemIndex = this.#items.indexOf(orphan);
|
|
3920
4109
|
return {
|
|
3921
4110
|
modified: makeUpdate(this, [
|
|
3922
4111
|
// If there is an item at this position, update is a set, else it's an insert
|
|
@@ -3927,9 +4116,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3927
4116
|
};
|
|
3928
4117
|
} else {
|
|
3929
4118
|
if (indexOfItemWithSamePosition !== -1) {
|
|
3930
|
-
this.
|
|
4119
|
+
this.#items.splice(indexOfItemWithSamePosition, 1);
|
|
3931
4120
|
}
|
|
3932
|
-
const { newItem, newIndex } = this
|
|
4121
|
+
const { newItem, newIndex } = this.#createAttachItemAndSort(
|
|
3933
4122
|
op,
|
|
3934
4123
|
op.parentKey
|
|
3935
4124
|
);
|
|
@@ -3946,9 +4135,8 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3946
4135
|
}
|
|
3947
4136
|
/**
|
|
3948
4137
|
* Returns the update delta of the deletion or null
|
|
3949
|
-
* @internal
|
|
3950
4138
|
*/
|
|
3951
|
-
|
|
4139
|
+
#detachItemAssociatedToSetOperation(deletedId) {
|
|
3952
4140
|
if (deletedId === void 0 || this._pool === void 0) {
|
|
3953
4141
|
return null;
|
|
3954
4142
|
}
|
|
@@ -3962,25 +4150,23 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3962
4150
|
}
|
|
3963
4151
|
return result.modified.updates[0];
|
|
3964
4152
|
}
|
|
3965
|
-
|
|
3966
|
-
_applyRemoteInsert(op) {
|
|
4153
|
+
#applyRemoteInsert(op) {
|
|
3967
4154
|
if (this._pool === void 0) {
|
|
3968
4155
|
throw new Error("Can't attach child if managed pool is not present");
|
|
3969
4156
|
}
|
|
3970
4157
|
const key = asPos(op.parentKey);
|
|
3971
4158
|
const existingItemIndex = this._indexOfPosition(key);
|
|
3972
4159
|
if (existingItemIndex !== -1) {
|
|
3973
|
-
this
|
|
4160
|
+
this.#shiftItemPosition(existingItemIndex, key);
|
|
3974
4161
|
}
|
|
3975
|
-
const { newItem, newIndex } = this
|
|
4162
|
+
const { newItem, newIndex } = this.#createAttachItemAndSort(op, key);
|
|
3976
4163
|
return {
|
|
3977
4164
|
modified: makeUpdate(this, [insertDelta(newIndex, newItem)]),
|
|
3978
4165
|
reverse: []
|
|
3979
4166
|
};
|
|
3980
4167
|
}
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
const existingItem = this._items.find((item) => item._id === op.id);
|
|
4168
|
+
#applyInsertAck(op) {
|
|
4169
|
+
const existingItem = this.#items.find((item) => item._id === op.id);
|
|
3984
4170
|
const key = asPos(op.parentKey);
|
|
3985
4171
|
const itemIndexAtPosition = this._indexOfPosition(key);
|
|
3986
4172
|
if (existingItem) {
|
|
@@ -3989,9 +4175,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
3989
4175
|
modified: false
|
|
3990
4176
|
};
|
|
3991
4177
|
} else {
|
|
3992
|
-
const oldPositionIndex = this.
|
|
4178
|
+
const oldPositionIndex = this.#items.indexOf(existingItem);
|
|
3993
4179
|
if (itemIndexAtPosition !== -1) {
|
|
3994
|
-
this
|
|
4180
|
+
this.#shiftItemPosition(itemIndexAtPosition, key);
|
|
3995
4181
|
}
|
|
3996
4182
|
existingItem._setParentLink(this, key);
|
|
3997
4183
|
this._sortItems();
|
|
@@ -4008,9 +4194,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4008
4194
|
}
|
|
4009
4195
|
} else {
|
|
4010
4196
|
const orphan = nn(this._pool).getNode(op.id);
|
|
4011
|
-
if (orphan && this.
|
|
4197
|
+
if (orphan && this.#implicitlyDeletedItems.has(orphan)) {
|
|
4012
4198
|
orphan._setParentLink(this, key);
|
|
4013
|
-
this.
|
|
4199
|
+
this.#implicitlyDeletedItems.delete(orphan);
|
|
4014
4200
|
this._insertAndSort(orphan);
|
|
4015
4201
|
const newIndex = this._indexOfPosition(key);
|
|
4016
4202
|
return {
|
|
@@ -4019,9 +4205,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4019
4205
|
};
|
|
4020
4206
|
} else {
|
|
4021
4207
|
if (itemIndexAtPosition !== -1) {
|
|
4022
|
-
this
|
|
4208
|
+
this.#shiftItemPosition(itemIndexAtPosition, key);
|
|
4023
4209
|
}
|
|
4024
|
-
const { newItem, newIndex } = this
|
|
4210
|
+
const { newItem, newIndex } = this.#createAttachItemAndSort(op, key);
|
|
4025
4211
|
return {
|
|
4026
4212
|
modified: makeUpdate(this, [insertDelta(newIndex, newItem)]),
|
|
4027
4213
|
reverse: []
|
|
@@ -4029,8 +4215,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4029
4215
|
}
|
|
4030
4216
|
}
|
|
4031
4217
|
}
|
|
4032
|
-
|
|
4033
|
-
_applyInsertUndoRedo(op) {
|
|
4218
|
+
#applyInsertUndoRedo(op) {
|
|
4034
4219
|
const { id, parentKey: key } = op;
|
|
4035
4220
|
const child = creationOpToLiveNode(op);
|
|
4036
4221
|
if (this._pool?.getNode(id) !== void 0) {
|
|
@@ -4041,8 +4226,8 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4041
4226
|
const existingItemIndex = this._indexOfPosition(key);
|
|
4042
4227
|
let newKey = key;
|
|
4043
4228
|
if (existingItemIndex !== -1) {
|
|
4044
|
-
const before2 = this
|
|
4045
|
-
const after2 = this
|
|
4229
|
+
const before2 = this.#items[existingItemIndex]?._parentPos;
|
|
4230
|
+
const after2 = this.#items[existingItemIndex + 1]?._parentPos;
|
|
4046
4231
|
newKey = makePosition(before2, after2);
|
|
4047
4232
|
child._setParentLink(this, newKey);
|
|
4048
4233
|
}
|
|
@@ -4053,28 +4238,27 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4053
4238
|
reverse: [{ type: 5 /* DELETE_CRDT */, id }]
|
|
4054
4239
|
};
|
|
4055
4240
|
}
|
|
4056
|
-
|
|
4057
|
-
_applySetUndoRedo(op) {
|
|
4241
|
+
#applySetUndoRedo(op) {
|
|
4058
4242
|
const { id, parentKey: key } = op;
|
|
4059
4243
|
const child = creationOpToLiveNode(op);
|
|
4060
4244
|
if (this._pool?.getNode(id) !== void 0) {
|
|
4061
4245
|
return { modified: false };
|
|
4062
4246
|
}
|
|
4063
|
-
this.
|
|
4247
|
+
this.#unacknowledgedSets.set(key, nn(op.opId));
|
|
4064
4248
|
const indexOfItemWithSameKey = this._indexOfPosition(key);
|
|
4065
4249
|
child._attach(id, nn(this._pool));
|
|
4066
4250
|
child._setParentLink(this, key);
|
|
4067
4251
|
const newKey = key;
|
|
4068
4252
|
if (indexOfItemWithSameKey !== -1) {
|
|
4069
|
-
const existingItem = this
|
|
4253
|
+
const existingItem = this.#items[indexOfItemWithSameKey];
|
|
4070
4254
|
existingItem._detach();
|
|
4071
|
-
this
|
|
4255
|
+
this.#items[indexOfItemWithSameKey] = child;
|
|
4072
4256
|
const reverse = HACK_addIntentAndDeletedIdToOperation(
|
|
4073
4257
|
existingItem._toOps(nn(this._id), key, this._pool),
|
|
4074
4258
|
op.id
|
|
4075
4259
|
);
|
|
4076
4260
|
const delta = [setDelta(indexOfItemWithSameKey, child)];
|
|
4077
|
-
const deletedDelta = this
|
|
4261
|
+
const deletedDelta = this.#detachItemAssociatedToSetOperation(
|
|
4078
4262
|
op.deletedId
|
|
4079
4263
|
);
|
|
4080
4264
|
if (deletedDelta) {
|
|
@@ -4086,7 +4270,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4086
4270
|
};
|
|
4087
4271
|
} else {
|
|
4088
4272
|
this._insertAndSort(child);
|
|
4089
|
-
this
|
|
4273
|
+
this.#detachItemAssociatedToSetOperation(op.deletedId);
|
|
4090
4274
|
const newIndex = this._indexOfPosition(newKey);
|
|
4091
4275
|
return {
|
|
4092
4276
|
reverse: [{ type: 5 /* DELETE_CRDT */, id }],
|
|
@@ -4102,19 +4286,19 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4102
4286
|
let result;
|
|
4103
4287
|
if (op.intent === "set") {
|
|
4104
4288
|
if (source === 1 /* REMOTE */) {
|
|
4105
|
-
result = this
|
|
4289
|
+
result = this.#applySetRemote(op);
|
|
4106
4290
|
} else if (source === 2 /* ACK */) {
|
|
4107
|
-
result = this
|
|
4291
|
+
result = this.#applySetAck(op);
|
|
4108
4292
|
} else {
|
|
4109
|
-
result = this
|
|
4293
|
+
result = this.#applySetUndoRedo(op);
|
|
4110
4294
|
}
|
|
4111
4295
|
} else {
|
|
4112
4296
|
if (source === 1 /* REMOTE */) {
|
|
4113
|
-
result = this
|
|
4297
|
+
result = this.#applyRemoteInsert(op);
|
|
4114
4298
|
} else if (source === 2 /* ACK */) {
|
|
4115
|
-
result = this
|
|
4299
|
+
result = this.#applyInsertAck(op);
|
|
4116
4300
|
} else {
|
|
4117
|
-
result = this
|
|
4301
|
+
result = this.#applyInsertUndoRedo(op);
|
|
4118
4302
|
}
|
|
4119
4303
|
}
|
|
4120
4304
|
if (result.modified !== false) {
|
|
@@ -4127,13 +4311,13 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4127
4311
|
if (child) {
|
|
4128
4312
|
const parentKey = nn(child._parentKey);
|
|
4129
4313
|
const reverse = child._toOps(nn(this._id), parentKey, this._pool);
|
|
4130
|
-
const indexToDelete = this.
|
|
4314
|
+
const indexToDelete = this.#items.indexOf(child);
|
|
4131
4315
|
if (indexToDelete === -1) {
|
|
4132
4316
|
return {
|
|
4133
4317
|
modified: false
|
|
4134
4318
|
};
|
|
4135
4319
|
}
|
|
4136
|
-
const [previousNode] = this.
|
|
4320
|
+
const [previousNode] = this.#items.splice(indexToDelete, 1);
|
|
4137
4321
|
this.invalidate();
|
|
4138
4322
|
child._detach();
|
|
4139
4323
|
return {
|
|
@@ -4143,13 +4327,12 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4143
4327
|
}
|
|
4144
4328
|
return { modified: false };
|
|
4145
4329
|
}
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
this._implicitlyDeletedItems.delete(child);
|
|
4330
|
+
#applySetChildKeyRemote(newKey, child) {
|
|
4331
|
+
if (this.#implicitlyDeletedItems.has(child)) {
|
|
4332
|
+
this.#implicitlyDeletedItems.delete(child);
|
|
4150
4333
|
child._setParentLink(this, newKey);
|
|
4151
4334
|
this._insertAndSort(child);
|
|
4152
|
-
const newIndex = this.
|
|
4335
|
+
const newIndex = this.#items.indexOf(child);
|
|
4153
4336
|
return {
|
|
4154
4337
|
modified: makeUpdate(this, [insertDelta(newIndex, child)]),
|
|
4155
4338
|
reverse: []
|
|
@@ -4163,10 +4346,10 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4163
4346
|
}
|
|
4164
4347
|
const existingItemIndex = this._indexOfPosition(newKey);
|
|
4165
4348
|
if (existingItemIndex === -1) {
|
|
4166
|
-
const previousIndex = this.
|
|
4349
|
+
const previousIndex = this.#items.indexOf(child);
|
|
4167
4350
|
child._setParentLink(this, newKey);
|
|
4168
4351
|
this._sortItems();
|
|
4169
|
-
const newIndex = this.
|
|
4352
|
+
const newIndex = this.#items.indexOf(child);
|
|
4170
4353
|
if (newIndex === previousIndex) {
|
|
4171
4354
|
return {
|
|
4172
4355
|
modified: false
|
|
@@ -4177,14 +4360,14 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4177
4360
|
reverse: []
|
|
4178
4361
|
};
|
|
4179
4362
|
} else {
|
|
4180
|
-
this
|
|
4363
|
+
this.#items[existingItemIndex]._setParentLink(
|
|
4181
4364
|
this,
|
|
4182
|
-
makePosition(newKey, this
|
|
4365
|
+
makePosition(newKey, this.#items[existingItemIndex + 1]?._parentPos)
|
|
4183
4366
|
);
|
|
4184
|
-
const previousIndex = this.
|
|
4367
|
+
const previousIndex = this.#items.indexOf(child);
|
|
4185
4368
|
child._setParentLink(this, newKey);
|
|
4186
4369
|
this._sortItems();
|
|
4187
|
-
const newIndex = this.
|
|
4370
|
+
const newIndex = this.#items.indexOf(child);
|
|
4188
4371
|
if (newIndex === previousIndex) {
|
|
4189
4372
|
return {
|
|
4190
4373
|
modified: false
|
|
@@ -4196,16 +4379,15 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4196
4379
|
};
|
|
4197
4380
|
}
|
|
4198
4381
|
}
|
|
4199
|
-
|
|
4200
|
-
_applySetChildKeyAck(newKey, child) {
|
|
4382
|
+
#applySetChildKeyAck(newKey, child) {
|
|
4201
4383
|
const previousKey = nn(child._parentKey);
|
|
4202
|
-
if (this.
|
|
4384
|
+
if (this.#implicitlyDeletedItems.has(child)) {
|
|
4203
4385
|
const existingItemIndex = this._indexOfPosition(newKey);
|
|
4204
|
-
this.
|
|
4386
|
+
this.#implicitlyDeletedItems.delete(child);
|
|
4205
4387
|
if (existingItemIndex !== -1) {
|
|
4206
|
-
this
|
|
4388
|
+
this.#items[existingItemIndex]._setParentLink(
|
|
4207
4389
|
this,
|
|
4208
|
-
makePosition(newKey, this
|
|
4390
|
+
makePosition(newKey, this.#items[existingItemIndex + 1]?._parentPos)
|
|
4209
4391
|
);
|
|
4210
4392
|
}
|
|
4211
4393
|
child._setParentLink(this, newKey);
|
|
@@ -4219,17 +4401,17 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4219
4401
|
modified: false
|
|
4220
4402
|
};
|
|
4221
4403
|
}
|
|
4222
|
-
const previousIndex = this.
|
|
4404
|
+
const previousIndex = this.#items.indexOf(child);
|
|
4223
4405
|
const existingItemIndex = this._indexOfPosition(newKey);
|
|
4224
4406
|
if (existingItemIndex !== -1) {
|
|
4225
|
-
this
|
|
4407
|
+
this.#items[existingItemIndex]._setParentLink(
|
|
4226
4408
|
this,
|
|
4227
|
-
makePosition(newKey, this
|
|
4409
|
+
makePosition(newKey, this.#items[existingItemIndex + 1]?._parentPos)
|
|
4228
4410
|
);
|
|
4229
4411
|
}
|
|
4230
4412
|
child._setParentLink(this, newKey);
|
|
4231
4413
|
this._sortItems();
|
|
4232
|
-
const newIndex = this.
|
|
4414
|
+
const newIndex = this.#items.indexOf(child);
|
|
4233
4415
|
if (previousIndex === newIndex) {
|
|
4234
4416
|
return {
|
|
4235
4417
|
modified: false
|
|
@@ -4244,20 +4426,19 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4244
4426
|
}
|
|
4245
4427
|
}
|
|
4246
4428
|
}
|
|
4247
|
-
|
|
4248
|
-
_applySetChildKeyUndoRedo(newKey, child) {
|
|
4429
|
+
#applySetChildKeyUndoRedo(newKey, child) {
|
|
4249
4430
|
const previousKey = nn(child._parentKey);
|
|
4250
|
-
const previousIndex = this.
|
|
4431
|
+
const previousIndex = this.#items.indexOf(child);
|
|
4251
4432
|
const existingItemIndex = this._indexOfPosition(newKey);
|
|
4252
4433
|
if (existingItemIndex !== -1) {
|
|
4253
|
-
this
|
|
4434
|
+
this.#items[existingItemIndex]._setParentLink(
|
|
4254
4435
|
this,
|
|
4255
|
-
makePosition(newKey, this
|
|
4436
|
+
makePosition(newKey, this.#items[existingItemIndex + 1]?._parentPos)
|
|
4256
4437
|
);
|
|
4257
4438
|
}
|
|
4258
4439
|
child._setParentLink(this, newKey);
|
|
4259
4440
|
this._sortItems();
|
|
4260
|
-
const newIndex = this.
|
|
4441
|
+
const newIndex = this.#items.indexOf(child);
|
|
4261
4442
|
if (previousIndex === newIndex) {
|
|
4262
4443
|
return {
|
|
4263
4444
|
modified: false
|
|
@@ -4277,11 +4458,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4277
4458
|
/** @internal */
|
|
4278
4459
|
_setChildKey(newKey, child, source) {
|
|
4279
4460
|
if (source === 1 /* REMOTE */) {
|
|
4280
|
-
return this
|
|
4461
|
+
return this.#applySetChildKeyRemote(newKey, child);
|
|
4281
4462
|
} else if (source === 2 /* ACK */) {
|
|
4282
|
-
return this
|
|
4463
|
+
return this.#applySetChildKeyAck(newKey, child);
|
|
4283
4464
|
} else {
|
|
4284
|
-
return this
|
|
4465
|
+
return this.#applySetChildKeyUndoRedo(newKey, child);
|
|
4285
4466
|
}
|
|
4286
4467
|
}
|
|
4287
4468
|
/** @internal */
|
|
@@ -4303,7 +4484,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4303
4484
|
* Returns the number of elements.
|
|
4304
4485
|
*/
|
|
4305
4486
|
get length() {
|
|
4306
|
-
return this.
|
|
4487
|
+
return this.#items.length;
|
|
4307
4488
|
}
|
|
4308
4489
|
/**
|
|
4309
4490
|
* Adds one element to the end of the LiveList.
|
|
@@ -4320,13 +4501,13 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4320
4501
|
*/
|
|
4321
4502
|
insert(element, index) {
|
|
4322
4503
|
this._pool?.assertStorageIsWritable();
|
|
4323
|
-
if (index < 0 || index > this.
|
|
4504
|
+
if (index < 0 || index > this.#items.length) {
|
|
4324
4505
|
throw new Error(
|
|
4325
|
-
`Cannot insert list item at index "${index}". index should be between 0 and ${this.
|
|
4506
|
+
`Cannot insert list item at index "${index}". index should be between 0 and ${this.#items.length}`
|
|
4326
4507
|
);
|
|
4327
4508
|
}
|
|
4328
|
-
const before2 = this
|
|
4329
|
-
const after2 = this
|
|
4509
|
+
const before2 = this.#items[index - 1] ? this.#items[index - 1]._parentPos : void 0;
|
|
4510
|
+
const after2 = this.#items[index] ? this.#items[index]._parentPos : void 0;
|
|
4330
4511
|
const position = makePosition(before2, after2);
|
|
4331
4512
|
const value = lsonToLiveNode(element);
|
|
4332
4513
|
value._setParentLink(this, position);
|
|
@@ -4353,7 +4534,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4353
4534
|
if (targetIndex < 0) {
|
|
4354
4535
|
throw new Error("targetIndex cannot be less than 0");
|
|
4355
4536
|
}
|
|
4356
|
-
if (targetIndex >= this.
|
|
4537
|
+
if (targetIndex >= this.#items.length) {
|
|
4357
4538
|
throw new Error(
|
|
4358
4539
|
"targetIndex cannot be greater or equal than the list length"
|
|
4359
4540
|
);
|
|
@@ -4361,20 +4542,20 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4361
4542
|
if (index < 0) {
|
|
4362
4543
|
throw new Error("index cannot be less than 0");
|
|
4363
4544
|
}
|
|
4364
|
-
if (index >= this.
|
|
4545
|
+
if (index >= this.#items.length) {
|
|
4365
4546
|
throw new Error("index cannot be greater or equal than the list length");
|
|
4366
4547
|
}
|
|
4367
4548
|
let beforePosition = null;
|
|
4368
4549
|
let afterPosition = null;
|
|
4369
4550
|
if (index < targetIndex) {
|
|
4370
|
-
afterPosition = targetIndex === this.
|
|
4371
|
-
beforePosition = this
|
|
4551
|
+
afterPosition = targetIndex === this.#items.length - 1 ? void 0 : this.#items[targetIndex + 1]._parentPos;
|
|
4552
|
+
beforePosition = this.#items[targetIndex]._parentPos;
|
|
4372
4553
|
} else {
|
|
4373
|
-
afterPosition = this
|
|
4374
|
-
beforePosition = targetIndex === 0 ? void 0 : this
|
|
4554
|
+
afterPosition = this.#items[targetIndex]._parentPos;
|
|
4555
|
+
beforePosition = targetIndex === 0 ? void 0 : this.#items[targetIndex - 1]._parentPos;
|
|
4375
4556
|
}
|
|
4376
4557
|
const position = makePosition(beforePosition, afterPosition);
|
|
4377
|
-
const item = this
|
|
4558
|
+
const item = this.#items[index];
|
|
4378
4559
|
const previousPosition = item._getParentKeyOrThrow();
|
|
4379
4560
|
item._setParentLink(this, position);
|
|
4380
4561
|
this._sortItems();
|
|
@@ -4408,14 +4589,14 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4408
4589
|
*/
|
|
4409
4590
|
delete(index) {
|
|
4410
4591
|
this._pool?.assertStorageIsWritable();
|
|
4411
|
-
if (index < 0 || index >= this.
|
|
4592
|
+
if (index < 0 || index >= this.#items.length) {
|
|
4412
4593
|
throw new Error(
|
|
4413
|
-
`Cannot delete list item at index "${index}". index should be between 0 and ${this.
|
|
4594
|
+
`Cannot delete list item at index "${index}". index should be between 0 and ${this.#items.length - 1}`
|
|
4414
4595
|
);
|
|
4415
4596
|
}
|
|
4416
|
-
const item = this
|
|
4597
|
+
const item = this.#items[index];
|
|
4417
4598
|
item._detach();
|
|
4418
|
-
const [prev] = this.
|
|
4599
|
+
const [prev] = this.#items.splice(index, 1);
|
|
4419
4600
|
this.invalidate();
|
|
4420
4601
|
if (this._pool) {
|
|
4421
4602
|
const childRecordId = item._id;
|
|
@@ -4445,7 +4626,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4445
4626
|
const ops = [];
|
|
4446
4627
|
const reverseOps = [];
|
|
4447
4628
|
const updateDelta = [];
|
|
4448
|
-
for (const item of this
|
|
4629
|
+
for (const item of this.#items) {
|
|
4449
4630
|
item._detach();
|
|
4450
4631
|
const childId = item._id;
|
|
4451
4632
|
if (childId) {
|
|
@@ -4460,33 +4641,33 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4460
4641
|
updateDelta.push(deleteDelta(0, item));
|
|
4461
4642
|
}
|
|
4462
4643
|
}
|
|
4463
|
-
this
|
|
4644
|
+
this.#items = [];
|
|
4464
4645
|
this.invalidate();
|
|
4465
4646
|
const storageUpdates = /* @__PURE__ */ new Map();
|
|
4466
4647
|
storageUpdates.set(nn(this._id), makeUpdate(this, updateDelta));
|
|
4467
4648
|
this._pool.dispatch(ops, reverseOps, storageUpdates);
|
|
4468
4649
|
} else {
|
|
4469
|
-
for (const item of this
|
|
4650
|
+
for (const item of this.#items) {
|
|
4470
4651
|
item._detach();
|
|
4471
4652
|
}
|
|
4472
|
-
this
|
|
4653
|
+
this.#items = [];
|
|
4473
4654
|
this.invalidate();
|
|
4474
4655
|
}
|
|
4475
4656
|
}
|
|
4476
4657
|
set(index, item) {
|
|
4477
4658
|
this._pool?.assertStorageIsWritable();
|
|
4478
|
-
if (index < 0 || index >= this.
|
|
4659
|
+
if (index < 0 || index >= this.#items.length) {
|
|
4479
4660
|
throw new Error(
|
|
4480
|
-
`Cannot set list item at index "${index}". index should be between 0 and ${this.
|
|
4661
|
+
`Cannot set list item at index "${index}". index should be between 0 and ${this.#items.length - 1}`
|
|
4481
4662
|
);
|
|
4482
4663
|
}
|
|
4483
|
-
const existingItem = this
|
|
4664
|
+
const existingItem = this.#items[index];
|
|
4484
4665
|
const position = existingItem._getParentKeyOrThrow();
|
|
4485
4666
|
const existingId = existingItem._id;
|
|
4486
4667
|
existingItem._detach();
|
|
4487
4668
|
const value = lsonToLiveNode(item);
|
|
4488
4669
|
value._setParentLink(this, position);
|
|
4489
|
-
this
|
|
4670
|
+
this.#items[index] = value;
|
|
4490
4671
|
this.invalidate();
|
|
4491
4672
|
if (this._pool && this._id) {
|
|
4492
4673
|
const id = this._pool.generateId();
|
|
@@ -4497,7 +4678,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4497
4678
|
value._toOps(this._id, position, this._pool),
|
|
4498
4679
|
existingId
|
|
4499
4680
|
);
|
|
4500
|
-
this.
|
|
4681
|
+
this.#unacknowledgedSets.set(position, nn(ops[0].opId));
|
|
4501
4682
|
const reverseOps = HACK_addIntentAndDeletedIdToOperation(
|
|
4502
4683
|
existingItem._toOps(this._id, position, void 0),
|
|
4503
4684
|
id
|
|
@@ -4509,7 +4690,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4509
4690
|
* Returns an Array of all the elements in the LiveList.
|
|
4510
4691
|
*/
|
|
4511
4692
|
toArray() {
|
|
4512
|
-
return this.
|
|
4693
|
+
return this.#items.map(
|
|
4513
4694
|
(entry) => liveNodeToLson(entry)
|
|
4514
4695
|
// ^^^^^^^^
|
|
4515
4696
|
// FIXME! This isn't safe.
|
|
@@ -4560,10 +4741,10 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4560
4741
|
* @returns The element at the specified index or undefined.
|
|
4561
4742
|
*/
|
|
4562
4743
|
get(index) {
|
|
4563
|
-
if (index < 0 || index >= this.
|
|
4744
|
+
if (index < 0 || index >= this.#items.length) {
|
|
4564
4745
|
return void 0;
|
|
4565
4746
|
}
|
|
4566
|
-
return liveNodeToLson(this
|
|
4747
|
+
return liveNodeToLson(this.#items[index]);
|
|
4567
4748
|
}
|
|
4568
4749
|
/**
|
|
4569
4750
|
* Returns the first index at which a given element can be found in the LiveList, or -1 if it is not present.
|
|
@@ -4589,7 +4770,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4589
4770
|
* @returns An array with each element being the result of the callback function.
|
|
4590
4771
|
*/
|
|
4591
4772
|
map(callback) {
|
|
4592
|
-
return this.
|
|
4773
|
+
return this.#items.map(
|
|
4593
4774
|
(entry, i) => callback(
|
|
4594
4775
|
liveNodeToLson(entry),
|
|
4595
4776
|
// ^^^^^^^^
|
|
@@ -4607,10 +4788,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4607
4788
|
return this.toArray().some(predicate);
|
|
4608
4789
|
}
|
|
4609
4790
|
[Symbol.iterator]() {
|
|
4610
|
-
return new LiveListIterator(this
|
|
4791
|
+
return new LiveListIterator(this.#items);
|
|
4611
4792
|
}
|
|
4612
|
-
|
|
4613
|
-
_createAttachItemAndSort(op, key) {
|
|
4793
|
+
#createAttachItemAndSort(op, key) {
|
|
4614
4794
|
const newItem = creationOpToLiveNode(op);
|
|
4615
4795
|
newItem._attach(op.id, nn(this._pool));
|
|
4616
4796
|
newItem._setParentLink(this, key);
|
|
@@ -4618,13 +4798,12 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4618
4798
|
const newIndex = this._indexOfPosition(key);
|
|
4619
4799
|
return { newItem, newIndex };
|
|
4620
4800
|
}
|
|
4621
|
-
|
|
4622
|
-
_shiftItemPosition(index, key) {
|
|
4801
|
+
#shiftItemPosition(index, key) {
|
|
4623
4802
|
const shiftedPosition = makePosition(
|
|
4624
4803
|
key,
|
|
4625
|
-
this.
|
|
4804
|
+
this.#items.length > index + 1 ? this.#items[index + 1]?._parentPos : void 0
|
|
4626
4805
|
);
|
|
4627
|
-
this
|
|
4806
|
+
this.#items[index]._setParentLink(this, shiftedPosition);
|
|
4628
4807
|
}
|
|
4629
4808
|
/** @internal */
|
|
4630
4809
|
_toTreeNode(key) {
|
|
@@ -4632,7 +4811,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4632
4811
|
type: "LiveList",
|
|
4633
4812
|
id: this._id ?? nanoid(),
|
|
4634
4813
|
key,
|
|
4635
|
-
payload: this.
|
|
4814
|
+
payload: this.#items.map(
|
|
4636
4815
|
(item, index) => item.toTreeNode(index.toString())
|
|
4637
4816
|
)
|
|
4638
4817
|
};
|
|
@@ -4642,22 +4821,23 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
4642
4821
|
}
|
|
4643
4822
|
/** @internal */
|
|
4644
4823
|
_toImmutable() {
|
|
4645
|
-
const result = this.
|
|
4824
|
+
const result = this.#items.map((node) => node.toImmutable());
|
|
4646
4825
|
return process.env.NODE_ENV === "production" ? result : Object.freeze(result);
|
|
4647
4826
|
}
|
|
4648
4827
|
clone() {
|
|
4649
|
-
return new _LiveList(this.
|
|
4828
|
+
return new _LiveList(this.#items.map((item) => item.clone()));
|
|
4650
4829
|
}
|
|
4651
4830
|
};
|
|
4652
4831
|
var LiveListIterator = class {
|
|
4832
|
+
#innerIterator;
|
|
4653
4833
|
constructor(items) {
|
|
4654
|
-
this
|
|
4834
|
+
this.#innerIterator = items[Symbol.iterator]();
|
|
4655
4835
|
}
|
|
4656
4836
|
[Symbol.iterator]() {
|
|
4657
4837
|
return this;
|
|
4658
4838
|
}
|
|
4659
4839
|
next() {
|
|
4660
|
-
const result = this.
|
|
4840
|
+
const result = this.#innerIterator.next();
|
|
4661
4841
|
if (result.done) {
|
|
4662
4842
|
return {
|
|
4663
4843
|
done: true,
|
|
@@ -4721,9 +4901,11 @@ function HACK_addIntentAndDeletedIdToOperation(ops, deletedId) {
|
|
|
4721
4901
|
|
|
4722
4902
|
// src/crdts/LiveMap.ts
|
|
4723
4903
|
var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
4904
|
+
#map;
|
|
4905
|
+
#unacknowledgedSet;
|
|
4724
4906
|
constructor(entries2) {
|
|
4725
4907
|
super();
|
|
4726
|
-
this
|
|
4908
|
+
this.#unacknowledgedSet = /* @__PURE__ */ new Map();
|
|
4727
4909
|
if (entries2) {
|
|
4728
4910
|
const mappedEntries = [];
|
|
4729
4911
|
for (const [key, value] of entries2) {
|
|
@@ -4731,14 +4913,12 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4731
4913
|
node._setParentLink(this, key);
|
|
4732
4914
|
mappedEntries.push([key, node]);
|
|
4733
4915
|
}
|
|
4734
|
-
this
|
|
4916
|
+
this.#map = new Map(mappedEntries);
|
|
4735
4917
|
} else {
|
|
4736
|
-
this
|
|
4918
|
+
this.#map = /* @__PURE__ */ new Map();
|
|
4737
4919
|
}
|
|
4738
4920
|
}
|
|
4739
|
-
/**
|
|
4740
|
-
* @internal
|
|
4741
|
-
*/
|
|
4921
|
+
/** @internal */
|
|
4742
4922
|
_toOps(parentId, parentKey, pool) {
|
|
4743
4923
|
if (this._id === void 0) {
|
|
4744
4924
|
throw new Error("Cannot serialize item is not attached");
|
|
@@ -4752,14 +4932,12 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4752
4932
|
parentKey
|
|
4753
4933
|
};
|
|
4754
4934
|
ops.push(op);
|
|
4755
|
-
for (const [key, value] of this
|
|
4935
|
+
for (const [key, value] of this.#map) {
|
|
4756
4936
|
ops.push(...value._toOps(this._id, key, pool));
|
|
4757
4937
|
}
|
|
4758
4938
|
return ops;
|
|
4759
4939
|
}
|
|
4760
|
-
/**
|
|
4761
|
-
* @internal
|
|
4762
|
-
*/
|
|
4940
|
+
/** @internal */
|
|
4763
4941
|
static _deserialize([id, _item], parentToChildren, pool) {
|
|
4764
4942
|
const map = new _LiveMap();
|
|
4765
4943
|
map._attach(id, pool);
|
|
@@ -4770,25 +4948,21 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4770
4948
|
for (const [id2, crdt] of children) {
|
|
4771
4949
|
const child = deserialize([id2, crdt], parentToChildren, pool);
|
|
4772
4950
|
child._setParentLink(map, crdt.parentKey);
|
|
4773
|
-
map.
|
|
4951
|
+
map.#map.set(crdt.parentKey, child);
|
|
4774
4952
|
map.invalidate();
|
|
4775
4953
|
}
|
|
4776
4954
|
return map;
|
|
4777
4955
|
}
|
|
4778
|
-
/**
|
|
4779
|
-
* @internal
|
|
4780
|
-
*/
|
|
4956
|
+
/** @internal */
|
|
4781
4957
|
_attach(id, pool) {
|
|
4782
4958
|
super._attach(id, pool);
|
|
4783
|
-
for (const [_key, value] of this
|
|
4959
|
+
for (const [_key, value] of this.#map) {
|
|
4784
4960
|
if (isLiveNode(value)) {
|
|
4785
4961
|
value._attach(pool.generateId(), pool);
|
|
4786
4962
|
}
|
|
4787
4963
|
}
|
|
4788
4964
|
}
|
|
4789
|
-
/**
|
|
4790
|
-
* @internal
|
|
4791
|
-
*/
|
|
4965
|
+
/** @internal */
|
|
4792
4966
|
_attachChild(op, source) {
|
|
4793
4967
|
if (this._pool === void 0) {
|
|
4794
4968
|
throw new Error("Can't attach child if managed pool is not present");
|
|
@@ -4800,17 +4974,17 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4800
4974
|
return { modified: false };
|
|
4801
4975
|
}
|
|
4802
4976
|
if (source === 2 /* ACK */) {
|
|
4803
|
-
const lastUpdateOpId = this
|
|
4977
|
+
const lastUpdateOpId = this.#unacknowledgedSet.get(key);
|
|
4804
4978
|
if (lastUpdateOpId === opId) {
|
|
4805
|
-
this
|
|
4979
|
+
this.#unacknowledgedSet.delete(key);
|
|
4806
4980
|
return { modified: false };
|
|
4807
4981
|
} else if (lastUpdateOpId !== void 0) {
|
|
4808
4982
|
return { modified: false };
|
|
4809
4983
|
}
|
|
4810
4984
|
} else if (source === 1 /* REMOTE */) {
|
|
4811
|
-
this
|
|
4985
|
+
this.#unacknowledgedSet.delete(key);
|
|
4812
4986
|
}
|
|
4813
|
-
const previousValue = this.
|
|
4987
|
+
const previousValue = this.#map.get(key);
|
|
4814
4988
|
let reverse;
|
|
4815
4989
|
if (previousValue) {
|
|
4816
4990
|
const thisId = nn(this._id);
|
|
@@ -4821,7 +4995,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4821
4995
|
}
|
|
4822
4996
|
child._setParentLink(this, key);
|
|
4823
4997
|
child._attach(id, this._pool);
|
|
4824
|
-
this.
|
|
4998
|
+
this.#map.set(key, child);
|
|
4825
4999
|
this.invalidate();
|
|
4826
5000
|
return {
|
|
4827
5001
|
modified: {
|
|
@@ -4832,25 +5006,21 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4832
5006
|
reverse
|
|
4833
5007
|
};
|
|
4834
5008
|
}
|
|
4835
|
-
/**
|
|
4836
|
-
* @internal
|
|
4837
|
-
*/
|
|
5009
|
+
/** @internal */
|
|
4838
5010
|
_detach() {
|
|
4839
5011
|
super._detach();
|
|
4840
|
-
for (const item of this.
|
|
5012
|
+
for (const item of this.#map.values()) {
|
|
4841
5013
|
item._detach();
|
|
4842
5014
|
}
|
|
4843
5015
|
}
|
|
4844
|
-
/**
|
|
4845
|
-
* @internal
|
|
4846
|
-
*/
|
|
5016
|
+
/** @internal */
|
|
4847
5017
|
_detachChild(child) {
|
|
4848
5018
|
const id = nn(this._id);
|
|
4849
5019
|
const parentKey = nn(child._parentKey);
|
|
4850
5020
|
const reverse = child._toOps(id, parentKey, this._pool);
|
|
4851
|
-
for (const [key, value] of this
|
|
5021
|
+
for (const [key, value] of this.#map) {
|
|
4852
5022
|
if (value === child) {
|
|
4853
|
-
this.
|
|
5023
|
+
this.#map.delete(key);
|
|
4854
5024
|
this.invalidate();
|
|
4855
5025
|
}
|
|
4856
5026
|
}
|
|
@@ -4862,9 +5032,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4862
5032
|
};
|
|
4863
5033
|
return { modified: storageUpdate, reverse };
|
|
4864
5034
|
}
|
|
4865
|
-
/**
|
|
4866
|
-
* @internal
|
|
4867
|
-
*/
|
|
5035
|
+
/** @internal */
|
|
4868
5036
|
_serialize() {
|
|
4869
5037
|
if (this.parent.type !== "HasParent") {
|
|
4870
5038
|
throw new Error("Cannot serialize LiveMap if parent is missing");
|
|
@@ -4881,7 +5049,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4881
5049
|
* @returns The element associated with the specified key, or undefined if the key can't be found in the LiveMap.
|
|
4882
5050
|
*/
|
|
4883
5051
|
get(key) {
|
|
4884
|
-
const value = this.
|
|
5052
|
+
const value = this.#map.get(key);
|
|
4885
5053
|
if (value === void 0) {
|
|
4886
5054
|
return void 0;
|
|
4887
5055
|
}
|
|
@@ -4894,13 +5062,13 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4894
5062
|
*/
|
|
4895
5063
|
set(key, value) {
|
|
4896
5064
|
this._pool?.assertStorageIsWritable();
|
|
4897
|
-
const oldValue = this.
|
|
5065
|
+
const oldValue = this.#map.get(key);
|
|
4898
5066
|
if (oldValue) {
|
|
4899
5067
|
oldValue._detach();
|
|
4900
5068
|
}
|
|
4901
5069
|
const item = lsonToLiveNode(value);
|
|
4902
5070
|
item._setParentLink(this, key);
|
|
4903
|
-
this.
|
|
5071
|
+
this.#map.set(key, item);
|
|
4904
5072
|
this.invalidate();
|
|
4905
5073
|
if (this._pool && this._id) {
|
|
4906
5074
|
const id = this._pool.generateId();
|
|
@@ -4912,7 +5080,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4912
5080
|
updates: { [key]: { type: "update" } }
|
|
4913
5081
|
});
|
|
4914
5082
|
const ops = item._toOps(this._id, key, this._pool);
|
|
4915
|
-
this
|
|
5083
|
+
this.#unacknowledgedSet.set(key, nn(ops[0].opId));
|
|
4916
5084
|
this._pool.dispatch(
|
|
4917
5085
|
item._toOps(this._id, key, this._pool),
|
|
4918
5086
|
oldValue ? oldValue._toOps(this._id, key) : [{ type: 5 /* DELETE_CRDT */, id }],
|
|
@@ -4924,14 +5092,14 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4924
5092
|
* Returns the number of elements in the LiveMap.
|
|
4925
5093
|
*/
|
|
4926
5094
|
get size() {
|
|
4927
|
-
return this.
|
|
5095
|
+
return this.#map.size;
|
|
4928
5096
|
}
|
|
4929
5097
|
/**
|
|
4930
5098
|
* Returns a boolean indicating whether an element with the specified key exists or not.
|
|
4931
5099
|
* @param key The key of the element to test for presence.
|
|
4932
5100
|
*/
|
|
4933
5101
|
has(key) {
|
|
4934
|
-
return this.
|
|
5102
|
+
return this.#map.has(key);
|
|
4935
5103
|
}
|
|
4936
5104
|
/**
|
|
4937
5105
|
* Removes the specified element by key.
|
|
@@ -4940,12 +5108,12 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4940
5108
|
*/
|
|
4941
5109
|
delete(key) {
|
|
4942
5110
|
this._pool?.assertStorageIsWritable();
|
|
4943
|
-
const item = this.
|
|
5111
|
+
const item = this.#map.get(key);
|
|
4944
5112
|
if (item === void 0) {
|
|
4945
5113
|
return false;
|
|
4946
5114
|
}
|
|
4947
5115
|
item._detach();
|
|
4948
|
-
this.
|
|
5116
|
+
this.#map.delete(key);
|
|
4949
5117
|
this.invalidate();
|
|
4950
5118
|
if (this._pool && item._id) {
|
|
4951
5119
|
const thisId = nn(this._id);
|
|
@@ -4973,7 +5141,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4973
5141
|
* Returns a new Iterator object that contains the [key, value] pairs for each element.
|
|
4974
5142
|
*/
|
|
4975
5143
|
entries() {
|
|
4976
|
-
const innerIterator = this.
|
|
5144
|
+
const innerIterator = this.#map.entries();
|
|
4977
5145
|
return {
|
|
4978
5146
|
[Symbol.iterator]() {
|
|
4979
5147
|
return this;
|
|
@@ -5005,13 +5173,13 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
5005
5173
|
* Returns a new Iterator object that contains the keys for each element.
|
|
5006
5174
|
*/
|
|
5007
5175
|
keys() {
|
|
5008
|
-
return this.
|
|
5176
|
+
return this.#map.keys();
|
|
5009
5177
|
}
|
|
5010
5178
|
/**
|
|
5011
5179
|
* Returns a new Iterator object that contains the values for each element.
|
|
5012
5180
|
*/
|
|
5013
5181
|
values() {
|
|
5014
|
-
const innerIterator = this.
|
|
5182
|
+
const innerIterator = this.#map.values();
|
|
5015
5183
|
return {
|
|
5016
5184
|
[Symbol.iterator]() {
|
|
5017
5185
|
return this;
|
|
@@ -5044,7 +5212,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
5044
5212
|
type: "LiveMap",
|
|
5045
5213
|
id: this._id ?? nanoid(),
|
|
5046
5214
|
key,
|
|
5047
|
-
payload: Array.from(this.
|
|
5215
|
+
payload: Array.from(this.#map.entries()).map(
|
|
5048
5216
|
([key2, val]) => val.toTreeNode(key2)
|
|
5049
5217
|
)
|
|
5050
5218
|
};
|
|
@@ -5055,22 +5223,23 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
5055
5223
|
/** @internal */
|
|
5056
5224
|
_toImmutable() {
|
|
5057
5225
|
const result = /* @__PURE__ */ new Map();
|
|
5058
|
-
for (const [key, value] of this
|
|
5226
|
+
for (const [key, value] of this.#map) {
|
|
5059
5227
|
result.set(key, value.toImmutable());
|
|
5060
5228
|
}
|
|
5061
5229
|
return freeze(result);
|
|
5062
5230
|
}
|
|
5063
5231
|
clone() {
|
|
5064
5232
|
return new _LiveMap(
|
|
5065
|
-
Array.from(this
|
|
5233
|
+
Array.from(this.#map).map(([key, node]) => [key, node.clone()])
|
|
5066
5234
|
);
|
|
5067
5235
|
}
|
|
5068
5236
|
};
|
|
5069
5237
|
|
|
5070
5238
|
// src/crdts/LiveObject.ts
|
|
5071
5239
|
var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
5072
|
-
|
|
5073
|
-
|
|
5240
|
+
#map;
|
|
5241
|
+
#propToLastUpdate;
|
|
5242
|
+
static #buildRootAndParentToChildren(items) {
|
|
5074
5243
|
const parentToChildren = /* @__PURE__ */ new Map();
|
|
5075
5244
|
let root = null;
|
|
5076
5245
|
for (const [id, crdt] of items) {
|
|
@@ -5093,7 +5262,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5093
5262
|
}
|
|
5094
5263
|
/** @internal */
|
|
5095
5264
|
static _fromItems(items, pool) {
|
|
5096
|
-
const [root, parentToChildren] = _LiveObject
|
|
5265
|
+
const [root, parentToChildren] = _LiveObject.#buildRootAndParentToChildren(items);
|
|
5097
5266
|
return _LiveObject._deserialize(
|
|
5098
5267
|
root,
|
|
5099
5268
|
parentToChildren,
|
|
@@ -5102,7 +5271,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5102
5271
|
}
|
|
5103
5272
|
constructor(obj = {}) {
|
|
5104
5273
|
super();
|
|
5105
|
-
this
|
|
5274
|
+
this.#propToLastUpdate = /* @__PURE__ */ new Map();
|
|
5106
5275
|
const o = compactObject(obj);
|
|
5107
5276
|
for (const key of Object.keys(o)) {
|
|
5108
5277
|
const value = o[key];
|
|
@@ -5110,7 +5279,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5110
5279
|
value._setParentLink(this, key);
|
|
5111
5280
|
}
|
|
5112
5281
|
}
|
|
5113
|
-
this
|
|
5282
|
+
this.#map = new Map(Object.entries(o));
|
|
5114
5283
|
}
|
|
5115
5284
|
/** @internal */
|
|
5116
5285
|
_toOps(parentId, parentKey, pool) {
|
|
@@ -5128,7 +5297,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5128
5297
|
data: {}
|
|
5129
5298
|
};
|
|
5130
5299
|
ops.push(op);
|
|
5131
|
-
for (const [key, value] of this
|
|
5300
|
+
for (const [key, value] of this.#map) {
|
|
5132
5301
|
if (isLiveNode(value)) {
|
|
5133
5302
|
ops.push(...value._toOps(this._id, key, pool));
|
|
5134
5303
|
} else {
|
|
@@ -5154,7 +5323,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5154
5323
|
if (isLiveStructure(child)) {
|
|
5155
5324
|
child._setParentLink(liveObj, crdt.parentKey);
|
|
5156
5325
|
}
|
|
5157
|
-
liveObj.
|
|
5326
|
+
liveObj.#map.set(crdt.parentKey, child);
|
|
5158
5327
|
liveObj.invalidate();
|
|
5159
5328
|
}
|
|
5160
5329
|
return liveObj;
|
|
@@ -5162,7 +5331,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5162
5331
|
/** @internal */
|
|
5163
5332
|
_attach(id, pool) {
|
|
5164
5333
|
super._attach(id, pool);
|
|
5165
|
-
for (const [_key, value] of this
|
|
5334
|
+
for (const [_key, value] of this.#map) {
|
|
5166
5335
|
if (isLiveNode(value)) {
|
|
5167
5336
|
value._attach(pool.generateId(), pool);
|
|
5168
5337
|
}
|
|
@@ -5176,22 +5345,22 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5176
5345
|
const { id, opId, parentKey: key } = op;
|
|
5177
5346
|
const child = creationOpToLson(op);
|
|
5178
5347
|
if (this._pool.getNode(id) !== void 0) {
|
|
5179
|
-
if (this.
|
|
5180
|
-
this.
|
|
5348
|
+
if (this.#propToLastUpdate.get(key) === opId) {
|
|
5349
|
+
this.#propToLastUpdate.delete(key);
|
|
5181
5350
|
}
|
|
5182
5351
|
return { modified: false };
|
|
5183
5352
|
}
|
|
5184
5353
|
if (source === 0 /* UNDOREDO_RECONNECT */) {
|
|
5185
|
-
this.
|
|
5186
|
-
} else if (this.
|
|
5187
|
-
} else if (this.
|
|
5188
|
-
this.
|
|
5354
|
+
this.#propToLastUpdate.set(key, nn(opId));
|
|
5355
|
+
} else if (this.#propToLastUpdate.get(key) === void 0) {
|
|
5356
|
+
} else if (this.#propToLastUpdate.get(key) === opId) {
|
|
5357
|
+
this.#propToLastUpdate.delete(key);
|
|
5189
5358
|
return { modified: false };
|
|
5190
5359
|
} else {
|
|
5191
5360
|
return { modified: false };
|
|
5192
5361
|
}
|
|
5193
5362
|
const thisId = nn(this._id);
|
|
5194
|
-
const previousValue = this.
|
|
5363
|
+
const previousValue = this.#map.get(key);
|
|
5195
5364
|
let reverse;
|
|
5196
5365
|
if (isLiveNode(previousValue)) {
|
|
5197
5366
|
reverse = previousValue._toOps(thisId, key);
|
|
@@ -5207,7 +5376,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5207
5376
|
}
|
|
5208
5377
|
];
|
|
5209
5378
|
}
|
|
5210
|
-
this.
|
|
5379
|
+
this.#map.set(key, child);
|
|
5211
5380
|
this.invalidate();
|
|
5212
5381
|
if (isLiveStructure(child)) {
|
|
5213
5382
|
child._setParentLink(this, key);
|
|
@@ -5228,9 +5397,9 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5228
5397
|
const id = nn(this._id);
|
|
5229
5398
|
const parentKey = nn(child._parentKey);
|
|
5230
5399
|
const reverse = child._toOps(id, parentKey, this._pool);
|
|
5231
|
-
for (const [key, value] of this
|
|
5400
|
+
for (const [key, value] of this.#map) {
|
|
5232
5401
|
if (value === child) {
|
|
5233
|
-
this.
|
|
5402
|
+
this.#map.delete(key);
|
|
5234
5403
|
this.invalidate();
|
|
5235
5404
|
}
|
|
5236
5405
|
}
|
|
@@ -5246,12 +5415,10 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5246
5415
|
}
|
|
5247
5416
|
return { modified: false };
|
|
5248
5417
|
}
|
|
5249
|
-
/**
|
|
5250
|
-
* @internal
|
|
5251
|
-
*/
|
|
5418
|
+
/** @internal */
|
|
5252
5419
|
_detach() {
|
|
5253
5420
|
super._detach();
|
|
5254
|
-
for (const value of this.
|
|
5421
|
+
for (const value of this.#map.values()) {
|
|
5255
5422
|
if (isLiveNode(value)) {
|
|
5256
5423
|
value._detach();
|
|
5257
5424
|
}
|
|
@@ -5260,18 +5427,16 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5260
5427
|
/** @internal */
|
|
5261
5428
|
_apply(op, isLocal) {
|
|
5262
5429
|
if (op.type === 3 /* UPDATE_OBJECT */) {
|
|
5263
|
-
return this
|
|
5430
|
+
return this.#applyUpdate(op, isLocal);
|
|
5264
5431
|
} else if (op.type === 6 /* DELETE_OBJECT_KEY */) {
|
|
5265
|
-
return this
|
|
5432
|
+
return this.#applyDeleteObjectKey(op, isLocal);
|
|
5266
5433
|
}
|
|
5267
5434
|
return super._apply(op, isLocal);
|
|
5268
5435
|
}
|
|
5269
|
-
/**
|
|
5270
|
-
* @internal
|
|
5271
|
-
*/
|
|
5436
|
+
/** @internal */
|
|
5272
5437
|
_serialize() {
|
|
5273
5438
|
const data = {};
|
|
5274
|
-
for (const [key, value] of this
|
|
5439
|
+
for (const [key, value] of this.#map) {
|
|
5275
5440
|
if (!isLiveNode(value)) {
|
|
5276
5441
|
data[key] = value;
|
|
5277
5442
|
}
|
|
@@ -5290,8 +5455,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5290
5455
|
};
|
|
5291
5456
|
}
|
|
5292
5457
|
}
|
|
5293
|
-
|
|
5294
|
-
_applyUpdate(op, isLocal) {
|
|
5458
|
+
#applyUpdate(op, isLocal) {
|
|
5295
5459
|
let isModified = false;
|
|
5296
5460
|
const id = nn(this._id);
|
|
5297
5461
|
const reverse = [];
|
|
@@ -5301,7 +5465,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5301
5465
|
data: {}
|
|
5302
5466
|
};
|
|
5303
5467
|
for (const key in op.data) {
|
|
5304
|
-
const oldValue = this.
|
|
5468
|
+
const oldValue = this.#map.get(key);
|
|
5305
5469
|
if (isLiveNode(oldValue)) {
|
|
5306
5470
|
reverse.push(...oldValue._toOps(id, key));
|
|
5307
5471
|
oldValue._detach();
|
|
@@ -5318,22 +5482,22 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5318
5482
|
continue;
|
|
5319
5483
|
}
|
|
5320
5484
|
if (isLocal) {
|
|
5321
|
-
this.
|
|
5322
|
-
} else if (this.
|
|
5485
|
+
this.#propToLastUpdate.set(key, nn(op.opId));
|
|
5486
|
+
} else if (this.#propToLastUpdate.get(key) === void 0) {
|
|
5323
5487
|
isModified = true;
|
|
5324
|
-
} else if (this.
|
|
5325
|
-
this.
|
|
5488
|
+
} else if (this.#propToLastUpdate.get(key) === op.opId) {
|
|
5489
|
+
this.#propToLastUpdate.delete(key);
|
|
5326
5490
|
continue;
|
|
5327
5491
|
} else {
|
|
5328
5492
|
continue;
|
|
5329
5493
|
}
|
|
5330
|
-
const oldValue = this.
|
|
5494
|
+
const oldValue = this.#map.get(key);
|
|
5331
5495
|
if (isLiveNode(oldValue)) {
|
|
5332
5496
|
oldValue._detach();
|
|
5333
5497
|
}
|
|
5334
5498
|
isModified = true;
|
|
5335
5499
|
updateDelta[key] = { type: "update" };
|
|
5336
|
-
this.
|
|
5500
|
+
this.#map.set(key, value);
|
|
5337
5501
|
this.invalidate();
|
|
5338
5502
|
}
|
|
5339
5503
|
if (Object.keys(reverseUpdate.data).length !== 0) {
|
|
@@ -5348,16 +5512,15 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5348
5512
|
reverse
|
|
5349
5513
|
} : { modified: false };
|
|
5350
5514
|
}
|
|
5351
|
-
|
|
5352
|
-
_applyDeleteObjectKey(op, isLocal) {
|
|
5515
|
+
#applyDeleteObjectKey(op, isLocal) {
|
|
5353
5516
|
const key = op.key;
|
|
5354
|
-
if (this.
|
|
5517
|
+
if (this.#map.has(key) === false) {
|
|
5355
5518
|
return { modified: false };
|
|
5356
5519
|
}
|
|
5357
|
-
if (!isLocal && this.
|
|
5520
|
+
if (!isLocal && this.#propToLastUpdate.get(key) !== void 0) {
|
|
5358
5521
|
return { modified: false };
|
|
5359
5522
|
}
|
|
5360
|
-
const oldValue = this.
|
|
5523
|
+
const oldValue = this.#map.get(key);
|
|
5361
5524
|
const id = nn(this._id);
|
|
5362
5525
|
let reverse = [];
|
|
5363
5526
|
if (isLiveNode(oldValue)) {
|
|
@@ -5372,7 +5535,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5372
5535
|
}
|
|
5373
5536
|
];
|
|
5374
5537
|
}
|
|
5375
|
-
this.
|
|
5538
|
+
this.#map.delete(key);
|
|
5376
5539
|
this.invalidate();
|
|
5377
5540
|
return {
|
|
5378
5541
|
modified: {
|
|
@@ -5387,7 +5550,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5387
5550
|
* Transform the LiveObject into a javascript object
|
|
5388
5551
|
*/
|
|
5389
5552
|
toObject() {
|
|
5390
|
-
return Object.fromEntries(this
|
|
5553
|
+
return Object.fromEntries(this.#map);
|
|
5391
5554
|
}
|
|
5392
5555
|
/**
|
|
5393
5556
|
* Adds or updates a property with a specified key and a value.
|
|
@@ -5403,7 +5566,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5403
5566
|
* @param key The key of the property to get
|
|
5404
5567
|
*/
|
|
5405
5568
|
get(key) {
|
|
5406
|
-
return this.
|
|
5569
|
+
return this.#map.get(key);
|
|
5407
5570
|
}
|
|
5408
5571
|
/**
|
|
5409
5572
|
* Deletes a key from the LiveObject
|
|
@@ -5412,7 +5575,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5412
5575
|
delete(key) {
|
|
5413
5576
|
this._pool?.assertStorageIsWritable();
|
|
5414
5577
|
const keyAsString = key;
|
|
5415
|
-
const oldValue = this.
|
|
5578
|
+
const oldValue = this.#map.get(keyAsString);
|
|
5416
5579
|
if (oldValue === void 0) {
|
|
5417
5580
|
return;
|
|
5418
5581
|
}
|
|
@@ -5420,7 +5583,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5420
5583
|
if (isLiveNode(oldValue)) {
|
|
5421
5584
|
oldValue._detach();
|
|
5422
5585
|
}
|
|
5423
|
-
this.
|
|
5586
|
+
this.#map.delete(keyAsString);
|
|
5424
5587
|
this.invalidate();
|
|
5425
5588
|
return;
|
|
5426
5589
|
}
|
|
@@ -5437,7 +5600,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5437
5600
|
}
|
|
5438
5601
|
];
|
|
5439
5602
|
}
|
|
5440
|
-
this.
|
|
5603
|
+
this.#map.delete(keyAsString);
|
|
5441
5604
|
this.invalidate();
|
|
5442
5605
|
const storageUpdates = /* @__PURE__ */ new Map();
|
|
5443
5606
|
storageUpdates.set(this._id, {
|
|
@@ -5470,14 +5633,14 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5470
5633
|
if (newValue === void 0) {
|
|
5471
5634
|
continue;
|
|
5472
5635
|
}
|
|
5473
|
-
const oldValue = this.
|
|
5636
|
+
const oldValue = this.#map.get(key);
|
|
5474
5637
|
if (isLiveNode(oldValue)) {
|
|
5475
5638
|
oldValue._detach();
|
|
5476
5639
|
}
|
|
5477
5640
|
if (isLiveNode(newValue)) {
|
|
5478
5641
|
newValue._setParentLink(this, key);
|
|
5479
5642
|
}
|
|
5480
|
-
this.
|
|
5643
|
+
this.#map.set(key, newValue);
|
|
5481
5644
|
this.invalidate();
|
|
5482
5645
|
}
|
|
5483
5646
|
return;
|
|
@@ -5497,7 +5660,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5497
5660
|
if (newValue === void 0) {
|
|
5498
5661
|
continue;
|
|
5499
5662
|
}
|
|
5500
|
-
const oldValue = this.
|
|
5663
|
+
const oldValue = this.#map.get(key);
|
|
5501
5664
|
if (isLiveNode(oldValue)) {
|
|
5502
5665
|
reverseOps.push(...oldValue._toOps(this._id, key));
|
|
5503
5666
|
oldValue._detach();
|
|
@@ -5514,14 +5677,14 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5514
5677
|
(op) => op.parentId === this._id
|
|
5515
5678
|
);
|
|
5516
5679
|
if (createCrdtOp) {
|
|
5517
|
-
this.
|
|
5680
|
+
this.#propToLastUpdate.set(key, nn(createCrdtOp.opId));
|
|
5518
5681
|
}
|
|
5519
5682
|
ops.push(...newAttachChildOps);
|
|
5520
5683
|
} else {
|
|
5521
5684
|
updatedProps[key] = newValue;
|
|
5522
|
-
this.
|
|
5685
|
+
this.#propToLastUpdate.set(key, opId);
|
|
5523
5686
|
}
|
|
5524
|
-
this.
|
|
5687
|
+
this.#map.set(key, newValue);
|
|
5525
5688
|
this.invalidate();
|
|
5526
5689
|
updateDelta[key] = { type: "update" };
|
|
5527
5690
|
}
|
|
@@ -5558,7 +5721,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5558
5721
|
type: "LiveObject",
|
|
5559
5722
|
id: nodeId,
|
|
5560
5723
|
key,
|
|
5561
|
-
payload: Array.from(this.
|
|
5724
|
+
payload: Array.from(this.#map.entries()).map(
|
|
5562
5725
|
([key2, value]) => isLiveNode(value) ? value.toTreeNode(key2) : { type: "Json", id: `${nodeId}:${key2}`, key: key2, payload: value }
|
|
5563
5726
|
)
|
|
5564
5727
|
};
|
|
@@ -5566,7 +5729,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5566
5729
|
/** @internal */
|
|
5567
5730
|
_toImmutable() {
|
|
5568
5731
|
const result = {};
|
|
5569
|
-
for (const [key, val] of this
|
|
5732
|
+
for (const [key, val] of this.#map) {
|
|
5570
5733
|
result[key] = isLiveStructure(val) ? val.toImmutable() : val;
|
|
5571
5734
|
}
|
|
5572
5735
|
return process.env.NODE_ENV === "production" ? result : Object.freeze(result);
|
|
@@ -5574,7 +5737,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
5574
5737
|
clone() {
|
|
5575
5738
|
return new _LiveObject(
|
|
5576
5739
|
Object.fromEntries(
|
|
5577
|
-
Array.from(this
|
|
5740
|
+
Array.from(this.#map).map(([key, value]) => [
|
|
5578
5741
|
key,
|
|
5579
5742
|
isLiveStructure(value) ? value.clone() : deepClone(value)
|
|
5580
5743
|
])
|
|
@@ -5868,7 +6031,7 @@ var ClientMsgCode = /* @__PURE__ */ ((ClientMsgCode2) => {
|
|
|
5868
6031
|
return ClientMsgCode2;
|
|
5869
6032
|
})(ClientMsgCode || {});
|
|
5870
6033
|
|
|
5871
|
-
// src/refs/
|
|
6034
|
+
// src/refs/ManagedOthers.ts
|
|
5872
6035
|
function makeUser(conn, presence) {
|
|
5873
6036
|
const { connectionId, id, info } = conn;
|
|
5874
6037
|
const canWrite = canWriteStorage(conn.scopes);
|
|
@@ -5885,98 +6048,110 @@ function makeUser(conn, presence) {
|
|
|
5885
6048
|
})
|
|
5886
6049
|
);
|
|
5887
6050
|
}
|
|
5888
|
-
var
|
|
5889
|
-
//
|
|
5890
|
-
//
|
|
5891
|
-
|
|
6051
|
+
var ManagedOthers = class {
|
|
6052
|
+
// Track mutable state internally, but signal to the outside when the
|
|
6053
|
+
// observable derived state changes only
|
|
6054
|
+
#internal;
|
|
6055
|
+
#userCache;
|
|
6056
|
+
// The "clean" signal that is exposed to the outside world
|
|
6057
|
+
signal;
|
|
5892
6058
|
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))
|
|
6059
|
+
this.#internal = new MutableSignal({
|
|
6060
|
+
connections: /* @__PURE__ */ new Map(),
|
|
6061
|
+
presences: /* @__PURE__ */ new Map()
|
|
6062
|
+
});
|
|
6063
|
+
this.signal = DerivedSignal.from(
|
|
6064
|
+
this.#internal,
|
|
6065
|
+
(_ignore) => compact(
|
|
6066
|
+
Array.from(this.#internal.get().presences.keys()).map(
|
|
6067
|
+
(connectionId) => this.getUser(Number(connectionId))
|
|
6068
|
+
)
|
|
5906
6069
|
)
|
|
5907
6070
|
);
|
|
5908
|
-
|
|
6071
|
+
this.#userCache = /* @__PURE__ */ new Map();
|
|
6072
|
+
}
|
|
6073
|
+
// Shorthand for .signal.get()
|
|
6074
|
+
get() {
|
|
6075
|
+
return this.signal.get();
|
|
6076
|
+
}
|
|
6077
|
+
connectionIds() {
|
|
6078
|
+
return this.#internal.get().connections.keys();
|
|
5909
6079
|
}
|
|
5910
6080
|
clearOthers() {
|
|
5911
|
-
this.
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
6081
|
+
this.#internal.mutate((state) => {
|
|
6082
|
+
state.connections.clear();
|
|
6083
|
+
state.presences.clear();
|
|
6084
|
+
this.#userCache.clear();
|
|
6085
|
+
});
|
|
5915
6086
|
}
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
const conn =
|
|
5919
|
-
const presence =
|
|
6087
|
+
#_getUser(connectionId) {
|
|
6088
|
+
const state = this.#internal.get();
|
|
6089
|
+
const conn = state.connections.get(connectionId);
|
|
6090
|
+
const presence = state.presences.get(connectionId);
|
|
5920
6091
|
if (conn !== void 0 && presence !== void 0) {
|
|
5921
6092
|
return makeUser(conn, presence);
|
|
5922
6093
|
}
|
|
5923
6094
|
return void 0;
|
|
5924
6095
|
}
|
|
5925
6096
|
getUser(connectionId) {
|
|
5926
|
-
const cachedUser = this.
|
|
6097
|
+
const cachedUser = this.#userCache.get(connectionId);
|
|
5927
6098
|
if (cachedUser) {
|
|
5928
6099
|
return cachedUser;
|
|
5929
6100
|
}
|
|
5930
|
-
const computedUser = this
|
|
6101
|
+
const computedUser = this.#_getUser(connectionId);
|
|
5931
6102
|
if (computedUser) {
|
|
5932
|
-
this.
|
|
6103
|
+
this.#userCache.set(connectionId, computedUser);
|
|
5933
6104
|
return computedUser;
|
|
5934
6105
|
}
|
|
5935
6106
|
return void 0;
|
|
5936
6107
|
}
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
if (this._users.has(connectionId)) {
|
|
5940
|
-
this._users.delete(connectionId);
|
|
5941
|
-
}
|
|
5942
|
-
this.invalidate();
|
|
6108
|
+
#invalidateUser(connectionId) {
|
|
6109
|
+
this.#userCache.delete(connectionId);
|
|
5943
6110
|
}
|
|
5944
6111
|
/**
|
|
5945
6112
|
* Records a known connection. This records the connection ID and the
|
|
5946
6113
|
* associated metadata.
|
|
5947
6114
|
*/
|
|
5948
6115
|
setConnection(connectionId, metaUserId, metaUserInfo, scopes) {
|
|
5949
|
-
this.
|
|
5950
|
-
|
|
5951
|
-
freeze({
|
|
6116
|
+
this.#internal.mutate((state) => {
|
|
6117
|
+
state.connections.set(
|
|
5952
6118
|
connectionId,
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
6119
|
+
freeze({
|
|
6120
|
+
connectionId,
|
|
6121
|
+
id: metaUserId,
|
|
6122
|
+
info: metaUserInfo,
|
|
6123
|
+
scopes
|
|
6124
|
+
})
|
|
6125
|
+
);
|
|
6126
|
+
if (!state.presences.has(connectionId)) {
|
|
6127
|
+
return false;
|
|
6128
|
+
}
|
|
6129
|
+
return this.#invalidateUser(connectionId);
|
|
6130
|
+
});
|
|
5961
6131
|
}
|
|
5962
6132
|
/**
|
|
5963
6133
|
* Removes a known connectionId. Removes both the connection's metadata and
|
|
5964
6134
|
* the presence information.
|
|
5965
6135
|
*/
|
|
5966
6136
|
removeConnection(connectionId) {
|
|
5967
|
-
this.
|
|
5968
|
-
|
|
5969
|
-
|
|
6137
|
+
this.#internal.mutate((state) => {
|
|
6138
|
+
state.connections.delete(connectionId);
|
|
6139
|
+
state.presences.delete(connectionId);
|
|
6140
|
+
this.#invalidateUser(connectionId);
|
|
6141
|
+
});
|
|
5970
6142
|
}
|
|
5971
6143
|
/**
|
|
5972
6144
|
* Stores a new user from a full presence update. If the user already exists,
|
|
5973
6145
|
* its known presence data is overwritten.
|
|
5974
6146
|
*/
|
|
5975
6147
|
setOther(connectionId, presence) {
|
|
5976
|
-
this.
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
6148
|
+
this.#internal.mutate((state) => {
|
|
6149
|
+
state.presences.set(connectionId, freeze(compactObject(presence)));
|
|
6150
|
+
if (!state.connections.has(connectionId)) {
|
|
6151
|
+
return false;
|
|
6152
|
+
}
|
|
6153
|
+
return this.#invalidateUser(connectionId);
|
|
6154
|
+
});
|
|
5980
6155
|
}
|
|
5981
6156
|
/**
|
|
5982
6157
|
* Patches the presence data for an existing "other". If we don't know the
|
|
@@ -5984,38 +6159,18 @@ var OthersRef = class extends ImmutableRef {
|
|
|
5984
6159
|
* full .setOther() call first.
|
|
5985
6160
|
*/
|
|
5986
6161
|
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
|
-
}
|
|
6162
|
+
this.#internal.mutate((state) => {
|
|
6163
|
+
const oldPresence = state.presences.get(connectionId);
|
|
6164
|
+
if (oldPresence === void 0) {
|
|
6165
|
+
return false;
|
|
6166
|
+
}
|
|
6167
|
+
const newPresence = merge(oldPresence, patch);
|
|
6168
|
+
if (oldPresence === newPresence) {
|
|
6169
|
+
return false;
|
|
6170
|
+
}
|
|
6171
|
+
state.presences.set(connectionId, freeze(newPresence));
|
|
6172
|
+
return this.#invalidateUser(connectionId);
|
|
6173
|
+
});
|
|
6019
6174
|
}
|
|
6020
6175
|
};
|
|
6021
6176
|
|
|
@@ -6092,10 +6247,10 @@ function createRoom(options, config) {
|
|
|
6092
6247
|
messages: [],
|
|
6093
6248
|
storageOperations: []
|
|
6094
6249
|
},
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
myPresence: new
|
|
6098
|
-
others: new
|
|
6250
|
+
staticSessionInfoSig: new Signal(null),
|
|
6251
|
+
dynamicSessionInfoSig: new Signal(null),
|
|
6252
|
+
myPresence: new PatchableSignal(initialPresence),
|
|
6253
|
+
others: new ManagedOthers(),
|
|
6099
6254
|
initialStorage,
|
|
6100
6255
|
idFactory: null,
|
|
6101
6256
|
// The Yjs provider associated to this room
|
|
@@ -6114,8 +6269,25 @@ function createRoom(options, config) {
|
|
|
6114
6269
|
// Debug
|
|
6115
6270
|
opStackTraces: process.env.NODE_ENV !== "production" ? /* @__PURE__ */ new Map() : void 0
|
|
6116
6271
|
};
|
|
6117
|
-
|
|
6118
|
-
|
|
6272
|
+
function printPending(cs) {
|
|
6273
|
+
if (cs) globalThis.console.log(`[debug] at ${cs}`);
|
|
6274
|
+
if (context.unacknowledgedOps.size === 0) {
|
|
6275
|
+
globalThis.console.log("[debug] no pending ops");
|
|
6276
|
+
} else {
|
|
6277
|
+
globalThis.console.log(
|
|
6278
|
+
`[debug] pending ops (${context.unacknowledgedOps.size}):`
|
|
6279
|
+
);
|
|
6280
|
+
for (const [opId, op] of context.unacknowledgedOps) {
|
|
6281
|
+
globalThis.console.log(
|
|
6282
|
+
"[debug] opid=",
|
|
6283
|
+
opId,
|
|
6284
|
+
"op=",
|
|
6285
|
+
JSON.stringify(op)
|
|
6286
|
+
);
|
|
6287
|
+
}
|
|
6288
|
+
}
|
|
6289
|
+
globalThis.console.log("[debug] storage status", getStorageStatus());
|
|
6290
|
+
}
|
|
6119
6291
|
let lastTokenKey;
|
|
6120
6292
|
function onStatusDidChange(newStatus) {
|
|
6121
6293
|
const authValue = managedSocket.authValue;
|
|
@@ -6125,46 +6297,38 @@ function createRoom(options, config) {
|
|
|
6125
6297
|
lastTokenKey = tokenKey;
|
|
6126
6298
|
if (authValue.type === "secret") {
|
|
6127
6299
|
const token = authValue.token.parsed;
|
|
6128
|
-
context.
|
|
6300
|
+
context.staticSessionInfoSig.set({
|
|
6129
6301
|
userId: token.k === "sec-legacy" /* SECRET_LEGACY */ ? token.id : token.uid,
|
|
6130
6302
|
userInfo: token.k === "sec-legacy" /* SECRET_LEGACY */ ? token.info : token.ui
|
|
6131
6303
|
});
|
|
6132
6304
|
} else {
|
|
6133
|
-
context.
|
|
6305
|
+
context.staticSessionInfoSig.set({
|
|
6134
6306
|
userId: void 0,
|
|
6135
6307
|
userInfo: void 0
|
|
6136
6308
|
});
|
|
6137
6309
|
}
|
|
6138
6310
|
}
|
|
6139
6311
|
}
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
notifySelfChanged(doNotBatchUpdates);
|
|
6143
|
-
});
|
|
6312
|
+
eventHub.status.notify(newStatus);
|
|
6313
|
+
notifySelfChanged();
|
|
6144
6314
|
}
|
|
6145
6315
|
let _connectionLossTimerId;
|
|
6146
6316
|
let _hasLostConnection = false;
|
|
6147
6317
|
function handleConnectionLossEvent(newStatus) {
|
|
6148
6318
|
if (newStatus === "reconnecting") {
|
|
6149
6319
|
_connectionLossTimerId = setTimeout(() => {
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
notify({ others: [{ type: "reset" }] }, doNotBatchUpdates);
|
|
6155
|
-
});
|
|
6320
|
+
eventHub.lostConnection.notify("lost");
|
|
6321
|
+
_hasLostConnection = true;
|
|
6322
|
+
context.others.clearOthers();
|
|
6323
|
+
notify({ others: [{ type: "reset" }] });
|
|
6156
6324
|
}, config.lostConnectionTimeout);
|
|
6157
6325
|
} else {
|
|
6158
6326
|
clearTimeout(_connectionLossTimerId);
|
|
6159
6327
|
if (_hasLostConnection) {
|
|
6160
6328
|
if (newStatus === "disconnected") {
|
|
6161
|
-
|
|
6162
|
-
eventHub.lostConnection.notify("failed");
|
|
6163
|
-
});
|
|
6329
|
+
eventHub.lostConnection.notify("failed");
|
|
6164
6330
|
} else {
|
|
6165
|
-
|
|
6166
|
-
eventHub.lostConnection.notify("restored");
|
|
6167
|
-
});
|
|
6331
|
+
eventHub.lostConnection.notify("restored");
|
|
6168
6332
|
}
|
|
6169
6333
|
_hasLostConnection = false;
|
|
6170
6334
|
}
|
|
@@ -6177,7 +6341,7 @@ function createRoom(options, config) {
|
|
|
6177
6341
|
// Because context.me.current is a readonly object, we'll have to
|
|
6178
6342
|
// make a copy here. Otherwise, type errors happen later when
|
|
6179
6343
|
// "patching" my presence.
|
|
6180
|
-
{ ...context.myPresence.
|
|
6344
|
+
{ ...context.myPresence.get() }
|
|
6181
6345
|
)
|
|
6182
6346
|
};
|
|
6183
6347
|
if (_getStorage$ !== null) {
|
|
@@ -6194,14 +6358,12 @@ function createRoom(options, config) {
|
|
|
6194
6358
|
managedSocket.events.didConnect.subscribe(onDidConnect);
|
|
6195
6359
|
managedSocket.events.didDisconnect.subscribe(onDidDisconnect);
|
|
6196
6360
|
managedSocket.events.onLiveblocksError.subscribe((err) => {
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
eventHub.error.notify(err);
|
|
6204
|
-
});
|
|
6361
|
+
if (process.env.NODE_ENV !== "production") {
|
|
6362
|
+
error2(
|
|
6363
|
+
`Connection to websocket server closed. Reason: ${err.message} (code: ${err.code}).`
|
|
6364
|
+
);
|
|
6365
|
+
}
|
|
6366
|
+
eventHub.error.notify(err);
|
|
6205
6367
|
});
|
|
6206
6368
|
const pool = {
|
|
6207
6369
|
roomId: config.roomId,
|
|
@@ -6237,16 +6399,14 @@ function createRoom(options, config) {
|
|
|
6237
6399
|
}
|
|
6238
6400
|
activeBatch.reverseOps.unshift(...reverse);
|
|
6239
6401
|
} else {
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
notify({ storageUpdates }, doNotBatchUpdates);
|
|
6245
|
-
});
|
|
6402
|
+
addToUndoStack(reverse);
|
|
6403
|
+
context.redoStack.length = 0;
|
|
6404
|
+
dispatchOps(ops);
|
|
6405
|
+
notify({ storageUpdates });
|
|
6246
6406
|
}
|
|
6247
6407
|
},
|
|
6248
6408
|
assertStorageIsWritable: () => {
|
|
6249
|
-
const scopes = context.
|
|
6409
|
+
const scopes = context.dynamicSessionInfoSig.get()?.scopes;
|
|
6250
6410
|
if (scopes === void 0) {
|
|
6251
6411
|
return;
|
|
6252
6412
|
}
|
|
@@ -6302,7 +6462,7 @@ function createRoom(options, config) {
|
|
|
6302
6462
|
}
|
|
6303
6463
|
function sendMessages(messages) {
|
|
6304
6464
|
const serializedPayload = JSON.stringify(messages);
|
|
6305
|
-
const nonce = context.
|
|
6465
|
+
const nonce = context.dynamicSessionInfoSig.get()?.nonce;
|
|
6306
6466
|
if (config.unstable_fallbackToHTTP && nonce) {
|
|
6307
6467
|
const size = new TextEncoder().encode(serializedPayload).length;
|
|
6308
6468
|
if (size > MAX_SOCKET_MESSAGE_SIZE) {
|
|
@@ -6319,9 +6479,9 @@ function createRoom(options, config) {
|
|
|
6319
6479
|
}
|
|
6320
6480
|
managedSocket.send(serializedPayload);
|
|
6321
6481
|
}
|
|
6322
|
-
const self =
|
|
6323
|
-
context.
|
|
6324
|
-
context.
|
|
6482
|
+
const self = DerivedSignal.from(
|
|
6483
|
+
context.staticSessionInfoSig,
|
|
6484
|
+
context.dynamicSessionInfoSig,
|
|
6325
6485
|
context.myPresence,
|
|
6326
6486
|
(staticSession, dynamicSession, myPresence) => {
|
|
6327
6487
|
if (staticSession === null || dynamicSession === null) {
|
|
@@ -6340,29 +6500,27 @@ function createRoom(options, config) {
|
|
|
6340
6500
|
}
|
|
6341
6501
|
);
|
|
6342
6502
|
let _lastSelf;
|
|
6343
|
-
function notifySelfChanged(
|
|
6344
|
-
const currSelf = self.
|
|
6503
|
+
function notifySelfChanged() {
|
|
6504
|
+
const currSelf = self.get();
|
|
6345
6505
|
if (currSelf !== null && currSelf !== _lastSelf) {
|
|
6346
|
-
|
|
6347
|
-
eventHub.self.notify(currSelf);
|
|
6348
|
-
});
|
|
6506
|
+
eventHub.self.notify(currSelf);
|
|
6349
6507
|
_lastSelf = currSelf;
|
|
6350
6508
|
}
|
|
6351
6509
|
}
|
|
6352
|
-
const selfAsTreeNode =
|
|
6510
|
+
const selfAsTreeNode = DerivedSignal.from(
|
|
6353
6511
|
self,
|
|
6354
6512
|
(me) => me !== null ? userToTreeNode("Me", me) : null
|
|
6355
6513
|
);
|
|
6356
|
-
function createOrUpdateRootFromMessage(message
|
|
6514
|
+
function createOrUpdateRootFromMessage(message) {
|
|
6357
6515
|
if (message.items.length === 0) {
|
|
6358
6516
|
throw new Error("Internal error: cannot load storage without items");
|
|
6359
6517
|
}
|
|
6360
6518
|
if (context.root !== void 0) {
|
|
6361
|
-
updateRoot(message.items
|
|
6519
|
+
updateRoot(message.items);
|
|
6362
6520
|
} else {
|
|
6363
6521
|
context.root = LiveObject._fromItems(message.items, pool);
|
|
6364
6522
|
}
|
|
6365
|
-
const canWrite = self.
|
|
6523
|
+
const canWrite = self.get()?.canWrite ?? true;
|
|
6366
6524
|
const stackSizeBefore = context.undoStack.length;
|
|
6367
6525
|
for (const key in context.initialStorage) {
|
|
6368
6526
|
if (context.root.get(key) === void 0) {
|
|
@@ -6377,7 +6535,7 @@ function createRoom(options, config) {
|
|
|
6377
6535
|
}
|
|
6378
6536
|
context.undoStack.length = stackSizeBefore;
|
|
6379
6537
|
}
|
|
6380
|
-
function updateRoot(items
|
|
6538
|
+
function updateRoot(items) {
|
|
6381
6539
|
if (context.root === void 0) {
|
|
6382
6540
|
return;
|
|
6383
6541
|
}
|
|
@@ -6387,45 +6545,43 @@ function createRoom(options, config) {
|
|
|
6387
6545
|
}
|
|
6388
6546
|
const ops = getTreesDiffOperations(currentItems, new Map(items));
|
|
6389
6547
|
const result = applyOps(ops, false);
|
|
6390
|
-
notify(result.updates
|
|
6548
|
+
notify(result.updates);
|
|
6391
6549
|
}
|
|
6392
|
-
function _addToRealUndoStack(historyOps
|
|
6550
|
+
function _addToRealUndoStack(historyOps) {
|
|
6393
6551
|
if (context.undoStack.length >= 50) {
|
|
6394
6552
|
context.undoStack.shift();
|
|
6395
6553
|
}
|
|
6396
6554
|
context.undoStack.push(historyOps);
|
|
6397
|
-
onHistoryChange(
|
|
6555
|
+
onHistoryChange();
|
|
6398
6556
|
}
|
|
6399
|
-
function addToUndoStack(historyOps
|
|
6557
|
+
function addToUndoStack(historyOps) {
|
|
6400
6558
|
if (context.pausedHistory !== null) {
|
|
6401
6559
|
context.pausedHistory.unshift(...historyOps);
|
|
6402
6560
|
} else {
|
|
6403
|
-
_addToRealUndoStack(historyOps
|
|
6561
|
+
_addToRealUndoStack(historyOps);
|
|
6404
6562
|
}
|
|
6405
6563
|
}
|
|
6406
|
-
function notify(updates
|
|
6564
|
+
function notify(updates) {
|
|
6407
6565
|
const storageUpdates = updates.storageUpdates;
|
|
6408
6566
|
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);
|
|
6567
|
+
if (othersUpdates !== void 0 && othersUpdates.length > 0) {
|
|
6568
|
+
const others = context.others.get();
|
|
6569
|
+
for (const event of othersUpdates) {
|
|
6570
|
+
eventHub.others.notify({ ...event, others });
|
|
6419
6571
|
}
|
|
6420
|
-
|
|
6421
|
-
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6572
|
+
}
|
|
6573
|
+
if (updates.presence ?? false) {
|
|
6574
|
+
notifySelfChanged();
|
|
6575
|
+
eventHub.myPresence.notify(context.myPresence.get());
|
|
6576
|
+
}
|
|
6577
|
+
if (storageUpdates !== void 0 && storageUpdates.size > 0) {
|
|
6578
|
+
const updates2 = Array.from(storageUpdates.values());
|
|
6579
|
+
eventHub.storageBatch.notify(updates2);
|
|
6580
|
+
}
|
|
6581
|
+
notifyStorageStatus();
|
|
6426
6582
|
}
|
|
6427
6583
|
function getConnectionId() {
|
|
6428
|
-
const info = context.
|
|
6584
|
+
const info = context.dynamicSessionInfoSig.get();
|
|
6429
6585
|
if (info) {
|
|
6430
6586
|
return info.actor;
|
|
6431
6587
|
}
|
|
@@ -6434,6 +6590,7 @@ function createRoom(options, config) {
|
|
|
6434
6590
|
);
|
|
6435
6591
|
}
|
|
6436
6592
|
function applyOps(rawOps, isLocal) {
|
|
6593
|
+
printPending("start of applyOps");
|
|
6437
6594
|
const output = {
|
|
6438
6595
|
reverse: [],
|
|
6439
6596
|
storageUpdates: /* @__PURE__ */ new Map(),
|
|
@@ -6454,7 +6611,7 @@ function createRoom(options, config) {
|
|
|
6454
6611
|
data: {}
|
|
6455
6612
|
};
|
|
6456
6613
|
for (const key in op.data) {
|
|
6457
|
-
reverse.data[key] = context.myPresence.
|
|
6614
|
+
reverse.data[key] = context.myPresence.get()[key];
|
|
6458
6615
|
}
|
|
6459
6616
|
context.myPresence.patch(op.data);
|
|
6460
6617
|
if (context.buffer.presenceUpdates === null) {
|
|
@@ -6476,6 +6633,9 @@ function createRoom(options, config) {
|
|
|
6476
6633
|
nn(context.opStackTraces).delete(opId);
|
|
6477
6634
|
}
|
|
6478
6635
|
const deleted = context.unacknowledgedOps.delete(opId);
|
|
6636
|
+
if (deleted) {
|
|
6637
|
+
globalThis.console.log("[debug] acked", opId);
|
|
6638
|
+
}
|
|
6479
6639
|
source = deleted ? 2 /* ACK */ : 1 /* REMOTE */;
|
|
6480
6640
|
}
|
|
6481
6641
|
const applyOpResult = applyOp(op, source);
|
|
@@ -6497,6 +6657,7 @@ function createRoom(options, config) {
|
|
|
6497
6657
|
}
|
|
6498
6658
|
}
|
|
6499
6659
|
}
|
|
6660
|
+
printPending("end of applyOps");
|
|
6500
6661
|
return {
|
|
6501
6662
|
ops,
|
|
6502
6663
|
reverse: output.reverse,
|
|
@@ -6563,7 +6724,7 @@ function createRoom(options, config) {
|
|
|
6563
6724
|
continue;
|
|
6564
6725
|
}
|
|
6565
6726
|
context.buffer.presenceUpdates.data[key] = overrideValue;
|
|
6566
|
-
oldValues[key] = context.myPresence.
|
|
6727
|
+
oldValues[key] = context.myPresence.get()[key];
|
|
6567
6728
|
}
|
|
6568
6729
|
context.myPresence.patch(patch);
|
|
6569
6730
|
if (context.activeBatch) {
|
|
@@ -6576,15 +6737,10 @@ function createRoom(options, config) {
|
|
|
6576
6737
|
context.activeBatch.updates.presence = true;
|
|
6577
6738
|
} else {
|
|
6578
6739
|
flushNowOrSoon();
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
doNotBatchUpdates
|
|
6584
|
-
);
|
|
6585
|
-
}
|
|
6586
|
-
notify({ presence: true }, doNotBatchUpdates);
|
|
6587
|
-
});
|
|
6740
|
+
if (options2?.addToHistory) {
|
|
6741
|
+
addToUndoStack([{ type: "presence", data: oldValues }]);
|
|
6742
|
+
}
|
|
6743
|
+
notify({ presence: true });
|
|
6588
6744
|
}
|
|
6589
6745
|
}
|
|
6590
6746
|
function onUpdatePresenceMessage(message) {
|
|
@@ -6617,14 +6773,14 @@ function createRoom(options, config) {
|
|
|
6617
6773
|
}
|
|
6618
6774
|
return null;
|
|
6619
6775
|
}
|
|
6620
|
-
function onRoomStateMessage(message
|
|
6621
|
-
context.
|
|
6776
|
+
function onRoomStateMessage(message) {
|
|
6777
|
+
context.dynamicSessionInfoSig.set({
|
|
6622
6778
|
actor: message.actor,
|
|
6623
6779
|
nonce: message.nonce,
|
|
6624
6780
|
scopes: message.scopes
|
|
6625
6781
|
});
|
|
6626
6782
|
context.idFactory = makeIdFactory(message.actor);
|
|
6627
|
-
notifySelfChanged(
|
|
6783
|
+
notifySelfChanged();
|
|
6628
6784
|
for (const connectionId of context.others.connectionIds()) {
|
|
6629
6785
|
const user = message.users[connectionId];
|
|
6630
6786
|
if (user === void 0) {
|
|
@@ -6649,10 +6805,8 @@ function createRoom(options, config) {
|
|
|
6649
6805
|
function canRedo() {
|
|
6650
6806
|
return context.redoStack.length > 0;
|
|
6651
6807
|
}
|
|
6652
|
-
function onHistoryChange(
|
|
6653
|
-
|
|
6654
|
-
eventHub.history.notify({ canUndo: canUndo(), canRedo: canRedo() });
|
|
6655
|
-
});
|
|
6808
|
+
function onHistoryChange() {
|
|
6809
|
+
eventHub.history.notify({ canUndo: canUndo(), canRedo: canRedo() });
|
|
6656
6810
|
}
|
|
6657
6811
|
function onUserJoinedMessage(message) {
|
|
6658
6812
|
context.others.setConnection(
|
|
@@ -6663,7 +6817,7 @@ function createRoom(options, config) {
|
|
|
6663
6817
|
);
|
|
6664
6818
|
context.buffer.messages.push({
|
|
6665
6819
|
type: 100 /* UPDATE_PRESENCE */,
|
|
6666
|
-
data: context.myPresence.
|
|
6820
|
+
data: context.myPresence.get(),
|
|
6667
6821
|
targetActor: message.actor
|
|
6668
6822
|
});
|
|
6669
6823
|
flushNowOrSoon();
|
|
@@ -6686,7 +6840,7 @@ function createRoom(options, config) {
|
|
|
6686
6840
|
return compact([parseServerMessage(data)]);
|
|
6687
6841
|
}
|
|
6688
6842
|
}
|
|
6689
|
-
function applyAndSendOps(offlineOps
|
|
6843
|
+
function applyAndSendOps(offlineOps) {
|
|
6690
6844
|
if (offlineOps.size === 0) {
|
|
6691
6845
|
return;
|
|
6692
6846
|
}
|
|
@@ -6697,7 +6851,7 @@ function createRoom(options, config) {
|
|
|
6697
6851
|
type: 201 /* UPDATE_STORAGE */,
|
|
6698
6852
|
ops: result.ops
|
|
6699
6853
|
});
|
|
6700
|
-
notify(result.updates
|
|
6854
|
+
notify(result.updates);
|
|
6701
6855
|
sendMessages(messages);
|
|
6702
6856
|
}
|
|
6703
6857
|
function handleServerMessage(event) {
|
|
@@ -6712,104 +6866,102 @@ function createRoom(options, config) {
|
|
|
6712
6866
|
storageUpdates: /* @__PURE__ */ new Map(),
|
|
6713
6867
|
others: []
|
|
6714
6868
|
};
|
|
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;
|
|
6869
|
+
for (const message of messages) {
|
|
6870
|
+
switch (message.type) {
|
|
6871
|
+
case 101 /* USER_JOINED */: {
|
|
6872
|
+
const userJoinedUpdate = onUserJoinedMessage(message);
|
|
6873
|
+
if (userJoinedUpdate) {
|
|
6874
|
+
updates.others.push(userJoinedUpdate);
|
|
6740
6875
|
}
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
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;
|
|
6755
|
-
}
|
|
6756
|
-
case 200 /* INITIAL_STORAGE_STATE */: {
|
|
6757
|
-
processInitialStorage(message);
|
|
6758
|
-
break;
|
|
6876
|
+
break;
|
|
6877
|
+
}
|
|
6878
|
+
case 100 /* UPDATE_PRESENCE */: {
|
|
6879
|
+
const othersPresenceUpdate = onUpdatePresenceMessage(message);
|
|
6880
|
+
if (othersPresenceUpdate) {
|
|
6881
|
+
updates.others.push(othersPresenceUpdate);
|
|
6759
6882
|
}
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6883
|
+
break;
|
|
6884
|
+
}
|
|
6885
|
+
case 103 /* BROADCASTED_EVENT */: {
|
|
6886
|
+
const others = context.others.get();
|
|
6887
|
+
eventHub.customEvent.notify({
|
|
6888
|
+
connectionId: message.actor,
|
|
6889
|
+
user: message.actor < 0 ? null : others.find((u) => u.connectionId === message.actor) ?? null,
|
|
6890
|
+
event: message.event
|
|
6891
|
+
});
|
|
6892
|
+
break;
|
|
6893
|
+
}
|
|
6894
|
+
case 102 /* USER_LEFT */: {
|
|
6895
|
+
const event2 = onUserLeftMessage(message);
|
|
6896
|
+
if (event2) {
|
|
6897
|
+
updates.others.push(event2);
|
|
6769
6898
|
}
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6899
|
+
break;
|
|
6900
|
+
}
|
|
6901
|
+
case 300 /* UPDATE_YDOC */: {
|
|
6902
|
+
eventHub.ydoc.notify(message);
|
|
6903
|
+
break;
|
|
6904
|
+
}
|
|
6905
|
+
case 104 /* ROOM_STATE */: {
|
|
6906
|
+
updates.others.push(onRoomStateMessage(message));
|
|
6907
|
+
break;
|
|
6908
|
+
}
|
|
6909
|
+
case 200 /* INITIAL_STORAGE_STATE */: {
|
|
6910
|
+
processInitialStorage(message);
|
|
6911
|
+
break;
|
|
6912
|
+
}
|
|
6913
|
+
case 201 /* UPDATE_STORAGE */: {
|
|
6914
|
+
const applyResult = applyOps(message.ops, false);
|
|
6915
|
+
for (const [key, value] of applyResult.updates.storageUpdates) {
|
|
6916
|
+
updates.storageUpdates.set(
|
|
6917
|
+
key,
|
|
6918
|
+
mergeStorageUpdates(updates.storageUpdates.get(key), value)
|
|
6774
6919
|
);
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
|
|
6920
|
+
}
|
|
6921
|
+
break;
|
|
6922
|
+
}
|
|
6923
|
+
case 299 /* REJECT_STORAGE_OP */: {
|
|
6924
|
+
errorWithTitle(
|
|
6925
|
+
"Storage mutation rejection error",
|
|
6926
|
+
message.reason
|
|
6927
|
+
);
|
|
6928
|
+
if (process.env.NODE_ENV !== "production") {
|
|
6929
|
+
const traces = /* @__PURE__ */ new Set();
|
|
6930
|
+
for (const opId of message.opIds) {
|
|
6931
|
+
const trace = context.opStackTraces?.get(opId);
|
|
6932
|
+
if (trace) {
|
|
6933
|
+
traces.add(trace);
|
|
6782
6934
|
}
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6935
|
+
}
|
|
6936
|
+
if (traces.size > 0) {
|
|
6937
|
+
warnWithTitle(
|
|
6938
|
+
"The following function calls caused the rejected storage mutations:",
|
|
6939
|
+
`
|
|
6787
6940
|
|
|
6788
6941
|
${Array.from(traces).join("\n\n")}`
|
|
6789
|
-
);
|
|
6790
|
-
}
|
|
6791
|
-
throw new Error(
|
|
6792
|
-
`Storage mutations rejected by server: ${message.reason}`
|
|
6793
6942
|
);
|
|
6794
6943
|
}
|
|
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;
|
|
6944
|
+
throw new Error(
|
|
6945
|
+
`Storage mutations rejected by server: ${message.reason}`
|
|
6946
|
+
);
|
|
6808
6947
|
}
|
|
6948
|
+
break;
|
|
6949
|
+
}
|
|
6950
|
+
case 400 /* THREAD_CREATED */:
|
|
6951
|
+
case 407 /* THREAD_DELETED */:
|
|
6952
|
+
case 401 /* THREAD_METADATA_UPDATED */:
|
|
6953
|
+
case 408 /* THREAD_UPDATED */:
|
|
6954
|
+
case 405 /* COMMENT_REACTION_ADDED */:
|
|
6955
|
+
case 406 /* COMMENT_REACTION_REMOVED */:
|
|
6956
|
+
case 402 /* COMMENT_CREATED */:
|
|
6957
|
+
case 403 /* COMMENT_EDITED */:
|
|
6958
|
+
case 404 /* COMMENT_DELETED */: {
|
|
6959
|
+
eventHub.comments.notify(message);
|
|
6960
|
+
break;
|
|
6809
6961
|
}
|
|
6810
6962
|
}
|
|
6811
|
-
|
|
6812
|
-
|
|
6963
|
+
}
|
|
6964
|
+
notify(updates);
|
|
6813
6965
|
}
|
|
6814
6966
|
function flushNowOrSoon() {
|
|
6815
6967
|
const storageOps = context.buffer.storageOperations;
|
|
@@ -6817,6 +6969,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6817
6969
|
for (const op of storageOps) {
|
|
6818
6970
|
context.unacknowledgedOps.set(nn(op.opId), op);
|
|
6819
6971
|
}
|
|
6972
|
+
printPending("flushNowOrSoon");
|
|
6820
6973
|
notifyStorageStatus();
|
|
6821
6974
|
}
|
|
6822
6975
|
if (managedSocket.getStatus() !== "connected") {
|
|
@@ -6906,9 +7059,10 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6906
7059
|
let _getStorage$ = null;
|
|
6907
7060
|
let _resolveStoragePromise = null;
|
|
6908
7061
|
function processInitialStorage(message) {
|
|
7062
|
+
printPending("initial local ops");
|
|
6909
7063
|
const unacknowledgedOps = new Map(context.unacknowledgedOps);
|
|
6910
|
-
createOrUpdateRootFromMessage(message
|
|
6911
|
-
applyAndSendOps(unacknowledgedOps
|
|
7064
|
+
createOrUpdateRootFromMessage(message);
|
|
7065
|
+
applyAndSendOps(unacknowledgedOps);
|
|
6912
7066
|
_resolveStoragePromise?.();
|
|
6913
7067
|
notifyStorageStatus();
|
|
6914
7068
|
eventHub.storageDidLoad.notify();
|
|
@@ -6981,11 +7135,9 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6981
7135
|
}
|
|
6982
7136
|
context.pausedHistory = null;
|
|
6983
7137
|
const result = applyOps(historyOps, true);
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
onHistoryChange(doNotBatchUpdates);
|
|
6988
|
-
});
|
|
7138
|
+
notify(result.updates);
|
|
7139
|
+
context.redoStack.push(result.reverse);
|
|
7140
|
+
onHistoryChange();
|
|
6989
7141
|
for (const op of result.ops) {
|
|
6990
7142
|
if (op.type !== "presence") {
|
|
6991
7143
|
context.buffer.storageOperations.push(op);
|
|
@@ -7003,11 +7155,9 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7003
7155
|
}
|
|
7004
7156
|
context.pausedHistory = null;
|
|
7005
7157
|
const result = applyOps(historyOps, true);
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
onHistoryChange(doNotBatchUpdates);
|
|
7010
|
-
});
|
|
7158
|
+
notify(result.updates);
|
|
7159
|
+
context.undoStack.push(result.reverse);
|
|
7160
|
+
onHistoryChange();
|
|
7011
7161
|
for (const op of result.ops) {
|
|
7012
7162
|
if (op.type !== "presence") {
|
|
7013
7163
|
context.buffer.storageOperations.push(op);
|
|
@@ -7019,39 +7169,37 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7019
7169
|
context.undoStack.length = 0;
|
|
7020
7170
|
context.redoStack.length = 0;
|
|
7021
7171
|
}
|
|
7022
|
-
function
|
|
7172
|
+
function batch2(callback) {
|
|
7023
7173
|
if (context.activeBatch) {
|
|
7024
7174
|
return callback();
|
|
7025
7175
|
}
|
|
7026
7176
|
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();
|
|
7177
|
+
context.activeBatch = {
|
|
7178
|
+
ops: [],
|
|
7179
|
+
updates: {
|
|
7180
|
+
storageUpdates: /* @__PURE__ */ new Map(),
|
|
7181
|
+
presence: false,
|
|
7182
|
+
others: []
|
|
7183
|
+
},
|
|
7184
|
+
reverseOps: []
|
|
7185
|
+
};
|
|
7186
|
+
try {
|
|
7187
|
+
returnValue = callback();
|
|
7188
|
+
} finally {
|
|
7189
|
+
const currentBatch = context.activeBatch;
|
|
7190
|
+
context.activeBatch = null;
|
|
7191
|
+
if (currentBatch.reverseOps.length > 0) {
|
|
7192
|
+
addToUndoStack(currentBatch.reverseOps);
|
|
7053
7193
|
}
|
|
7054
|
-
|
|
7194
|
+
if (currentBatch.ops.length > 0) {
|
|
7195
|
+
context.redoStack.length = 0;
|
|
7196
|
+
}
|
|
7197
|
+
if (currentBatch.ops.length > 0) {
|
|
7198
|
+
dispatchOps(currentBatch.ops);
|
|
7199
|
+
}
|
|
7200
|
+
notify(currentBatch.updates);
|
|
7201
|
+
flushNowOrSoon();
|
|
7202
|
+
}
|
|
7055
7203
|
return returnValue;
|
|
7056
7204
|
}
|
|
7057
7205
|
function pauseHistory() {
|
|
@@ -7063,7 +7211,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7063
7211
|
const historyOps = context.pausedHistory;
|
|
7064
7212
|
context.pausedHistory = null;
|
|
7065
7213
|
if (historyOps !== null && historyOps.length > 0) {
|
|
7066
|
-
_addToRealUndoStack(historyOps
|
|
7214
|
+
_addToRealUndoStack(historyOps);
|
|
7067
7215
|
}
|
|
7068
7216
|
}
|
|
7069
7217
|
const syncSourceForStorage = config.createSyncSource();
|
|
@@ -7086,7 +7234,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7086
7234
|
);
|
|
7087
7235
|
}
|
|
7088
7236
|
function isPresenceReady() {
|
|
7089
|
-
return self.
|
|
7237
|
+
return self.get() !== null;
|
|
7090
7238
|
}
|
|
7091
7239
|
async function waitUntilPresenceReady() {
|
|
7092
7240
|
while (!isPresenceReady()) {
|
|
@@ -7106,8 +7254,8 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7106
7254
|
await getStorage();
|
|
7107
7255
|
}
|
|
7108
7256
|
}
|
|
7109
|
-
const others_forDevTools =
|
|
7110
|
-
context.others,
|
|
7257
|
+
const others_forDevTools = DerivedSignal.from(
|
|
7258
|
+
context.others.signal,
|
|
7111
7259
|
(others) => others.map((other, index) => userToTreeNode(`Other ${index}`, other))
|
|
7112
7260
|
);
|
|
7113
7261
|
const events = {
|
|
@@ -7297,8 +7445,8 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7297
7445
|
// create a version
|
|
7298
7446
|
createTextVersion,
|
|
7299
7447
|
// Support for the Liveblocks browser extension
|
|
7300
|
-
getSelf_forDevTools: () => selfAsTreeNode.
|
|
7301
|
-
getOthers_forDevTools: () => others_forDevTools.
|
|
7448
|
+
getSelf_forDevTools: () => selfAsTreeNode.get(),
|
|
7449
|
+
getOthers_forDevTools: () => others_forDevTools.get(),
|
|
7302
7450
|
// prettier-ignore
|
|
7303
7451
|
simulate: {
|
|
7304
7452
|
// These exist only for our E2E testing app
|
|
@@ -7324,7 +7472,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7324
7472
|
updateYDoc,
|
|
7325
7473
|
broadcastEvent,
|
|
7326
7474
|
// Storage
|
|
7327
|
-
batch,
|
|
7475
|
+
batch: batch2,
|
|
7328
7476
|
history: {
|
|
7329
7477
|
undo,
|
|
7330
7478
|
redo,
|
|
@@ -7345,10 +7493,10 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7345
7493
|
events,
|
|
7346
7494
|
// Core
|
|
7347
7495
|
getStatus: () => managedSocket.getStatus(),
|
|
7348
|
-
getSelf: () => self.
|
|
7496
|
+
getSelf: () => self.get(),
|
|
7349
7497
|
// Presence
|
|
7350
|
-
getPresence: () => context.myPresence.
|
|
7351
|
-
getOthers: () => context.others.
|
|
7498
|
+
getPresence: () => context.myPresence.get(),
|
|
7499
|
+
getOthers: () => context.others.get(),
|
|
7352
7500
|
// Comments
|
|
7353
7501
|
getThreads,
|
|
7354
7502
|
getThreadsSince,
|
|
@@ -7526,10 +7674,10 @@ function createClient(options) {
|
|
|
7526
7674
|
clientOptions.backgroundKeepAliveTimeout
|
|
7527
7675
|
);
|
|
7528
7676
|
const baseUrl = getBaseUrl(clientOptions.baseUrl);
|
|
7529
|
-
const
|
|
7677
|
+
const currentUserId = new Signal(void 0);
|
|
7530
7678
|
const authManager = createAuthManager(options, (token) => {
|
|
7531
7679
|
const userId = token.k === "sec-legacy" /* SECRET_LEGACY */ ? token.id : token.uid;
|
|
7532
|
-
|
|
7680
|
+
currentUserId.set(() => userId);
|
|
7533
7681
|
});
|
|
7534
7682
|
const fetchPolyfill = clientOptions.polyfills?.fetch || /* istanbul ignore next */
|
|
7535
7683
|
globalThis.fetch?.bind(globalThis);
|
|
@@ -7588,7 +7736,6 @@ function createClient(options) {
|
|
|
7588
7736
|
authenticate: makeAuthDelegateForRoom(roomId, authManager)
|
|
7589
7737
|
},
|
|
7590
7738
|
enableDebugLogging: clientOptions.enableDebugLogging,
|
|
7591
|
-
unstable_batchedUpdates: options2?.unstable_batchedUpdates,
|
|
7592
7739
|
baseUrl,
|
|
7593
7740
|
unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP,
|
|
7594
7741
|
unstable_streamData: !!clientOptions.unstable_streamData,
|
|
@@ -7623,7 +7770,7 @@ function createClient(options) {
|
|
|
7623
7770
|
}
|
|
7624
7771
|
function logout() {
|
|
7625
7772
|
authManager.reset();
|
|
7626
|
-
|
|
7773
|
+
currentUserId.set(() => void 0);
|
|
7627
7774
|
for (const { room } of roomsById.values()) {
|
|
7628
7775
|
if (!isIdle(room.getStatus())) {
|
|
7629
7776
|
room.reconnect();
|
|
@@ -7671,20 +7818,20 @@ function createClient(options) {
|
|
|
7671
7818
|
mentionSuggestionsCache.clear();
|
|
7672
7819
|
}
|
|
7673
7820
|
const syncStatusSources = [];
|
|
7674
|
-
const
|
|
7821
|
+
const syncStatusSignal = new Signal("synchronized");
|
|
7675
7822
|
function getSyncStatus() {
|
|
7676
|
-
const status =
|
|
7823
|
+
const status = syncStatusSignal.get();
|
|
7677
7824
|
return status === "synchronizing" ? status : "synchronized";
|
|
7678
7825
|
}
|
|
7679
7826
|
function recompute() {
|
|
7680
|
-
|
|
7681
|
-
syncStatusSources.some((src) => src.
|
|
7827
|
+
syncStatusSignal.set(
|
|
7828
|
+
syncStatusSources.some((src) => src.get() === "synchronizing") ? "synchronizing" : syncStatusSources.some((src) => src.get() === "has-local-changes") ? "has-local-changes" : "synchronized"
|
|
7682
7829
|
);
|
|
7683
7830
|
}
|
|
7684
7831
|
function createSyncSource() {
|
|
7685
|
-
const source = new
|
|
7832
|
+
const source = new Signal("synchronized");
|
|
7686
7833
|
syncStatusSources.push(source);
|
|
7687
|
-
const unsub = source.
|
|
7834
|
+
const unsub = source.subscribe(() => recompute());
|
|
7688
7835
|
function setSyncStatus(status) {
|
|
7689
7836
|
source.set(status);
|
|
7690
7837
|
}
|
|
@@ -7693,7 +7840,7 @@ function createClient(options) {
|
|
|
7693
7840
|
const index = syncStatusSources.findIndex((item) => item === source);
|
|
7694
7841
|
if (index > -1) {
|
|
7695
7842
|
const [ref] = syncStatusSources.splice(index, 1);
|
|
7696
|
-
const wasStillPending = ref.
|
|
7843
|
+
const wasStillPending = ref.get() !== "synchronized";
|
|
7697
7844
|
if (wasStillPending) {
|
|
7698
7845
|
recompute();
|
|
7699
7846
|
}
|
|
@@ -7703,7 +7850,7 @@ function createClient(options) {
|
|
|
7703
7850
|
}
|
|
7704
7851
|
{
|
|
7705
7852
|
const maybePreventClose = (e) => {
|
|
7706
|
-
if (clientOptions.preventUnsavedChanges &&
|
|
7853
|
+
if (clientOptions.preventUnsavedChanges && syncStatusSignal.get() !== "synchronized") {
|
|
7707
7854
|
e.preventDefault();
|
|
7708
7855
|
}
|
|
7709
7856
|
};
|
|
@@ -7731,11 +7878,11 @@ function createClient(options) {
|
|
|
7731
7878
|
},
|
|
7732
7879
|
getSyncStatus,
|
|
7733
7880
|
events: {
|
|
7734
|
-
syncStatus:
|
|
7881
|
+
syncStatus: syncStatusSignal
|
|
7735
7882
|
},
|
|
7736
7883
|
// Internal
|
|
7737
7884
|
[kInternal]: {
|
|
7738
|
-
|
|
7885
|
+
currentUserId,
|
|
7739
7886
|
mentionSuggestionsCache,
|
|
7740
7887
|
resolveMentionSuggestions: clientOptions.resolveMentionSuggestions,
|
|
7741
7888
|
usersStore,
|
|
@@ -7909,13 +8056,15 @@ function escapeHtml(value) {
|
|
|
7909
8056
|
);
|
|
7910
8057
|
}
|
|
7911
8058
|
var HtmlSafeString = class {
|
|
8059
|
+
#strings;
|
|
8060
|
+
#values;
|
|
7912
8061
|
constructor(strings, values) {
|
|
7913
|
-
this
|
|
7914
|
-
this
|
|
8062
|
+
this.#strings = strings;
|
|
8063
|
+
this.#values = values;
|
|
7915
8064
|
}
|
|
7916
8065
|
toString() {
|
|
7917
|
-
return this.
|
|
7918
|
-
return result + escapeHtml(nn(this
|
|
8066
|
+
return this.#strings.reduce((result, str, i) => {
|
|
8067
|
+
return result + escapeHtml(nn(this.#values[i - 1])) + str;
|
|
7919
8068
|
});
|
|
7920
8069
|
}
|
|
7921
8070
|
};
|
|
@@ -7963,13 +8112,15 @@ function escapeMarkdown(value) {
|
|
|
7963
8112
|
);
|
|
7964
8113
|
}
|
|
7965
8114
|
var MarkdownSafeString = class {
|
|
8115
|
+
#strings;
|
|
8116
|
+
#values;
|
|
7966
8117
|
constructor(strings, values) {
|
|
7967
|
-
this
|
|
7968
|
-
this
|
|
8118
|
+
this.#strings = strings;
|
|
8119
|
+
this.#values = values;
|
|
7969
8120
|
}
|
|
7970
8121
|
toString() {
|
|
7971
|
-
return this.
|
|
7972
|
-
return result + escapeMarkdown(nn(this
|
|
8122
|
+
return this.#strings.reduce((result, str, i) => {
|
|
8123
|
+
return result + escapeMarkdown(nn(this.#values[i - 1])) + str;
|
|
7973
8124
|
});
|
|
7974
8125
|
}
|
|
7975
8126
|
};
|
|
@@ -8642,9 +8793,11 @@ function bisectRight(arr, x, lt) {
|
|
|
8642
8793
|
return lo;
|
|
8643
8794
|
}
|
|
8644
8795
|
var SortedList = class _SortedList {
|
|
8796
|
+
#data;
|
|
8797
|
+
#lt;
|
|
8645
8798
|
constructor(alreadySortedList, lt) {
|
|
8646
|
-
this
|
|
8647
|
-
this
|
|
8799
|
+
this.#lt = lt;
|
|
8800
|
+
this.#data = alreadySortedList;
|
|
8648
8801
|
}
|
|
8649
8802
|
static from(arr, lt) {
|
|
8650
8803
|
const sorted = new _SortedList([], lt);
|
|
@@ -8660,14 +8813,14 @@ var SortedList = class _SortedList {
|
|
|
8660
8813
|
* Clones the sorted list to a new instance.
|
|
8661
8814
|
*/
|
|
8662
8815
|
clone() {
|
|
8663
|
-
return new _SortedList(this.
|
|
8816
|
+
return new _SortedList(this.#data.slice(), this.#lt);
|
|
8664
8817
|
}
|
|
8665
8818
|
/**
|
|
8666
8819
|
* Adds a new item to the sorted list, such that it remains sorted.
|
|
8667
8820
|
*/
|
|
8668
8821
|
add(value) {
|
|
8669
|
-
const idx = bisectRight(this
|
|
8670
|
-
this.
|
|
8822
|
+
const idx = bisectRight(this.#data, value, this.#lt);
|
|
8823
|
+
this.#data.splice(idx, 0, value);
|
|
8671
8824
|
}
|
|
8672
8825
|
/**
|
|
8673
8826
|
* Removes the given value from the sorted list, if it exists. The given
|
|
@@ -8675,25 +8828,25 @@ var SortedList = class _SortedList {
|
|
|
8675
8828
|
* removed if the element exists in the sorted list multiple times.
|
|
8676
8829
|
*/
|
|
8677
8830
|
remove(value) {
|
|
8678
|
-
const idx = this.
|
|
8831
|
+
const idx = this.#data.indexOf(value);
|
|
8679
8832
|
if (idx >= 0) {
|
|
8680
|
-
this.
|
|
8833
|
+
this.#data.splice(idx, 1);
|
|
8681
8834
|
return true;
|
|
8682
8835
|
}
|
|
8683
8836
|
return false;
|
|
8684
8837
|
}
|
|
8685
8838
|
get length() {
|
|
8686
|
-
return this.
|
|
8839
|
+
return this.#data.length;
|
|
8687
8840
|
}
|
|
8688
8841
|
*filter(predicate) {
|
|
8689
|
-
for (const item of this
|
|
8842
|
+
for (const item of this.#data) {
|
|
8690
8843
|
if (predicate(item)) {
|
|
8691
8844
|
yield item;
|
|
8692
8845
|
}
|
|
8693
8846
|
}
|
|
8694
8847
|
}
|
|
8695
8848
|
[Symbol.iterator]() {
|
|
8696
|
-
return this
|
|
8849
|
+
return this.#data[Symbol.iterator]();
|
|
8697
8850
|
}
|
|
8698
8851
|
};
|
|
8699
8852
|
|
|
@@ -8712,15 +8865,18 @@ export {
|
|
|
8712
8865
|
ClientMsgCode,
|
|
8713
8866
|
CommentsApiError,
|
|
8714
8867
|
CrdtType,
|
|
8868
|
+
DerivedSignal,
|
|
8715
8869
|
HttpError,
|
|
8716
8870
|
LiveList,
|
|
8717
8871
|
LiveMap,
|
|
8718
8872
|
LiveObject,
|
|
8873
|
+
MutableSignal,
|
|
8719
8874
|
NotificationsApiError,
|
|
8720
8875
|
OpCode,
|
|
8721
8876
|
Permission,
|
|
8722
8877
|
Promise_withResolvers,
|
|
8723
8878
|
ServerMsgCode,
|
|
8879
|
+
Signal,
|
|
8724
8880
|
SortedList,
|
|
8725
8881
|
TextEditorType,
|
|
8726
8882
|
WebsocketCloseCodes,
|
|
@@ -8730,6 +8886,7 @@ export {
|
|
|
8730
8886
|
assertNever,
|
|
8731
8887
|
autoRetry,
|
|
8732
8888
|
b64decode,
|
|
8889
|
+
batch,
|
|
8733
8890
|
chunk,
|
|
8734
8891
|
cloneLson,
|
|
8735
8892
|
compactObject,
|
|
@@ -8742,7 +8899,6 @@ export {
|
|
|
8742
8899
|
createCommentAttachmentId,
|
|
8743
8900
|
createCommentId,
|
|
8744
8901
|
createInboxNotificationId,
|
|
8745
|
-
createStore,
|
|
8746
8902
|
createThreadId,
|
|
8747
8903
|
deprecate,
|
|
8748
8904
|
deprecateIf,
|