@liveblocks/server 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,3285 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var __defProp = Object.defineProperty;
2
+ var __typeError = (msg) => {
3
+ throw TypeError(msg);
4
+ };
5
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
7
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
8
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
9
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
10
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
11
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
12
+
13
+ // ../../node_modules/@liveblocks/core/dist/index.js
14
+ var __defProp2 = Object.defineProperty;
15
+ var __export = (target, all) => {
16
+ for (var name in all)
17
+ __defProp2(target, name, { get: all[name], enumerable: true });
18
+ };
19
+ var PKG_NAME = "@liveblocks/core";
20
+ var PKG_VERSION = "3.14.0-pre5";
21
+ var PKG_FORMAT = "esm";
22
+ var g = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {};
23
+ var crossLinkedDocs = "https://liveblocks.io/docs/errors/cross-linked";
24
+ var dupesDocs = "https://liveblocks.io/docs/errors/dupes";
25
+ var SPACE = " ";
26
+ function error(msg) {
27
+ if (process.env.NODE_ENV === "production") {
28
+ console.error(msg);
29
+ } else {
30
+ throw new Error(msg);
31
+ }
32
+ }
33
+ function detectDupes(pkgName, pkgVersion, pkgFormat) {
34
+ const pkgId = Symbol.for(pkgName);
35
+ const pkgBuildInfo = pkgFormat ? `${pkgVersion || "dev"} (${pkgFormat})` : pkgVersion || "dev";
36
+ if (!g[pkgId]) {
37
+ g[pkgId] = pkgBuildInfo;
38
+ } else if (g[pkgId] === pkgBuildInfo) {
39
+ } else {
40
+ const msg = [
41
+ `Multiple copies of Liveblocks are being loaded in your project. This will cause issues! See ${dupesDocs + SPACE}`,
42
+ "",
43
+ "Conflicts:",
44
+ `- ${pkgName} ${g[pkgId]} (already loaded)`,
45
+ `- ${pkgName} ${pkgBuildInfo} (trying to load this now)`
46
+ ].join("\n");
47
+ error(msg);
48
+ }
49
+ if (pkgVersion && PKG_VERSION && pkgVersion !== PKG_VERSION) {
50
+ error(
51
+ [
52
+ `Cross-linked versions of Liveblocks found, which will cause issues! See ${crossLinkedDocs + SPACE}`,
53
+ "",
54
+ "Conflicts:",
55
+ `- ${PKG_NAME} is at ${PKG_VERSION}`,
56
+ `- ${pkgName} is at ${pkgVersion}`,
57
+ "",
58
+ "Always upgrade all Liveblocks packages to the same version number."
59
+ ].join("\n")
60
+ );
61
+ }
62
+ }
63
+ function makeEventSource() {
64
+ const _observers = /* @__PURE__ */ new Set();
65
+ function subscribe(callback) {
66
+ _observers.add(callback);
67
+ return () => _observers.delete(callback);
68
+ }
69
+ function subscribeOnce(callback) {
70
+ const unsub = subscribe((event) => {
71
+ unsub();
72
+ return callback(event);
73
+ });
74
+ return unsub;
75
+ }
76
+ async function waitUntil(predicate) {
77
+ let unsub;
78
+ return new Promise((res) => {
79
+ unsub = subscribe((event) => {
80
+ if (predicate === void 0 || predicate(event)) {
81
+ res(event);
82
+ }
83
+ });
84
+ }).finally(() => _optionalChain([unsub, 'optionalCall', _2 => _2()]));
85
+ }
86
+ function notify(event) {
87
+ let called = false;
88
+ for (const callback of _observers) {
89
+ callback(event);
90
+ called = true;
91
+ }
92
+ return called;
93
+ }
94
+ function count() {
95
+ return _observers.size;
96
+ }
97
+ return {
98
+ // Private/internal control over event emission
99
+ notify,
100
+ subscribe,
101
+ subscribeOnce,
102
+ count,
103
+ waitUntil,
104
+ dispose() {
105
+ _observers.clear();
106
+ },
107
+ // Publicly exposable subscription API
108
+ observable: {
109
+ subscribe,
110
+ subscribeOnce,
111
+ waitUntil
112
+ }
113
+ };
114
+ }
115
+ var freeze = process.env.NODE_ENV === "production" ? (
116
+ /* istanbul ignore next */
117
+ (x) => x
118
+ ) : Object.freeze;
119
+ function raise(msg) {
120
+ throw new Error(msg);
121
+ }
122
+ function tryParseJson(rawMessage) {
123
+ try {
124
+ return JSON.parse(rawMessage);
125
+ } catch (e) {
126
+ return void 0;
127
+ }
128
+ }
129
+ var kSinks = Symbol("kSinks");
130
+ var kTrigger = Symbol("kTrigger");
131
+ var signalsToTrigger = null;
132
+ var trackedReads = null;
133
+ function enqueueTrigger(signal) {
134
+ if (!signalsToTrigger) raise("Expected to be in an active batch");
135
+ signalsToTrigger.add(signal);
136
+ }
137
+ var _a, _eventSource, _b;
138
+ var AbstractSignal = (_b = class {
139
+ constructor(equals) {
140
+ /** @internal */
141
+ __publicField(this, "equals");
142
+ __privateAdd(this, _eventSource);
143
+ /** @internal */
144
+ __publicField(this, _a);
145
+ this.equals = _nullishCoalesce(equals, () => ( Object.is));
146
+ __privateSet(this, _eventSource, makeEventSource());
147
+ this[kSinks] = /* @__PURE__ */ new Set();
148
+ this.get = this.get.bind(this);
149
+ this.subscribe = this.subscribe.bind(this);
150
+ this.subscribeOnce = this.subscribeOnce.bind(this);
151
+ }
152
+ dispose() {
153
+ __privateGet(this, _eventSource).dispose();
154
+ __privateSet(this, _eventSource, "(disposed)");
155
+ this.equals = "(disposed)";
156
+ }
157
+ get hasWatchers() {
158
+ if (__privateGet(this, _eventSource).count() > 0) return true;
159
+ for (const sink of this[kSinks]) {
160
+ if (sink.hasWatchers) {
161
+ return true;
162
+ }
163
+ }
164
+ return false;
165
+ }
166
+ [(_a = kSinks, kTrigger)]() {
167
+ __privateGet(this, _eventSource).notify();
168
+ for (const sink of this[kSinks]) {
169
+ enqueueTrigger(sink);
170
+ }
171
+ }
172
+ subscribe(callback) {
173
+ if (__privateGet(this, _eventSource).count() === 0) {
174
+ this.get();
175
+ }
176
+ return __privateGet(this, _eventSource).subscribe(callback);
177
+ }
178
+ subscribeOnce(callback) {
179
+ const unsub = this.subscribe(() => {
180
+ unsub();
181
+ return callback();
182
+ });
183
+ return unsub;
184
+ }
185
+ waitUntil() {
186
+ throw new Error("waitUntil not supported on Signals");
187
+ }
188
+ markSinksDirty() {
189
+ for (const sink of this[kSinks]) {
190
+ sink.markDirty();
191
+ }
192
+ }
193
+ addSink(sink) {
194
+ this[kSinks].add(sink);
195
+ }
196
+ removeSink(sink) {
197
+ this[kSinks].delete(sink);
198
+ }
199
+ asReadonly() {
200
+ return this;
201
+ }
202
+ }, _eventSource = new WeakMap(), _b);
203
+ var INITIAL = Symbol();
204
+ var _prevValue, _dirty, _sources, _deps, _transform, __DerivedSignal_instances, recompute_fn, _a2;
205
+ var DerivedSignal = (_a2 = class extends AbstractSignal {
206
+ constructor(deps, transform, equals) {
207
+ super(equals);
208
+ __privateAdd(this, __DerivedSignal_instances);
209
+ __privateAdd(this, _prevValue);
210
+ __privateAdd(this, _dirty);
211
+ // When true, the value in #value may not be up-to-date and needs re-checking
212
+ __privateAdd(this, _sources);
213
+ __privateAdd(this, _deps);
214
+ __privateAdd(this, _transform);
215
+ __privateSet(this, _dirty, true);
216
+ __privateSet(this, _prevValue, INITIAL);
217
+ __privateSet(this, _deps, deps);
218
+ __privateSet(this, _sources, /* @__PURE__ */ new Set());
219
+ __privateSet(this, _transform, transform);
220
+ }
221
+ // prettier-ignore
222
+ static from(...args) {
223
+ const last = args.pop();
224
+ if (typeof last !== "function")
225
+ raise("Invalid .from() call, last argument expected to be a function");
226
+ if (typeof args[args.length - 1] === "function") {
227
+ const equals = last;
228
+ const transform = args.pop();
229
+ return new _a2(args, transform, equals);
230
+ } else {
231
+ const transform = last;
232
+ return new _a2(args, transform);
233
+ }
234
+ }
235
+ dispose() {
236
+ for (const src of __privateGet(this, _sources)) {
237
+ src.removeSink(this);
238
+ }
239
+ __privateSet(this, _prevValue, "(disposed)");
240
+ __privateSet(this, _sources, "(disposed)");
241
+ __privateSet(this, _deps, "(disposed)");
242
+ __privateSet(this, _transform, "(disposed)");
243
+ }
244
+ get isDirty() {
245
+ return __privateGet(this, _dirty);
246
+ }
247
+ markDirty() {
248
+ if (!__privateGet(this, _dirty)) {
249
+ __privateSet(this, _dirty, true);
250
+ this.markSinksDirty();
251
+ }
252
+ }
253
+ get() {
254
+ if (__privateGet(this, _dirty)) {
255
+ __privateMethod(this, __DerivedSignal_instances, recompute_fn).call(this);
256
+ }
257
+ _optionalChain([trackedReads, 'optionalAccess', _3 => _3.add, 'call', _4 => _4(this)]);
258
+ return __privateGet(this, _prevValue);
259
+ }
260
+ /**
261
+ * Called by the Signal system if one or more of the dependent signals have
262
+ * changed. In the case of a DerivedSignal, we'll only want to re-evaluate
263
+ * the actual value if it's being watched, or any of their sinks are being
264
+ * watched actively.
265
+ */
266
+ [kTrigger]() {
267
+ if (!this.hasWatchers) {
268
+ return;
269
+ }
270
+ const updated = __privateMethod(this, __DerivedSignal_instances, recompute_fn).call(this);
271
+ if (updated) {
272
+ super[kTrigger]();
273
+ }
274
+ }
275
+ }, _prevValue = new WeakMap(), _dirty = new WeakMap(), _sources = new WeakMap(), _deps = new WeakMap(), _transform = new WeakMap(), __DerivedSignal_instances = new WeakSet(), recompute_fn = function() {
276
+ const oldTrackedReads = trackedReads;
277
+ let derived;
278
+ trackedReads = /* @__PURE__ */ new Set();
279
+ try {
280
+ derived = __privateGet(this, _transform).call(this, ...__privateGet(this, _deps).map((p) => p.get()));
281
+ } finally {
282
+ const oldSources = __privateGet(this, _sources);
283
+ __privateSet(this, _sources, /* @__PURE__ */ new Set());
284
+ for (const sig of trackedReads) {
285
+ __privateGet(this, _sources).add(sig);
286
+ oldSources.delete(sig);
287
+ }
288
+ for (const oldSource of oldSources) {
289
+ oldSource.removeSink(this);
290
+ }
291
+ for (const newSource of __privateGet(this, _sources)) {
292
+ newSource.addSink(this);
293
+ }
294
+ trackedReads = oldTrackedReads;
295
+ }
296
+ __privateSet(this, _dirty, false);
297
+ if (!this.equals(__privateGet(this, _prevValue), derived)) {
298
+ __privateSet(this, _prevValue, derived);
299
+ return true;
300
+ }
301
+ return false;
302
+ }, _a2);
303
+ function assertNever(_value, errmsg) {
304
+ throw new Error(errmsg);
305
+ }
306
+ function assert(condition, errmsg) {
307
+ if (process.env.NODE_ENV !== "production") {
308
+ if (!condition) {
309
+ const err = new Error(errmsg);
310
+ err.name = "Assertion failure";
311
+ throw err;
312
+ }
313
+ }
314
+ }
315
+ function nn(value, errmsg = "Expected value to be non-nullable") {
316
+ assert(value !== null && value !== void 0, errmsg);
317
+ return value;
318
+ }
319
+ var fancy_console_exports = {};
320
+ __export(fancy_console_exports, {
321
+ error: () => error2,
322
+ errorWithTitle: () => errorWithTitle,
323
+ warn: () => warn,
324
+ warnWithTitle: () => warnWithTitle
325
+ });
326
+ var badge = "background:#0e0d12;border-radius:9999px;color:#fff;padding:3px 7px;font-family:sans-serif;font-weight:600;";
327
+ var bold = "font-weight:600";
328
+ function wrap(method) {
329
+ return typeof window === "undefined" || process.env.NODE_ENV === "test" ? console[method] : (
330
+ /* istanbul ignore next */
331
+ (message, ...args) => console[method]("%cLiveblocks", badge, message, ...args)
332
+ );
333
+ }
334
+ var warn = wrap("warn");
335
+ var error2 = wrap("error");
336
+ function wrapWithTitle(method) {
337
+ return typeof window === "undefined" || process.env.NODE_ENV === "test" ? console[method] : (
338
+ /* istanbul ignore next */
339
+ (title, message, ...args) => console[method](
340
+ `%cLiveblocks%c ${title}`,
341
+ badge,
342
+ bold,
343
+ message,
344
+ ...args
345
+ )
346
+ );
347
+ }
348
+ var warnWithTitle = wrapWithTitle("warn");
349
+ var errorWithTitle = wrapWithTitle("error");
350
+ var _defaultFn, _a3;
351
+ var DefaultMap = (_a3 = class extends Map {
352
+ /**
353
+ * If the default function is not provided to the constructor, it has to be
354
+ * provided in each .getOrCreate() call individually.
355
+ */
356
+ constructor(defaultFn, entries2) {
357
+ super(entries2);
358
+ __privateAdd(this, _defaultFn);
359
+ __privateSet(this, _defaultFn, defaultFn);
360
+ }
361
+ /**
362
+ * Gets the value at the given key, or creates it.
363
+ *
364
+ * Difference from normal Map: if the key does not exist, it will be created
365
+ * on the fly using the factory function, and that value will get returned
366
+ * instead of `undefined`.
367
+ */
368
+ getOrCreate(key, defaultFn) {
369
+ if (super.has(key)) {
370
+ return super.get(key);
371
+ } else {
372
+ const fn = _nullishCoalesce(_nullishCoalesce(defaultFn, () => ( __privateGet(this, _defaultFn))), () => ( raise("DefaultMap used without a factory function")));
373
+ const value = fn(key);
374
+ this.set(key, value);
375
+ return value;
376
+ }
377
+ }
378
+ }, _defaultFn = new WeakMap(), _a3);
379
+ var ServerMsgCode = Object.freeze({
380
+ // For Presence
381
+ UPDATE_PRESENCE: 100,
382
+ USER_JOINED: 101,
383
+ USER_LEFT: 102,
384
+ BROADCASTED_EVENT: 103,
385
+ ROOM_STATE: 104,
386
+ // For Storage
387
+ STORAGE_STATE_V7: 200,
388
+ // Only sent in V7
389
+ STORAGE_CHUNK: 210,
390
+ // Used in V8+
391
+ STORAGE_STREAM_END: 211,
392
+ // Used in V8+
393
+ UPDATE_STORAGE: 201,
394
+ // For Yjs Docs
395
+ UPDATE_YDOC: 300,
396
+ // For Comments
397
+ THREAD_CREATED: 400,
398
+ THREAD_DELETED: 407,
399
+ THREAD_METADATA_UPDATED: 401,
400
+ THREAD_UPDATED: 408,
401
+ COMMENT_CREATED: 402,
402
+ COMMENT_EDITED: 403,
403
+ COMMENT_DELETED: 404,
404
+ COMMENT_REACTION_ADDED: 405,
405
+ COMMENT_REACTION_REMOVED: 406,
406
+ COMMENT_METADATA_UPDATED: 409,
407
+ // Error codes
408
+ REJECT_STORAGE_OP: 299
409
+ // Sent if a mutation was not allowed on the server (i.e. due to permissions, limit exceeded, etc)
410
+ });
411
+ var WebsocketCloseCodes = /* @__PURE__ */ ((WebsocketCloseCodes2) => {
412
+ WebsocketCloseCodes2[WebsocketCloseCodes2["CLOSE_NORMAL"] = 1e3] = "CLOSE_NORMAL";
413
+ WebsocketCloseCodes2[WebsocketCloseCodes2["CLOSE_ABNORMAL"] = 1006] = "CLOSE_ABNORMAL";
414
+ WebsocketCloseCodes2[WebsocketCloseCodes2["UNEXPECTED_CONDITION"] = 1011] = "UNEXPECTED_CONDITION";
415
+ WebsocketCloseCodes2[WebsocketCloseCodes2["TRY_AGAIN_LATER"] = 1013] = "TRY_AGAIN_LATER";
416
+ WebsocketCloseCodes2[WebsocketCloseCodes2["INVALID_MESSAGE_FORMAT"] = 4e3] = "INVALID_MESSAGE_FORMAT";
417
+ WebsocketCloseCodes2[WebsocketCloseCodes2["NOT_ALLOWED"] = 4001] = "NOT_ALLOWED";
418
+ WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_MESSAGES_PER_SECONDS"] = 4002] = "MAX_NUMBER_OF_MESSAGES_PER_SECONDS";
419
+ WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_CONCURRENT_CONNECTIONS"] = 4003] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS";
420
+ WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP"] = 4004] = "MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP";
421
+ WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM"] = 4005] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM";
422
+ WebsocketCloseCodes2[WebsocketCloseCodes2["ROOM_ID_UPDATED"] = 4006] = "ROOM_ID_UPDATED";
423
+ WebsocketCloseCodes2[WebsocketCloseCodes2["KICKED"] = 4100] = "KICKED";
424
+ WebsocketCloseCodes2[WebsocketCloseCodes2["TOKEN_EXPIRED"] = 4109] = "TOKEN_EXPIRED";
425
+ WebsocketCloseCodes2[WebsocketCloseCodes2["CLOSE_WITHOUT_RETRY"] = 4999] = "CLOSE_WITHOUT_RETRY";
426
+ return WebsocketCloseCodes2;
427
+ })(WebsocketCloseCodes || {});
428
+ var BACKOFF_DELAYS = [250, 500, 1e3, 2e3, 4e3, 8e3, 1e4];
429
+ var RESET_DELAY = BACKOFF_DELAYS[0] - 1;
430
+ function log(level, message) {
431
+ const logger = level === 2 ? error2 : level === 1 ? warn : (
432
+ /* black hole */
433
+ () => {
434
+ }
435
+ );
436
+ return () => {
437
+ logger(message);
438
+ };
439
+ }
440
+ var logPermanentClose = log(
441
+ 1,
442
+ "Connection to WebSocket closed permanently. Won't retry."
443
+ );
444
+ var kInternal = Symbol();
445
+ var EMPTY_OBJECT = Object.freeze({});
446
+ var NULL_KEYWORD_CHARS = Array.from(new Set("null"));
447
+ var TRUE_KEYWORD_CHARS = Array.from(new Set("true"));
448
+ var FALSE_KEYWORD_CHARS = Array.from(new Set("false"));
449
+ var ALL_KEYWORD_CHARS = Array.from(new Set("nulltruefalse"));
450
+ var kWILDCARD = Symbol("*");
451
+ var eventSource = makeEventSource();
452
+ if (process.env.NODE_ENV !== "production" && typeof window !== "undefined") {
453
+ window.addEventListener("message", (event) => {
454
+ if (event.source === window && _optionalChain([event, 'access', _5 => _5.data, 'optionalAccess', _6 => _6.source]) === "liveblocks-devtools-panel") {
455
+ eventSource.notify(event.data);
456
+ } else {
457
+ }
458
+ });
459
+ }
460
+ var onMessageFromPanel = eventSource.observable;
461
+ var loadedAt = Date.now();
462
+ var kPlain = Symbol("notification-settings-plain");
463
+ var MIN_CODE = 32;
464
+ var MAX_CODE = 126;
465
+ var NUM_DIGITS = MAX_CODE - MIN_CODE + 1;
466
+ var ZERO = nthDigit(0);
467
+ var ONE = nthDigit(1);
468
+ var ZERO_NINE = ZERO + nthDigit(-1);
469
+ function nthDigit(n) {
470
+ const code = MIN_CODE + (n < 0 ? NUM_DIGITS + n : n);
471
+ if (code < MIN_CODE || code > MAX_CODE) {
472
+ throw new Error(`Invalid n value: ${n}`);
473
+ }
474
+ return String.fromCharCode(code);
475
+ }
476
+ function makePosition(x, y) {
477
+ if (x !== void 0 && y !== void 0) {
478
+ return between(x, y);
479
+ } else if (x !== void 0) {
480
+ return after(x);
481
+ } else if (y !== void 0) {
482
+ return before(y);
483
+ } else {
484
+ return ONE;
485
+ }
486
+ }
487
+ function before(pos) {
488
+ const lastIndex = pos.length - 1;
489
+ for (let i = 0; i <= lastIndex; i++) {
490
+ const code = pos.charCodeAt(i);
491
+ if (code <= MIN_CODE) {
492
+ continue;
493
+ }
494
+ if (i === lastIndex) {
495
+ if (code === MIN_CODE + 1) {
496
+ return pos.substring(0, i) + ZERO_NINE;
497
+ } else {
498
+ return pos.substring(0, i) + String.fromCharCode(code - 1);
499
+ }
500
+ } else {
501
+ return pos.substring(0, i + 1);
502
+ }
503
+ }
504
+ return ONE;
505
+ }
506
+ var VIEWPORT_START = 2;
507
+ var VIEWPORT_STEP = 3;
508
+ function after(pos) {
509
+ for (let i = 0; i < pos.length; i++) {
510
+ const code = pos.charCodeAt(i);
511
+ if (code < MIN_CODE || code > MAX_CODE) {
512
+ return pos + ONE;
513
+ }
514
+ }
515
+ while (pos.length > 1 && pos.charCodeAt(pos.length - 1) === MIN_CODE) {
516
+ pos = pos.slice(0, -1);
517
+ }
518
+ if (pos.length === 0 || pos === ZERO) {
519
+ return ONE;
520
+ }
521
+ let viewport = VIEWPORT_START;
522
+ if (pos.length > VIEWPORT_START) {
523
+ viewport = VIEWPORT_START + Math.ceil((pos.length - VIEWPORT_START) / VIEWPORT_STEP) * VIEWPORT_STEP;
524
+ }
525
+ const result = incrementWithinViewport(pos, viewport);
526
+ if (result !== null) {
527
+ return result;
528
+ }
529
+ viewport += VIEWPORT_STEP;
530
+ const extendedResult = incrementWithinViewport(pos, viewport);
531
+ if (extendedResult !== null) {
532
+ return extendedResult;
533
+ }
534
+ return pos + ONE;
535
+ }
536
+ function incrementWithinViewport(pos, viewport) {
537
+ const digits = [];
538
+ for (let i = 0; i < viewport; i++) {
539
+ if (i < pos.length) {
540
+ digits.push(pos.charCodeAt(i) - MIN_CODE);
541
+ } else {
542
+ digits.push(0);
543
+ }
544
+ }
545
+ let carry = 1;
546
+ for (let i = viewport - 1; i >= 0 && carry; i--) {
547
+ const sum = digits[i] + carry;
548
+ if (sum >= NUM_DIGITS) {
549
+ digits[i] = 0;
550
+ carry = 1;
551
+ } else {
552
+ digits[i] = sum;
553
+ carry = 0;
554
+ }
555
+ }
556
+ if (carry) {
557
+ return null;
558
+ }
559
+ let result = "";
560
+ for (const d of digits) {
561
+ result += String.fromCharCode(d + MIN_CODE);
562
+ }
563
+ while (result.length > 1 && result.charCodeAt(result.length - 1) === MIN_CODE) {
564
+ result = result.slice(0, -1);
565
+ }
566
+ return result;
567
+ }
568
+ function between(lo, hi) {
569
+ if (lo < hi) {
570
+ return _between(lo, hi);
571
+ } else if (lo > hi) {
572
+ return _between(hi, lo);
573
+ } else {
574
+ throw new Error("Cannot compute value between two equal positions");
575
+ }
576
+ }
577
+ function _between(lo, hi) {
578
+ let index = 0;
579
+ const loLen = lo.length;
580
+ const hiLen = hi.length;
581
+ while (true) {
582
+ const loCode = index < loLen ? lo.charCodeAt(index) : MIN_CODE;
583
+ const hiCode = index < hiLen ? hi.charCodeAt(index) : MAX_CODE;
584
+ if (loCode === hiCode) {
585
+ index++;
586
+ continue;
587
+ }
588
+ if (hiCode - loCode === 1) {
589
+ const size = index + 1;
590
+ let prefix = lo.substring(0, size);
591
+ if (prefix.length < size) {
592
+ prefix += ZERO.repeat(size - prefix.length);
593
+ }
594
+ const suffix = lo.substring(size);
595
+ const nines = "";
596
+ return prefix + _between(suffix, nines);
597
+ } else {
598
+ return takeN(lo, index) + String.fromCharCode(hiCode + loCode >> 1);
599
+ }
600
+ }
601
+ }
602
+ function takeN(pos, n) {
603
+ return n < pos.length ? pos.substring(0, n) : pos + ZERO.repeat(n - pos.length);
604
+ }
605
+ var MIN_NON_ZERO_CODE = MIN_CODE + 1;
606
+ function isPos(str) {
607
+ if (str === "") {
608
+ return false;
609
+ }
610
+ const lastIdx = str.length - 1;
611
+ const last = str.charCodeAt(lastIdx);
612
+ if (last < MIN_NON_ZERO_CODE || last > MAX_CODE) {
613
+ return false;
614
+ }
615
+ for (let i = 0; i < lastIdx; i++) {
616
+ const code = str.charCodeAt(i);
617
+ if (code < MIN_CODE || code > MAX_CODE) {
618
+ return false;
619
+ }
620
+ }
621
+ return true;
622
+ }
623
+ function convertToPos(str) {
624
+ const codes = [];
625
+ for (let i = 0; i < str.length; i++) {
626
+ const code = str.charCodeAt(i);
627
+ codes.push(code < MIN_CODE ? MIN_CODE : code > MAX_CODE ? MAX_CODE : code);
628
+ }
629
+ while (codes.length > 0 && codes[codes.length - 1] === MIN_CODE) {
630
+ codes.length--;
631
+ }
632
+ return codes.length > 0 ? String.fromCharCode(...codes) : (
633
+ // Edge case: the str was a 0-only string, which is invalid. Default back to .1
634
+ ONE
635
+ );
636
+ }
637
+ function asPos(str) {
638
+ return isPos(str) ? str : convertToPos(str);
639
+ }
640
+ var OpCode = Object.freeze({
641
+ INIT: 0,
642
+ SET_PARENT_KEY: 1,
643
+ CREATE_LIST: 2,
644
+ UPDATE_OBJECT: 3,
645
+ CREATE_OBJECT: 4,
646
+ DELETE_CRDT: 5,
647
+ DELETE_OBJECT_KEY: 6,
648
+ CREATE_MAP: 7,
649
+ CREATE_REGISTER: 8
650
+ });
651
+ var NoParent = Object.freeze({ type: "NoParent" });
652
+ var CrdtType = Object.freeze({
653
+ OBJECT: 0,
654
+ LIST: 1,
655
+ MAP: 2,
656
+ REGISTER: 3
657
+ });
658
+ function isRootStorageNode(node) {
659
+ return node[0] === "root";
660
+ }
661
+ function isObjectStorageNode(node) {
662
+ return node[1].type === CrdtType.OBJECT;
663
+ }
664
+ function isListStorageNode(node) {
665
+ return node[1].type === CrdtType.LIST;
666
+ }
667
+ function isMapStorageNode(node) {
668
+ return node[1].type === CrdtType.MAP;
669
+ }
670
+ function isRegisterStorageNode(node) {
671
+ return node[1].type === CrdtType.REGISTER;
672
+ }
673
+ function* nodeStreamToCompactNodes(nodes) {
674
+ for (const node of nodes) {
675
+ if (isObjectStorageNode(node)) {
676
+ if (isRootStorageNode(node)) {
677
+ const id = node[0];
678
+ const crdt = node[1];
679
+ yield [id, crdt.data];
680
+ } else {
681
+ const id = node[0];
682
+ const crdt = node[1];
683
+ yield [id, CrdtType.OBJECT, crdt.parentId, crdt.parentKey, crdt.data];
684
+ }
685
+ } else if (isListStorageNode(node)) {
686
+ const id = node[0];
687
+ const crdt = node[1];
688
+ yield [id, CrdtType.LIST, crdt.parentId, crdt.parentKey];
689
+ } else if (isMapStorageNode(node)) {
690
+ const id = node[0];
691
+ const crdt = node[1];
692
+ yield [id, CrdtType.MAP, crdt.parentId, crdt.parentKey];
693
+ } else if (isRegisterStorageNode(node)) {
694
+ const id = node[0];
695
+ const crdt = node[1];
696
+ yield [id, CrdtType.REGISTER, crdt.parentId, crdt.parentKey, crdt.data];
697
+ } else {
698
+ }
699
+ }
700
+ }
701
+ var MAX_LIVE_OBJECT_SIZE = 128 * 1024;
702
+ function isJsonScalar(data) {
703
+ return data === null || typeof data === "string" || typeof data === "number" || typeof data === "boolean";
704
+ }
705
+ function isJsonArray(data) {
706
+ return Array.isArray(data);
707
+ }
708
+ function isJsonObject(data) {
709
+ return !isJsonScalar(data) && !isJsonArray(data);
710
+ }
711
+ var ClientMsgCode = Object.freeze({
712
+ // For Presence
713
+ UPDATE_PRESENCE: 100,
714
+ BROADCAST_EVENT: 103,
715
+ // For Storage
716
+ FETCH_STORAGE: 200,
717
+ UPDATE_STORAGE: 201,
718
+ // For Yjs support
719
+ FETCH_YDOC: 300,
720
+ UPDATE_YDOC: 301
721
+ });
722
+ var MAX_SOCKET_MESSAGE_SIZE = 1024 * 1024 - 512;
723
+ var htmlEscapables = {
724
+ "&": "&amp;",
725
+ "<": "&lt;",
726
+ ">": "&gt;",
727
+ '"': "&quot;",
728
+ "'": "&#39;"
729
+ };
730
+ var htmlEscapablesRegex = new RegExp(
731
+ Object.keys(htmlEscapables).map((entity) => `\\${entity}`).join("|"),
732
+ "g"
733
+ );
734
+ var markdownEscapables = {
735
+ _: "\\_",
736
+ "*": "\\*",
737
+ "#": "\\#",
738
+ "`": "\\`",
739
+ "~": "\\~",
740
+ "!": "\\!",
741
+ "|": "\\|",
742
+ "(": "\\(",
743
+ ")": "\\)",
744
+ "{": "\\{",
745
+ "}": "\\}",
746
+ "[": "\\[",
747
+ "]": "\\]"
748
+ };
749
+ var markdownEscapablesRegex = new RegExp(
750
+ Object.keys(markdownEscapables).map((entity) => `\\${entity}`).join("|"),
751
+ "g"
752
+ );
753
+ detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
754
+
755
+ // src/decoders/ClientMsg.ts
756
+
757
+
758
+
759
+
760
+
761
+
762
+
763
+
764
+
765
+ var _decoders = require('decoders');
766
+
767
+ // src/decoders/jsonYolo.ts
768
+
769
+ var jsonYolo = _decoders.unknown;
770
+ var jsonObjectYolo = jsonYolo.refine(
771
+ (value) => value !== null && typeof value === "object" && !Array.isArray(value),
772
+ "Must be JSON object"
773
+ );
774
+
775
+ // src/decoders/Op.ts
776
+
777
+ var updateObjectOp = _decoders.object.call(void 0, {
778
+ type: _decoders.constant.call(void 0, OpCode.UPDATE_OBJECT),
779
+ opId: _decoders.string,
780
+ id: _decoders.string,
781
+ data: jsonObjectYolo
782
+ });
783
+ var createObjectOp = _decoders.object.call(void 0, {
784
+ type: _decoders.constant.call(void 0, OpCode.CREATE_OBJECT),
785
+ opId: _decoders.string,
786
+ id: _decoders.string,
787
+ parentId: _decoders.string,
788
+ parentKey: _decoders.string,
789
+ data: jsonObjectYolo,
790
+ intent: _decoders.optional.call(void 0, _decoders.constant.call(void 0, "set")),
791
+ deletedId: _decoders.optional.call(void 0, _decoders.string)
792
+ });
793
+ var createListOp = _decoders.object.call(void 0, {
794
+ type: _decoders.constant.call(void 0, OpCode.CREATE_LIST),
795
+ opId: _decoders.string,
796
+ id: _decoders.string,
797
+ parentId: _decoders.string,
798
+ parentKey: _decoders.string,
799
+ intent: _decoders.optional.call(void 0, _decoders.constant.call(void 0, "set")),
800
+ deletedId: _decoders.optional.call(void 0, _decoders.string)
801
+ });
802
+ var createMapOp = _decoders.object.call(void 0, {
803
+ type: _decoders.constant.call(void 0, OpCode.CREATE_MAP),
804
+ opId: _decoders.string,
805
+ id: _decoders.string,
806
+ parentId: _decoders.string,
807
+ parentKey: _decoders.string,
808
+ intent: _decoders.optional.call(void 0, _decoders.constant.call(void 0, "set")),
809
+ deletedId: _decoders.optional.call(void 0, _decoders.string)
810
+ });
811
+ var createRegisterOp = _decoders.object.call(void 0, {
812
+ type: _decoders.constant.call(void 0, OpCode.CREATE_REGISTER),
813
+ opId: _decoders.string,
814
+ id: _decoders.string,
815
+ parentId: _decoders.string,
816
+ parentKey: _decoders.string,
817
+ data: jsonYolo,
818
+ intent: _decoders.optional.call(void 0, _decoders.constant.call(void 0, "set")),
819
+ deletedId: _decoders.optional.call(void 0, _decoders.string)
820
+ });
821
+ var deleteCrdtOp = _decoders.object.call(void 0, {
822
+ type: _decoders.constant.call(void 0, OpCode.DELETE_CRDT),
823
+ opId: _decoders.string,
824
+ id: _decoders.string
825
+ });
826
+ var setParentKeyOp = _decoders.object.call(void 0, {
827
+ type: _decoders.constant.call(void 0, OpCode.SET_PARENT_KEY),
828
+ opId: _decoders.string,
829
+ id: _decoders.string,
830
+ parentKey: _decoders.string
831
+ });
832
+ var deleteObjectKeyOp = _decoders.object.call(void 0, {
833
+ type: _decoders.constant.call(void 0, OpCode.DELETE_OBJECT_KEY),
834
+ opId: _decoders.string,
835
+ id: _decoders.string,
836
+ key: _decoders.string
837
+ });
838
+ var op = _decoders.taggedUnion.call(void 0, "type", {
839
+ [OpCode.UPDATE_OBJECT]: updateObjectOp,
840
+ [OpCode.CREATE_OBJECT]: createObjectOp,
841
+ [OpCode.CREATE_LIST]: createListOp,
842
+ [OpCode.CREATE_MAP]: createMapOp,
843
+ [OpCode.CREATE_REGISTER]: createRegisterOp,
844
+ [OpCode.DELETE_CRDT]: deleteCrdtOp,
845
+ [OpCode.SET_PARENT_KEY]: setParentKeyOp,
846
+ [OpCode.DELETE_OBJECT_KEY]: deleteObjectKeyOp
847
+ });
848
+
849
+ // src/decoders/y-types.ts
850
+
851
+ var guidDecoder = _decoders.uuid.refineType();
852
+ var ROOT_YDOC_ID = "root";
853
+
854
+ // src/decoders/ClientMsg.ts
855
+ var updatePresenceClientMsg = _decoders.object.call(void 0, {
856
+ type: _decoders.constant.call(void 0, ClientMsgCode.UPDATE_PRESENCE),
857
+ data: jsonObjectYolo,
858
+ targetActor: _decoders.optional.call(void 0, _decoders.number)
859
+ });
860
+ var broadcastEventClientMsg = _decoders.object.call(void 0, {
861
+ type: _decoders.constant.call(void 0, ClientMsgCode.BROADCAST_EVENT),
862
+ event: jsonYolo
863
+ });
864
+ var fetchStorageClientMsg = _decoders.object.call(void 0, {
865
+ type: _decoders.constant.call(void 0, ClientMsgCode.FETCH_STORAGE)
866
+ });
867
+ var updateStorageClientMsg = _decoders.object.call(void 0, {
868
+ type: _decoders.constant.call(void 0, ClientMsgCode.UPDATE_STORAGE),
869
+ ops: _decoders.array.call(void 0, op)
870
+ });
871
+ var fetchYDocClientMsg = _decoders.object.call(void 0, {
872
+ type: _decoders.constant.call(void 0, ClientMsgCode.FETCH_YDOC),
873
+ vector: _decoders.string.refineType(),
874
+ guid: _decoders.optional.call(void 0, guidDecoder),
875
+ // Don't specify to update the root doc
876
+ v2: _decoders.optional.call(void 0, _decoders.boolean)
877
+ });
878
+ var updateYDocClientMsg = _decoders.object.call(void 0, {
879
+ type: _decoders.constant.call(void 0, ClientMsgCode.UPDATE_YDOC),
880
+ update: _decoders.string.refineType(),
881
+ guid: _decoders.optional.call(void 0, guidDecoder),
882
+ // Don't specify to update the root doc
883
+ v2: _decoders.optional.call(void 0, _decoders.boolean)
884
+ });
885
+ var clientMsgDecoder = _decoders.taggedUnion.call(void 0, "type", {
886
+ [ClientMsgCode.UPDATE_PRESENCE]: updatePresenceClientMsg,
887
+ [ClientMsgCode.BROADCAST_EVENT]: broadcastEventClientMsg,
888
+ [ClientMsgCode.FETCH_STORAGE]: fetchStorageClientMsg,
889
+ [ClientMsgCode.UPDATE_STORAGE]: updateStorageClientMsg,
890
+ [ClientMsgCode.FETCH_YDOC]: fetchYDocClientMsg,
891
+ [ClientMsgCode.UPDATE_YDOC]: updateYDocClientMsg
892
+ }).describe("Must be a valid client message");
893
+ var transientClientMsgDecoder = _decoders.taggedUnion.call(void 0, "type", {
894
+ // [ClientMsgCode.UPDATE_PRESENCE]: updatePresenceClientMsg,
895
+ // [ClientMsgCode.BROADCAST_EVENT]: broadcastEventClientMsg,
896
+ // [ClientMsgCode.FETCH_STORAGE]: fetchStorageClientMsg,
897
+ [ClientMsgCode.UPDATE_STORAGE]: updateStorageClientMsg
898
+ // [ClientMsgCode.FETCH_YDOC]: fetchYDocClientMsg,
899
+ // [ClientMsgCode.UPDATE_YDOC]: updateYDocClientMsg,
900
+ }).describe("Must be a valid transient client message");
901
+
902
+ // src/formats/LossyJson.ts
903
+ function snapshotToLossyJson_eager(snapshot2) {
904
+ try {
905
+ return buildObject(snapshot2, "root", snapshot2.get_root().data);
906
+ } finally {
907
+ snapshot2.destroy();
908
+ }
909
+ }
910
+ function buildNode(snapshot2, id) {
911
+ const node = snapshot2.get_node(id);
912
+ if (node.type === CrdtType.OBJECT) {
913
+ return buildObject(snapshot2, id, node.data);
914
+ } else if (node.type === CrdtType.LIST) {
915
+ return buildList(snapshot2, id);
916
+ } else if (node.type === CrdtType.MAP) {
917
+ return buildMap(snapshot2, id);
918
+ } else {
919
+ return node.data;
920
+ }
921
+ }
922
+ function buildObject(snapshot2, id, staticData) {
923
+ const data = Object.assign(/* @__PURE__ */ Object.create(null), staticData);
924
+ for (const [key, childId] of snapshot2.iter_children(id)) {
925
+ data[key] = buildNode(snapshot2, childId);
926
+ }
927
+ return data;
928
+ }
929
+ function buildList(snapshot2, id) {
930
+ const data = [];
931
+ for (const [_, childId] of snapshot2.iter_children(id)) {
932
+ data.push(buildNode(snapshot2, childId));
933
+ }
934
+ return data;
935
+ }
936
+ function buildMap(snapshot2, id) {
937
+ const data = /* @__PURE__ */ Object.create(null);
938
+ for (const [key, childId] of snapshot2.iter_children(id)) {
939
+ data[key] = buildNode(snapshot2, childId);
940
+ }
941
+ return data;
942
+ }
943
+ function* snapshotToLossyJson_lazy(snapshot2) {
944
+ try {
945
+ const staticJson = JSON.stringify(snapshot2.get_root().data).slice(1, -1);
946
+ yield* emitObject(snapshot2, "root", staticJson);
947
+ } finally {
948
+ snapshot2.destroy();
949
+ }
950
+ }
951
+ function* emit(snapshot2, id) {
952
+ const node = snapshot2.get_node(id);
953
+ if (node.type === CrdtType.OBJECT) {
954
+ yield* emitObject(snapshot2, id, JSON.stringify(node.data).slice(1, -1));
955
+ } else if (node.type === CrdtType.LIST) {
956
+ yield* emitList(snapshot2, id);
957
+ } else if (node.type === CrdtType.MAP) {
958
+ yield* emitMap(snapshot2, id);
959
+ } else if (node.type === CrdtType.REGISTER) {
960
+ yield JSON.stringify(node.data);
961
+ }
962
+ }
963
+ function* emitObject(snapshot2, id, staticJson) {
964
+ let comma = staticJson.length > 0;
965
+ yield "{";
966
+ yield staticJson;
967
+ for (const [key, childId] of snapshot2.iter_children(id)) {
968
+ if (comma) yield ",";
969
+ else comma = true;
970
+ yield `${JSON.stringify(key)}:`;
971
+ yield* emit(snapshot2, childId);
972
+ }
973
+ yield "}";
974
+ }
975
+ function* emitList(snapshot2, id) {
976
+ let comma = false;
977
+ yield "[";
978
+ for (const [_, childId] of snapshot2.iter_children(id)) {
979
+ if (comma) yield ",";
980
+ else comma = true;
981
+ yield* emit(snapshot2, childId);
982
+ }
983
+ yield "]";
984
+ }
985
+ function* emitMap(snapshot2, id) {
986
+ let comma = false;
987
+ yield "{";
988
+ for (const [key, childId] of snapshot2.iter_children(id)) {
989
+ if (comma) yield ",";
990
+ else comma = true;
991
+ yield `${JSON.stringify(key)}:`;
992
+ yield* emit(snapshot2, childId);
993
+ }
994
+ yield "}";
995
+ }
996
+
997
+ // src/formats/NodeStream.ts
998
+ function* snapshotToNodeStream(snapshot2) {
999
+ try {
1000
+ yield* snapshot2.iter_all();
1001
+ } finally {
1002
+ snapshot2.destroy();
1003
+ }
1004
+ }
1005
+
1006
+ // src/formats/PlainLson.ts
1007
+ var SERVER_INIT_OP_PREFIX = "si";
1008
+ function generateId(state) {
1009
+ return `${SERVER_INIT_OP_PREFIX}:${state.clock++}`;
1010
+ }
1011
+ function isSpecialPlainLsonValue(value) {
1012
+ return isJsonObject(value) && value.liveblocksType !== void 0;
1013
+ }
1014
+ function* iterJson(key, data, parent, state) {
1015
+ if (isSpecialPlainLsonValue(data)) {
1016
+ switch (data.liveblocksType) {
1017
+ case "LiveObject":
1018
+ yield* iterObjectInner(key, data.data, parent, state);
1019
+ return;
1020
+ case "LiveList":
1021
+ yield* iterList(key, data.data, parent, state);
1022
+ return;
1023
+ case "LiveMap":
1024
+ yield* iterMap(key, data.data, parent, state);
1025
+ return;
1026
+ default:
1027
+ assertNever(data, "Unknown `liveblocksType` field");
1028
+ }
1029
+ } else {
1030
+ yield [
1031
+ generateId(state),
1032
+ {
1033
+ type: CrdtType.REGISTER,
1034
+ data,
1035
+ parentId: parent[0],
1036
+ parentKey: key
1037
+ }
1038
+ ];
1039
+ }
1040
+ }
1041
+ function* iterMap(key, map, parent, state) {
1042
+ const mapTuple = [
1043
+ generateId(state),
1044
+ { type: CrdtType.MAP, parentId: parent[0], parentKey: key }
1045
+ ];
1046
+ yield mapTuple;
1047
+ for (const [subKey, subValue] of Object.entries(map)) {
1048
+ yield* iterJson(subKey, subValue, mapTuple, state);
1049
+ }
1050
+ }
1051
+ function* iterList(key, list, parent, state) {
1052
+ const id = generateId(state);
1053
+ const crdt = {
1054
+ type: CrdtType.LIST,
1055
+ parentId: parent[0],
1056
+ parentKey: key
1057
+ };
1058
+ const listTuple = [id, crdt];
1059
+ yield listTuple;
1060
+ let position = makePosition();
1061
+ for (const subValue of list) {
1062
+ yield* iterJson(position, subValue, listTuple, state);
1063
+ position = makePosition(position);
1064
+ }
1065
+ }
1066
+ function* iterObjectInner(key, value, parent, state) {
1067
+ const data = {};
1068
+ const specialChildren = [];
1069
+ for (const [subKey, subValue] of Object.entries(value)) {
1070
+ if (isSpecialPlainLsonValue(subValue)) {
1071
+ specialChildren.push([subKey, subValue]);
1072
+ } else {
1073
+ data[subKey] = subValue;
1074
+ }
1075
+ }
1076
+ const objectTuple = parent !== null ? [
1077
+ generateId(state),
1078
+ {
1079
+ type: CrdtType.OBJECT,
1080
+ data,
1081
+ parentId: parent[0],
1082
+ parentKey: key
1083
+ }
1084
+ ] : ["root", { type: CrdtType.OBJECT, data }];
1085
+ yield objectTuple;
1086
+ for (const [subKey, subValue] of specialChildren) {
1087
+ yield* iterJson(subKey, subValue, objectTuple, state);
1088
+ }
1089
+ }
1090
+ function* plainLsonToNodeStream(root) {
1091
+ const state = { clock: 1 };
1092
+ yield* iterObjectInner("root", root.data, null, state);
1093
+ }
1094
+ function snapshotToPlainLson_eager(snapshot2) {
1095
+ try {
1096
+ return buildObject2(snapshot2, "root", snapshot2.get_root().data);
1097
+ } finally {
1098
+ snapshot2.destroy();
1099
+ }
1100
+ }
1101
+ function buildNode2(snapshot2, id) {
1102
+ const node = snapshot2.get_node(id);
1103
+ if (node.type === CrdtType.OBJECT) {
1104
+ return buildObject2(snapshot2, id, node.data);
1105
+ } else if (node.type === CrdtType.LIST) {
1106
+ return buildList2(snapshot2, id);
1107
+ } else if (node.type === CrdtType.MAP) {
1108
+ return buildMap2(snapshot2, id);
1109
+ } else {
1110
+ return node.data;
1111
+ }
1112
+ }
1113
+ function buildObject2(snapshot2, id, staticData) {
1114
+ const data = Object.assign(
1115
+ /* @__PURE__ */ Object.create(null),
1116
+ staticData
1117
+ );
1118
+ for (const [key, childId] of snapshot2.iter_children(id)) {
1119
+ data[key] = buildNode2(snapshot2, childId);
1120
+ }
1121
+ return { liveblocksType: "LiveObject", data };
1122
+ }
1123
+ function buildList2(snapshot2, id) {
1124
+ const data = [];
1125
+ for (const [_, childId] of snapshot2.iter_children(id)) {
1126
+ data.push(buildNode2(snapshot2, childId));
1127
+ }
1128
+ return { liveblocksType: "LiveList", data };
1129
+ }
1130
+ function buildMap2(snapshot2, id) {
1131
+ const data = /* @__PURE__ */ Object.create(null);
1132
+ for (const [key, childId] of snapshot2.iter_children(id)) {
1133
+ data[key] = buildNode2(snapshot2, childId);
1134
+ }
1135
+ return { liveblocksType: "LiveMap", data };
1136
+ }
1137
+ function* snapshotToPlainLson_lazy(snapshot2) {
1138
+ try {
1139
+ const staticJson = JSON.stringify(snapshot2.get_root().data).slice(1, -1);
1140
+ yield* emitObject2(snapshot2, "root", staticJson);
1141
+ } finally {
1142
+ snapshot2.destroy();
1143
+ }
1144
+ }
1145
+ function* emit2(snapshot2, id) {
1146
+ const node = snapshot2.get_node(id);
1147
+ if (node.type === CrdtType.OBJECT) {
1148
+ yield* emitObject2(snapshot2, id, JSON.stringify(node.data).slice(1, -1));
1149
+ } else if (node.type === CrdtType.LIST) {
1150
+ yield* emitList2(snapshot2, id);
1151
+ } else if (node.type === CrdtType.MAP) {
1152
+ yield* emitMap2(snapshot2, id);
1153
+ } else if (node.type === CrdtType.REGISTER) {
1154
+ yield JSON.stringify(node.data);
1155
+ }
1156
+ }
1157
+ function* emitObject2(snapshot2, id, staticJson) {
1158
+ let comma = staticJson.length > 0;
1159
+ yield '{"liveblocksType":"LiveObject","data":{';
1160
+ yield staticJson;
1161
+ for (const [key, childId] of snapshot2.iter_children(id)) {
1162
+ if (comma) yield ",";
1163
+ else comma = true;
1164
+ yield `${JSON.stringify(key)}:`;
1165
+ yield* emit2(snapshot2, childId);
1166
+ }
1167
+ yield "}}";
1168
+ }
1169
+ function* emitList2(snapshot2, id) {
1170
+ let comma = false;
1171
+ yield '{"liveblocksType":"LiveList","data":[';
1172
+ for (const [_, childId] of snapshot2.iter_children(id)) {
1173
+ if (comma) yield ",";
1174
+ else comma = true;
1175
+ yield* emit2(snapshot2, childId);
1176
+ }
1177
+ yield "]}";
1178
+ }
1179
+ function* emitMap2(snapshot2, id) {
1180
+ let comma = false;
1181
+ yield '{"liveblocksType":"LiveMap","data":{';
1182
+ for (const [key, childId] of snapshot2.iter_children(id)) {
1183
+ if (comma) yield ",";
1184
+ else comma = true;
1185
+ yield `${JSON.stringify(key)}:`;
1186
+ yield* emit2(snapshot2, childId);
1187
+ }
1188
+ yield "}}";
1189
+ }
1190
+
1191
+ // src/lib/DefaultMap.ts
1192
+ var _defaultFn2;
1193
+ var DefaultMap2 = class extends Map {
1194
+ /**
1195
+ * If the default function is not provided to the constructor, it has to be
1196
+ * provided in each .getOrCreate() call individually.
1197
+ */
1198
+ constructor(defaultFn, entries) {
1199
+ super(entries);
1200
+ __privateAdd(this, _defaultFn2);
1201
+ __privateSet(this, _defaultFn2, defaultFn);
1202
+ }
1203
+ /**
1204
+ * Gets the value at the given key, or creates it.
1205
+ *
1206
+ * Difference from normal Map: if the key does not exist, it will be created
1207
+ * on the fly using the factory function, and that value will get returned
1208
+ * instead of `undefined`.
1209
+ */
1210
+ getOrCreate(key, defaultFn) {
1211
+ if (super.has(key)) {
1212
+ return super.get(key);
1213
+ } else {
1214
+ const fn = _nullishCoalesce(_nullishCoalesce(defaultFn, () => ( __privateGet(this, _defaultFn2))), () => ( raise("DefaultMap used without a factory function")));
1215
+ const value = fn(key);
1216
+ this.set(key, value);
1217
+ return value;
1218
+ }
1219
+ }
1220
+ };
1221
+ _defaultFn2 = new WeakMap();
1222
+
1223
+ // src/lib/NestedMap.ts
1224
+ function emptyIterator() {
1225
+ return [][Symbol.iterator]();
1226
+ }
1227
+ var _map;
1228
+ var NestedMap = class {
1229
+ constructor() {
1230
+ __privateAdd(this, _map);
1231
+ __privateSet(this, _map, new DefaultMap2(() => /* @__PURE__ */ new Map()));
1232
+ }
1233
+ get size() {
1234
+ let total = 0;
1235
+ for (const value of __privateGet(this, _map).values()) {
1236
+ total += value.size;
1237
+ }
1238
+ return total;
1239
+ }
1240
+ count(key1) {
1241
+ return _nullishCoalesce(_optionalChain([__privateGet, 'call', _7 => _7(this, _map), 'access', _8 => _8.get, 'call', _9 => _9(key1), 'optionalAccess', _10 => _10.size]), () => ( 0));
1242
+ }
1243
+ *keys() {
1244
+ for (const [key1, nested] of __privateGet(this, _map)) {
1245
+ for (const key2 of nested.keys()) {
1246
+ yield [key1, key2];
1247
+ }
1248
+ }
1249
+ }
1250
+ has(key1, key2) {
1251
+ return _nullishCoalesce(_optionalChain([__privateGet, 'call', _11 => _11(this, _map), 'access', _12 => _12.get, 'call', _13 => _13(key1), 'optionalAccess', _14 => _14.has, 'call', _15 => _15(key2)]), () => ( false));
1252
+ }
1253
+ get(key1, key2) {
1254
+ return _optionalChain([__privateGet, 'call', _16 => _16(this, _map), 'access', _17 => _17.get, 'call', _18 => _18(key1), 'optionalAccess', _19 => _19.get, 'call', _20 => _20(key2)]);
1255
+ }
1256
+ set(key1, key2, value) {
1257
+ __privateGet(this, _map).getOrCreate(key1).set(key2, value);
1258
+ return this;
1259
+ }
1260
+ delete(key1, key2) {
1261
+ if (!__privateGet(this, _map).has(key1)) {
1262
+ return;
1263
+ }
1264
+ const nested = __privateGet(this, _map).get(key1);
1265
+ nested.delete(key2);
1266
+ if (nested.size === 0) {
1267
+ __privateGet(this, _map).delete(key1);
1268
+ }
1269
+ }
1270
+ clear() {
1271
+ __privateGet(this, _map).clear();
1272
+ }
1273
+ *[Symbol.iterator]() {
1274
+ for (const [key1, nested] of __privateGet(this, _map)) {
1275
+ for (const [key2, value] of nested) {
1276
+ yield [key1, key2, value];
1277
+ }
1278
+ }
1279
+ }
1280
+ entriesAt(key1) {
1281
+ return _nullishCoalesce(_optionalChain([__privateGet, 'call', _21 => _21(this, _map), 'access', _22 => _22.get, 'call', _23 => _23(key1), 'optionalAccess', _24 => _24.entries, 'call', _25 => _25()]), () => ( emptyIterator()));
1282
+ }
1283
+ *filterAt(key1, keys) {
1284
+ const nested = __privateGet(this, _map).get(key1);
1285
+ if (nested === void 0) {
1286
+ return;
1287
+ }
1288
+ for (const k2 of keys) {
1289
+ const value = nested.get(k2);
1290
+ if (value !== void 0) {
1291
+ yield [k2, value];
1292
+ }
1293
+ }
1294
+ }
1295
+ keysAt(key1) {
1296
+ return _nullishCoalesce(_optionalChain([__privateGet, 'call', _26 => _26(this, _map), 'access', _27 => _27.get, 'call', _28 => _28(key1), 'optionalAccess', _29 => _29.keys, 'call', _30 => _30()]), () => ( emptyIterator()));
1297
+ }
1298
+ valuesAt(key1) {
1299
+ return _nullishCoalesce(_optionalChain([__privateGet, 'call', _31 => _31(this, _map), 'access', _32 => _32.get, 'call', _33 => _33(key1), 'optionalAccess', _34 => _34.values, 'call', _35 => _35()]), () => ( emptyIterator()));
1300
+ }
1301
+ deleteAll(key1) {
1302
+ __privateGet(this, _map).delete(key1);
1303
+ }
1304
+ };
1305
+ _map = new WeakMap();
1306
+
1307
+ // src/makeInMemorySnapshot.ts
1308
+ function makeInMemorySnapshot(values) {
1309
+ const map = new Map(values);
1310
+ if (!map.has("root")) {
1311
+ map.set("root", { type: CrdtType.OBJECT, data: {} });
1312
+ }
1313
+ const entries = [];
1314
+ const nodeStream = map;
1315
+ for (const node of nodeStream) {
1316
+ if (isRootStorageNode(node)) continue;
1317
+ const [id, crdt] = node;
1318
+ entries.push([crdt.parentId, crdt.parentKey, id]);
1319
+ }
1320
+ entries.sort(
1321
+ (a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0
1322
+ );
1323
+ const revMap = new NestedMap();
1324
+ for (const [parentId, parentKey, id] of entries) {
1325
+ revMap.set(parentId, parentKey, id);
1326
+ }
1327
+ function get_node(id) {
1328
+ return nn(map.get(id), `Node not found: ${id}`);
1329
+ }
1330
+ return {
1331
+ get_root: () => nn(
1332
+ map.get("root"),
1333
+ "Root not found"
1334
+ ),
1335
+ get_node,
1336
+ iter_children: (nodeId) => revMap.entriesAt(nodeId),
1337
+ iter_all: () => map,
1338
+ destroy() {
1339
+ map.clear();
1340
+ revMap.clear();
1341
+ }
1342
+ };
1343
+ }
1344
+
1345
+ // src/MetadataDB.ts
1346
+ function makeMetadataDB(driver) {
1347
+ async function get(a1, a2) {
1348
+ if (a2 === void 0) {
1349
+ return await driver.get_meta(a1);
1350
+ } else {
1351
+ return a1.value(await driver.get_meta(a2));
1352
+ }
1353
+ }
1354
+ return {
1355
+ get,
1356
+ put: driver.put_meta.bind(driver),
1357
+ delete: driver.delete_meta.bind(driver)
1358
+ };
1359
+ }
1360
+
1361
+ // src/protocol/ProtocolVersion.ts
1362
+
1363
+ var ProtocolVersion = /* @__PURE__ */ ((ProtocolVersion2) => {
1364
+ ProtocolVersion2[ProtocolVersion2["V7"] = 7] = "V7";
1365
+ ProtocolVersion2[ProtocolVersion2["V8"] = 8] = "V8";
1366
+ return ProtocolVersion2;
1367
+ })(ProtocolVersion || {});
1368
+ var protocolVersionDecoder = _decoders.enum_.call(void 0, ProtocolVersion).describe(
1369
+ "Unsupported protocol version"
1370
+ );
1371
+
1372
+ // src/Room.ts
1373
+ var _asyncmutex = require('async-mutex');
1374
+
1375
+ var _itertools = require('itertools');
1376
+ var _nanoid = require('nanoid');
1377
+
1378
+ // src/lib/Logger.ts
1379
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
1380
+ LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
1381
+ LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
1382
+ LogLevel2[LogLevel2["WARNING"] = 2] = "WARNING";
1383
+ LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
1384
+ return LogLevel2;
1385
+ })(LogLevel || {});
1386
+ function formatError(err) {
1387
+ const prefix = `${err.name}: ${err.message}`;
1388
+ return (_optionalChain([err, 'access', _36 => _36.stack, 'optionalAccess', _37 => _37.startsWith, 'call', _38 => _38(prefix)]) ? err.stack : `${prefix}
1389
+ ${_nullishCoalesce(err.stack, () => ( ""))}`).trimEnd();
1390
+ }
1391
+ var _cache;
1392
+ var LogTarget = class {
1393
+ constructor(level = 1 /* INFO */) {
1394
+ __publicField(this, "level");
1395
+ __privateAdd(this, _cache, /* @__PURE__ */ new WeakMap());
1396
+ this.level = typeof level === "number" ? level : _nullishCoalesce(LogLevelNames[level], () => ( 1)) /* INFO */;
1397
+ }
1398
+ /** Helper for formatting a log level */
1399
+ formatLevel(level) {
1400
+ switch (level) {
1401
+ case 0 /* DEBUG */:
1402
+ return "debug";
1403
+ case 1 /* INFO */:
1404
+ return "info";
1405
+ case 2 /* WARNING */:
1406
+ return "warn";
1407
+ case 3 /* ERROR */:
1408
+ return "error";
1409
+ default:
1410
+ return raise("Invalid log level");
1411
+ }
1412
+ }
1413
+ /** Helper for formatting an Arg */
1414
+ formatArg(arg) {
1415
+ return typeof arg === "object" ? arg instanceof Error ? formatError(arg) : JSON.stringify(arg) : String(arg);
1416
+ }
1417
+ /**
1418
+ * Helper for formatting a Context. Override this in a subclass to change the
1419
+ * formatting.
1420
+ */
1421
+ formatContextImpl(context) {
1422
+ const parts = [];
1423
+ for (const [k, v] of Object.entries(_nullishCoalesce(context, () => ( {})))) {
1424
+ if (v !== void 0) {
1425
+ const sv = typeof v === "object" ? JSON.stringify(v) : v;
1426
+ parts.push(`${k}=${sv}`);
1427
+ }
1428
+ }
1429
+ return parts.length > 0 ? `[${parts.join(" ")}]` : "";
1430
+ }
1431
+ /**
1432
+ * Helper for formatting a Context. Will only compute the string once for
1433
+ * every Context instance, and keep its computed string value cached for
1434
+ * performance.
1435
+ */
1436
+ formatContext(context) {
1437
+ let formatted = __privateGet(this, _cache).get(context);
1438
+ if (formatted === void 0) {
1439
+ formatted = this.formatContextImpl(context);
1440
+ __privateGet(this, _cache).set(context, formatted);
1441
+ }
1442
+ return formatted;
1443
+ }
1444
+ };
1445
+ _cache = new WeakMap();
1446
+ var CONSOLE_METHOD = {
1447
+ [0 /* DEBUG */]: "info",
1448
+ [1 /* INFO */]: "info",
1449
+ [2 /* WARNING */]: "warn",
1450
+ [3 /* ERROR */]: "error"
1451
+ };
1452
+ var ConsoleTarget = class extends LogTarget {
1453
+ log(level, context, arg) {
1454
+ console[CONSOLE_METHOD[level]](
1455
+ this.formatArg(arg),
1456
+ this.formatContext(context)
1457
+ );
1458
+ }
1459
+ };
1460
+ var LogLevelNames = {
1461
+ debug: 0 /* DEBUG */,
1462
+ info: 1 /* INFO */,
1463
+ warning: 2 /* WARNING */,
1464
+ error: 3 /* ERROR */
1465
+ };
1466
+ var Logger = class _Logger {
1467
+ constructor(target = new ConsoleTarget(), context = {}) {
1468
+ __publicField(this, "debug");
1469
+ __publicField(this, "info");
1470
+ __publicField(this, "warn");
1471
+ __publicField(this, "error");
1472
+ __publicField(this, "o");
1473
+ __publicField(this, "_context");
1474
+ __publicField(this, "_targets");
1475
+ this._context = context;
1476
+ this._targets = Array.isArray(target) ? target : [target];
1477
+ const minLevel = Math.min(...this._targets.map((t) => t.level));
1478
+ const noop = () => {
1479
+ };
1480
+ const makeLogFn = (lvl) => (arg) => this._targets.forEach((target2) => {
1481
+ if (target2.level <= lvl) {
1482
+ target2.log(lvl, this._context, arg);
1483
+ }
1484
+ });
1485
+ this.o = {
1486
+ /* eslint-disable @typescript-eslint/no-unsafe-enum-comparison */
1487
+ debug: minLevel <= 0 /* DEBUG */ ? makeLogFn(0 /* DEBUG */) : void 0,
1488
+ info: minLevel <= 1 /* INFO */ ? makeLogFn(1 /* INFO */) : void 0,
1489
+ warn: minLevel <= 2 /* WARNING */ ? makeLogFn(2 /* WARNING */) : void 0,
1490
+ error: minLevel <= 3 /* ERROR */ ? makeLogFn(3 /* ERROR */) : void 0
1491
+ /* eslint-enable @typescript-eslint/no-unsafe-enum-comparison */
1492
+ };
1493
+ this.debug = _nullishCoalesce(this.o.debug, () => ( noop));
1494
+ this.info = _nullishCoalesce(this.o.info, () => ( noop));
1495
+ this.warn = _nullishCoalesce(this.o.warn, () => ( noop));
1496
+ this.error = _nullishCoalesce(this.o.error, () => ( noop));
1497
+ }
1498
+ /**
1499
+ * Creates a new Logger instance with the given extra context applied. All
1500
+ * log calls made from that new Logger will carry all current _and_ the extra
1501
+ * context, with the extra context taking precedence. Assign an explicit
1502
+ * `undefined` value to a key to "remove" it from the context.
1503
+ */
1504
+ withContext(extra) {
1505
+ const combined = { ...this._context, ...extra };
1506
+ return new _Logger(this._targets, combined);
1507
+ }
1508
+ };
1509
+
1510
+ // src/plugins/InMemoryDriver.ts
1511
+
1512
+
1513
+ // src/lib/text.ts
1514
+ function quote(value) {
1515
+ return value !== void 0 ? `'${value}'` : "???";
1516
+ }
1517
+
1518
+ // src/plugins/InMemoryDriver.ts
1519
+ function buildRevNodes(nodeStream) {
1520
+ const result = new NestedMap();
1521
+ for (const node of nodeStream) {
1522
+ if (isRootStorageNode(node)) continue;
1523
+ const [id, crdt] = node;
1524
+ const existing = result.get(crdt.parentId, crdt.parentKey);
1525
+ if (existing === void 0 || id > existing) {
1526
+ result.set(crdt.parentId, crdt.parentKey, id);
1527
+ }
1528
+ }
1529
+ return result;
1530
+ }
1531
+ function buildReverseLookup(nodes) {
1532
+ const revNodes = buildRevNodes(nodes);
1533
+ const queue = ["root"];
1534
+ const reachableNodes = /* @__PURE__ */ new Set();
1535
+ while (queue.length > 0) {
1536
+ const nodeId = queue.pop();
1537
+ const node = nn(nodes.get(nodeId));
1538
+ if (node.type === CrdtType.OBJECT) {
1539
+ for (const key of revNodes.keysAt(nodeId)) {
1540
+ delete node.data[key];
1541
+ }
1542
+ }
1543
+ if (node.type !== CrdtType.REGISTER) {
1544
+ queue.push(...revNodes.valuesAt(nodeId));
1545
+ } else {
1546
+ const parent = nodes.get(node.parentId);
1547
+ if (_optionalChain([parent, 'optionalAccess', _39 => _39.type]) === CrdtType.OBJECT) {
1548
+ continue;
1549
+ }
1550
+ }
1551
+ reachableNodes.add(nodeId);
1552
+ }
1553
+ let deletedCount = 0;
1554
+ for (const [id] of nodes) {
1555
+ if (!reachableNodes.has(id)) {
1556
+ nodes.delete(id);
1557
+ deletedCount++;
1558
+ }
1559
+ }
1560
+ return deletedCount === 0 ? revNodes : buildRevNodes(nodes);
1561
+ }
1562
+ function hasStaticDataAt(node, key) {
1563
+ return node.type === CrdtType.OBJECT && Object.prototype.hasOwnProperty.call(node.data, key) && node.data[key] !== void 0;
1564
+ }
1565
+ var InMemoryDriver = class {
1566
+ constructor(options) {
1567
+ __publicField(this, "_nextActor");
1568
+ __publicField(this, "_nodes");
1569
+ __publicField(this, "_metadb");
1570
+ __publicField(this, "_ydb");
1571
+ this._nodes = /* @__PURE__ */ new Map();
1572
+ this._metadb = /* @__PURE__ */ new Map();
1573
+ this._ydb = /* @__PURE__ */ new Map();
1574
+ this._nextActor = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _40 => _40.initialActor]), () => ( -1));
1575
+ for (const [key, value] of _nullishCoalesce(_optionalChain([options, 'optionalAccess', _41 => _41.initialNodes]), () => ( []))) {
1576
+ this._nodes.set(key, value);
1577
+ }
1578
+ }
1579
+ raw_iter_nodes() {
1580
+ return this._nodes[Symbol.iterator]();
1581
+ }
1582
+ /** Deletes all nodes and replaces them with the given document. */
1583
+ DANGEROUSLY_reset_nodes(doc) {
1584
+ this._nodes.clear();
1585
+ for (const [id, node] of plainLsonToNodeStream(doc)) {
1586
+ this._nodes.set(id, node);
1587
+ }
1588
+ }
1589
+ async get_meta(key) {
1590
+ return this._metadb.get(key);
1591
+ }
1592
+ async put_meta(key, value) {
1593
+ this._metadb.set(key, value);
1594
+ }
1595
+ async delete_meta(key) {
1596
+ this._metadb.delete(key);
1597
+ }
1598
+ next_actor() {
1599
+ return ++this._nextActor;
1600
+ }
1601
+ async iter_y_updates(docId) {
1602
+ const prefix = `${docId}@|@`;
1603
+ return _itertools.imap.call(void 0,
1604
+ _itertools.ifilter.call(void 0, this._ydb.entries(), ([k]) => k.startsWith(prefix)),
1605
+ ([k, v]) => [k.slice(prefix.length), v]
1606
+ );
1607
+ }
1608
+ async write_y_updates(docId, key, data) {
1609
+ this._ydb.set(`${docId}@|@${key}`, data);
1610
+ }
1611
+ async delete_y_updates(docId, keys) {
1612
+ for (const key of keys) {
1613
+ this._ydb.delete(`${docId}@|@${key}`);
1614
+ }
1615
+ }
1616
+ /** @private Only use this in unit tests, never in production. */
1617
+ async DANGEROUSLY_wipe_all_y_updates() {
1618
+ this._ydb.clear();
1619
+ }
1620
+ // Intercept load_nodes_api to add caching layer
1621
+ load_nodes_api() {
1622
+ const nodes = this._nodes;
1623
+ if (!nodes.has("root")) {
1624
+ nodes.set("root", { type: CrdtType.OBJECT, data: {} });
1625
+ }
1626
+ const revNodes = buildReverseLookup(nodes);
1627
+ function get_next_sibling(parentId, pos) {
1628
+ let nextPos;
1629
+ for (const siblingKey of revNodes.keysAt(parentId)) {
1630
+ const siblingPos = asPos(siblingKey);
1631
+ if (siblingPos > pos && (nextPos === void 0 || siblingPos < nextPos)) {
1632
+ nextPos = siblingPos;
1633
+ }
1634
+ }
1635
+ return nextPos;
1636
+ }
1637
+ async function set_child(id, node, allowOverwrite = false) {
1638
+ const parentNode = nodes.get(node.parentId);
1639
+ if (parentNode === void 0) {
1640
+ throw new Error(`No such parent ${quote(node.parentId)}`);
1641
+ }
1642
+ if (node.type === CrdtType.REGISTER && parentNode.type === CrdtType.OBJECT) {
1643
+ throw new Error("Cannot add register under object");
1644
+ }
1645
+ const conflictingSiblingId = revNodes.get(node.parentId, node.parentKey);
1646
+ if (conflictingSiblingId !== id) {
1647
+ const parentNode2 = nodes.get(node.parentId);
1648
+ const hasConflictingData = parentNode2 !== void 0 && hasStaticDataAt(parentNode2, node.parentKey);
1649
+ if (conflictingSiblingId !== void 0 || hasConflictingData) {
1650
+ if (allowOverwrite) {
1651
+ delete_child_key(node.parentId, node.parentKey);
1652
+ } else {
1653
+ throw new Error(`Key ${quote(node.parentKey)} already exists`);
1654
+ }
1655
+ }
1656
+ revNodes.set(node.parentId, node.parentKey, id);
1657
+ }
1658
+ nodes.set(id, node);
1659
+ }
1660
+ async function move_sibling(id, newPos) {
1661
+ const node = nodes.get(id);
1662
+ if (_optionalChain([node, 'optionalAccess', _42 => _42.parentId]) === void 0) {
1663
+ return;
1664
+ }
1665
+ if (revNodes.has(node.parentId, newPos))
1666
+ throw new Error(`Pos ${quote(newPos)} already taken`);
1667
+ revNodes.delete(node.parentId, node.parentKey);
1668
+ const newNode = { ...node, parentKey: newPos };
1669
+ nodes.set(id, newNode);
1670
+ revNodes.set(node.parentId, newPos, id);
1671
+ }
1672
+ async function set_object_data(id, data, allowOverwrite = false) {
1673
+ const node = nodes.get(id);
1674
+ if (_optionalChain([node, 'optionalAccess', _43 => _43.type]) !== CrdtType.OBJECT) {
1675
+ return;
1676
+ }
1677
+ for (const key of Object.keys(data)) {
1678
+ const childId = revNodes.get(id, key);
1679
+ if (childId !== void 0) {
1680
+ if (allowOverwrite) {
1681
+ delete_node(childId);
1682
+ } else {
1683
+ throw new Error(`Child node already exists under ${quote(key)}`);
1684
+ }
1685
+ }
1686
+ }
1687
+ nodes.set(id, { ...node, data: { ...node.data, ...data } });
1688
+ }
1689
+ function delete_node(id) {
1690
+ const node = nodes.get(id);
1691
+ if (_optionalChain([node, 'optionalAccess', _44 => _44.parentId]) === void 0) {
1692
+ return;
1693
+ }
1694
+ revNodes.delete(node.parentId, node.parentKey);
1695
+ const queue = [id];
1696
+ while (queue.length > 0) {
1697
+ const currid = queue.pop();
1698
+ queue.push(...revNodes.valuesAt(currid));
1699
+ nodes.delete(currid);
1700
+ revNodes.deleteAll(currid);
1701
+ }
1702
+ }
1703
+ function delete_child_key(id, key) {
1704
+ const node = nodes.get(id);
1705
+ if (node !== void 0 && hasStaticDataAt(node, key)) {
1706
+ const { [key]: _, ...rest } = node.data;
1707
+ nodes.set(id, { ...node, data: rest });
1708
+ }
1709
+ const childId = revNodes.get(id, key);
1710
+ if (childId !== void 0) {
1711
+ delete_node(childId);
1712
+ }
1713
+ }
1714
+ const api = {
1715
+ /**
1716
+ * Return the node with the given id, or undefined if no such node exists.
1717
+ * Must always return a valid root node for id="root", even if empty.
1718
+ */
1719
+ get_node: (id) => nodes.get(id),
1720
+ /**
1721
+ * Yield all nodes as [id, node] pairs. Must always include the root node.
1722
+ */
1723
+ iter_nodes: () => nodes,
1724
+ /**
1725
+ * Return true iff a node with the given id exists. Must return true for "root".
1726
+ */
1727
+ has_node: (id) => nodes.has(id),
1728
+ /**
1729
+ * Return the id of the child node at (parentId, parentKey), or undefined if
1730
+ * none. Only checks child nodes registered via set_child, NOT static data
1731
+ * keys on OBJECT nodes.
1732
+ */
1733
+ get_child_at: (id, key) => revNodes.get(id, key),
1734
+ /**
1735
+ * Return true iff a child node exists at (parentId, parentKey). Static data
1736
+ * keys on OBJECT nodes do not count—return false for those.
1737
+ */
1738
+ has_child_at: (id, key) => revNodes.has(id, key),
1739
+ /**
1740
+ * Return the position of the closest sibling "to the right" of `pos` under
1741
+ * parentId, or undefined if no such sibling exists. The given `pos` may, but
1742
+ * does not have to exist already. Positions compare lexicographically.
1743
+ */
1744
+ get_next_sibling,
1745
+ /**
1746
+ * Insert a child node with the given id.
1747
+ *
1748
+ * If allowOverwrite=false (default): throw if a node with this id exists.
1749
+ * If allowOverwrite=true: replace any existing node at this id, deleting its
1750
+ * entire subtree if it has children.
1751
+ */
1752
+ set_child,
1753
+ /**
1754
+ * Change a node's parentKey, effectively repositioning the node within its
1755
+ * parent. The new position must be free.
1756
+ * Throw if another node already occupies (parentId, newPos).
1757
+ */
1758
+ move_sibling,
1759
+ /**
1760
+ * Delete a node and its entire subtree recursively.
1761
+ * Ignore if id="root" (root is immortal).
1762
+ */
1763
+ delete_node,
1764
+ /**
1765
+ * Delete a key from node `id`. Handle two cases:
1766
+ *
1767
+ * 1. If id is an OBJECT with `key` in its data: remove that data field.
1768
+ * 2. If a child exists at (id, key): delete that child and all its
1769
+ * descendants recursively.
1770
+ *
1771
+ * No-op if neither applies or if the node doesn't exist.
1772
+ */
1773
+ delete_child_key,
1774
+ /**
1775
+ * Replace the data object of an OBJECT node.
1776
+ *
1777
+ * If allowOverwrite=false (default): throw if any key in `data` conflicts
1778
+ * with an existing child's parentKey.
1779
+ * If allowOverwrite=true: first delete any conflicting children (and their
1780
+ * entire subtrees), then set the data.
1781
+ */
1782
+ set_object_data,
1783
+ /**
1784
+ * Return a readable snapshot of the storage tree.
1785
+ *
1786
+ * @param lowMemory When true, the call site hints that the snapshot should
1787
+ * be optimized for lower memory consumption, even if that means slower
1788
+ * access.
1789
+ */
1790
+ get_snapshot(_lowMemory) {
1791
+ return makeInMemorySnapshot(nodes);
1792
+ }
1793
+ };
1794
+ return api;
1795
+ }
1796
+ };
1797
+ function makeNewInMemoryDriver(options) {
1798
+ return new InMemoryDriver(options);
1799
+ }
1800
+
1801
+ // src/Storage.ts
1802
+ function accept(op2, fix) {
1803
+ return { action: "accepted", op: op2, fix };
1804
+ }
1805
+ function ignore(ignoredOp) {
1806
+ return { action: "ignored", ignoredOpId: ignoredOp.opId };
1807
+ }
1808
+ function nodeFromCreateChildOp(op2) {
1809
+ switch (op2.type) {
1810
+ case OpCode.CREATE_LIST:
1811
+ return {
1812
+ type: CrdtType.LIST,
1813
+ parentId: op2.parentId,
1814
+ parentKey: op2.parentKey
1815
+ };
1816
+ case OpCode.CREATE_MAP:
1817
+ return {
1818
+ type: CrdtType.MAP,
1819
+ parentId: op2.parentId,
1820
+ parentKey: op2.parentKey
1821
+ };
1822
+ case OpCode.CREATE_OBJECT:
1823
+ return {
1824
+ type: CrdtType.OBJECT,
1825
+ parentId: op2.parentId,
1826
+ parentKey: op2.parentKey,
1827
+ data: op2.data
1828
+ };
1829
+ case OpCode.CREATE_REGISTER:
1830
+ return {
1831
+ type: CrdtType.REGISTER,
1832
+ parentId: op2.parentId,
1833
+ parentKey: op2.parentKey,
1834
+ data: op2.data
1835
+ };
1836
+ default:
1837
+ return assertNever(op2, "Unknown op code");
1838
+ }
1839
+ }
1840
+ var Storage = class {
1841
+ constructor(coreDriver) {
1842
+ // The actual underlying storage API (could be backed by in-memory store,
1843
+ // SQLite, Redis, Postgres, Cloudflare Durable Object Storage, etc.)
1844
+ __publicField(this, "coreDriver");
1845
+ __publicField(this, "_loadedDriver");
1846
+ this.coreDriver = coreDriver;
1847
+ }
1848
+ // -------------------------------------------------------------------------
1849
+ // Public API (for Storage)
1850
+ // -------------------------------------------------------------------------
1851
+ get loadedDriver() {
1852
+ if (this._loadedDriver === void 0) {
1853
+ throw new Error("Cannot access tree before it's been loaded");
1854
+ }
1855
+ return this._loadedDriver;
1856
+ }
1857
+ // REFACTOR NOTE: Eventually raw_iter_nodes has to be removed here
1858
+ raw_iter_nodes() {
1859
+ return this.coreDriver.raw_iter_nodes();
1860
+ }
1861
+ /**
1862
+ * Load the room data from object storage into memory. Persisted room
1863
+ * data consists of the main node map, which represents the Liveblocks
1864
+ * Storage tree, and special keys where we store usage metrics, or room
1865
+ * metadata.
1866
+ */
1867
+ async load(logger) {
1868
+ this._loadedDriver = await this.coreDriver.load_nodes_api(logger);
1869
+ }
1870
+ unload() {
1871
+ this._loadedDriver = void 0;
1872
+ }
1873
+ /**
1874
+ * Applies a batch of Ops.
1875
+ */
1876
+ async applyOps(ops) {
1877
+ const results = [];
1878
+ for (const op2 of ops) {
1879
+ results.push(await this.applyOp(op2));
1880
+ }
1881
+ return results;
1882
+ }
1883
+ // -------------------------------------------------------------------------
1884
+ // Private APIs (for Storage)
1885
+ // -------------------------------------------------------------------------
1886
+ /**
1887
+ * Applies a single Op.
1888
+ */
1889
+ async applyOp(op2) {
1890
+ switch (op2.type) {
1891
+ case OpCode.CREATE_LIST:
1892
+ case OpCode.CREATE_MAP:
1893
+ case OpCode.CREATE_REGISTER:
1894
+ case OpCode.CREATE_OBJECT:
1895
+ return await this.applyCreateOp(op2);
1896
+ case OpCode.UPDATE_OBJECT:
1897
+ return await this.applyUpdateObjectOp(op2);
1898
+ case OpCode.SET_PARENT_KEY:
1899
+ return await this.applySetParentKeyOp(op2);
1900
+ case OpCode.DELETE_OBJECT_KEY:
1901
+ return await this.applyDeleteObjectKeyOp(op2);
1902
+ case OpCode.DELETE_CRDT:
1903
+ return await this.applyDeleteCrdtOp(op2);
1904
+ default:
1905
+ if (process.env.NODE_ENV === "production") {
1906
+ return ignore(op2);
1907
+ } else {
1908
+ return assertNever(op2, "Invalid op");
1909
+ }
1910
+ }
1911
+ }
1912
+ async applyCreateOp(op2) {
1913
+ if (this.loadedDriver.has_node(op2.id)) {
1914
+ return ignore(op2);
1915
+ }
1916
+ const node = nodeFromCreateChildOp(op2);
1917
+ const parent = this.loadedDriver.get_node(node.parentId);
1918
+ if (parent === void 0) {
1919
+ return ignore(op2);
1920
+ }
1921
+ switch (parent.type) {
1922
+ case CrdtType.OBJECT:
1923
+ if (op2.type === OpCode.CREATE_REGISTER) {
1924
+ return ignore(op2);
1925
+ }
1926
+ case CrdtType.MAP:
1927
+ await this.loadedDriver.set_child(op2.id, node, true);
1928
+ return accept(op2);
1929
+ case CrdtType.LIST:
1930
+ return this.createChildAsListItem(op2, node);
1931
+ case CrdtType.REGISTER:
1932
+ return ignore(op2);
1933
+ default:
1934
+ return assertNever(parent, "Unhandled CRDT type");
1935
+ }
1936
+ }
1937
+ async createChildAsListItem(op2, node) {
1938
+ let fix;
1939
+ const intent = _nullishCoalesce(op2.intent, () => ( "insert"));
1940
+ if (intent === "insert") {
1941
+ const insertedParentKey = await this.insertIntoList(op2.id, node);
1942
+ if (insertedParentKey !== node.parentKey) {
1943
+ op2 = { ...op2, parentKey: insertedParentKey };
1944
+ fix = {
1945
+ type: OpCode.SET_PARENT_KEY,
1946
+ id: op2.id,
1947
+ parentKey: insertedParentKey
1948
+ };
1949
+ return accept(op2, fix);
1950
+ }
1951
+ return accept(op2);
1952
+ } else if (intent === "set") {
1953
+ const deletedId = op2.deletedId !== void 0 && op2.deletedId !== op2.id && _optionalChain([this, 'access', _45 => _45.loadedDriver, 'access', _46 => _46.get_node, 'call', _47 => _47(op2.deletedId), 'optionalAccess', _48 => _48.parentId]) === node.parentId ? op2.deletedId : void 0;
1954
+ if (deletedId !== void 0) {
1955
+ await this.loadedDriver.delete_node(deletedId);
1956
+ }
1957
+ const prevItemId = this.loadedDriver.get_child_at(
1958
+ node.parentId,
1959
+ node.parentKey
1960
+ );
1961
+ if (prevItemId !== void 0 && prevItemId !== deletedId) {
1962
+ fix = {
1963
+ type: OpCode.DELETE_CRDT,
1964
+ id: prevItemId
1965
+ };
1966
+ }
1967
+ await this.loadedDriver.set_child(op2.id, node, true);
1968
+ return accept(op2, fix);
1969
+ } else {
1970
+ return assertNever(intent, "Invalid intent");
1971
+ }
1972
+ }
1973
+ async applyDeleteObjectKeyOp(op2) {
1974
+ await this.loadedDriver.delete_child_key(op2.id, op2.key);
1975
+ return accept(op2);
1976
+ }
1977
+ async applyUpdateObjectOp(op2) {
1978
+ await this.loadedDriver.set_object_data(op2.id, op2.data, true);
1979
+ return accept(op2);
1980
+ }
1981
+ async applyDeleteCrdtOp(op2) {
1982
+ await this.loadedDriver.delete_node(op2.id);
1983
+ return accept(op2);
1984
+ }
1985
+ async applySetParentKeyOp(op2) {
1986
+ const newPosition = await this.moveToPosInList(op2.id, op2.parentKey);
1987
+ if (newPosition === void 0) {
1988
+ return ignore(op2);
1989
+ }
1990
+ if (newPosition !== op2.parentKey) {
1991
+ const modifiedOp = { ...op2, parentKey: newPosition };
1992
+ const fix = {
1993
+ type: OpCode.SET_PARENT_KEY,
1994
+ id: op2.id,
1995
+ parentKey: newPosition
1996
+ };
1997
+ return accept(modifiedOp, fix);
1998
+ } else {
1999
+ return accept(op2);
2000
+ }
2001
+ }
2002
+ /**
2003
+ * Inserts a new node in the storage tree, under a list parent. If an
2004
+ * existing sibling node already exist under this key, however, it will look
2005
+ * for another free position under that parent and insert it under
2006
+ * a different parent key that is guaranteed to be available.
2007
+ *
2008
+ * Returns the key that was used for the insertion.
2009
+ */
2010
+ async insertIntoList(id, node) {
2011
+ const key = this.findFreeListPosition(node.parentId, asPos(node.parentKey));
2012
+ if (key !== node.parentKey) {
2013
+ node = { ...node, parentKey: key };
2014
+ }
2015
+ await this.loadedDriver.set_child(id, node);
2016
+ return node.parentKey;
2017
+ }
2018
+ /**
2019
+ * Tries to move a node to the given position under the same parent. If
2020
+ * a conflicting sibling node already exist at this position, it will use
2021
+ * another free position instead, to avoid the conflict.
2022
+ *
2023
+ * Returns the position (parentKey) that the node was eventually placed at.
2024
+ * If the node could be inserted without conflict, it will return the same
2025
+ * parentKey position.
2026
+ *
2027
+ * Will return `undefined` if this action could not be interpreted. Will be
2028
+ * a no-op for non-list items.
2029
+ */
2030
+ async moveToPosInList(id, targetKey) {
2031
+ const node = this.loadedDriver.get_node(id);
2032
+ if (_optionalChain([node, 'optionalAccess', _49 => _49.parentId]) === void 0) {
2033
+ return;
2034
+ }
2035
+ if (_optionalChain([this, 'access', _50 => _50.loadedDriver, 'access', _51 => _51.get_node, 'call', _52 => _52(node.parentId), 'optionalAccess', _53 => _53.type]) !== CrdtType.LIST) {
2036
+ return;
2037
+ }
2038
+ if (node.parentKey === targetKey) {
2039
+ return targetKey;
2040
+ }
2041
+ const key = this.findFreeListPosition(node.parentId, asPos(targetKey));
2042
+ if (key !== node.parentKey) {
2043
+ await this.loadedDriver.move_sibling(id, key);
2044
+ }
2045
+ return key;
2046
+ }
2047
+ /**
2048
+ * Checks whether the given parentKey is a "free position" under the
2049
+ * parentId, i.e. there are no siblings that have the same key. If a sibling
2050
+ * exists under that key, it tries to generate new positions until it finds
2051
+ * a free slot, and returns that. The returned value is therefore always safe
2052
+ * to use as parentKey.
2053
+ */
2054
+ findFreeListPosition(parentId, parentPos) {
2055
+ if (!this.loadedDriver.has_child_at(parentId, parentPos)) {
2056
+ return parentPos;
2057
+ }
2058
+ const currPos = parentPos;
2059
+ const nextPos = this.loadedDriver.get_next_sibling(parentId, currPos);
2060
+ if (nextPos !== void 0) {
2061
+ return makePosition(currPos, nextPos);
2062
+ } else {
2063
+ return makePosition(currPos);
2064
+ }
2065
+ }
2066
+ };
2067
+
2068
+ // src/YjsStorage.ts
2069
+ var _jsbase64 = require('js-base64');
2070
+
2071
+ var _yjs = require('yjs'); var Y = _interopRequireWildcard(_yjs);
2072
+ var MAX_Y_UPDATE_SIZE = 1e5;
2073
+ var YjsStorage = class {
2074
+ constructor(driver) {
2075
+ __publicField(this, "driver");
2076
+ __publicField(this, "doc", new Y.Doc());
2077
+ // the root document
2078
+ __publicField(this, "lastUpdatesById", /* @__PURE__ */ new Map());
2079
+ __publicField(this, "lastSnapshotById", /* @__PURE__ */ new Map());
2080
+ // Keeps track of which keys are loaded, so we can clean them up without calling `.list()`
2081
+ __publicField(this, "keysById", new DefaultMap(
2082
+ () => /* @__PURE__ */ new Set()
2083
+ ));
2084
+ __publicField(this, "initPromisesById", /* @__PURE__ */ new Map());
2085
+ /**
2086
+ * Given a record of updates, merge them and compress if savings are significant
2087
+ */
2088
+ __publicField(this, "_loadAndCompressYJSUpdates", async (docUpdates, doc, docId) => {
2089
+ const SAVINGS_THRESHOLD = 0.2;
2090
+ const updates = Object.values(docUpdates);
2091
+ const sizeOnDisk = updates.reduce((acc, update) => {
2092
+ return acc + update.length;
2093
+ }, 0);
2094
+ if (updates.length > 0) {
2095
+ const docKeys = Object.keys(docUpdates);
2096
+ this.keysById.set(docId, new Set(docKeys));
2097
+ const mergedUpdate = Y.mergeUpdates(updates);
2098
+ Y.applyUpdate(doc, mergedUpdate);
2099
+ const garbageCollectedUpdate = Y.encodeStateAsUpdate(doc);
2100
+ if (garbageCollectedUpdate.length < sizeOnDisk * (1 - SAVINGS_THRESHOLD)) {
2101
+ const newKey = _nanoid.nanoid.call(void 0, );
2102
+ await this.driver.write_y_updates(
2103
+ docId,
2104
+ newKey,
2105
+ garbageCollectedUpdate
2106
+ );
2107
+ await this.driver.delete_y_updates(docId, docKeys);
2108
+ this.keysById.set(docId, /* @__PURE__ */ new Set([newKey]));
2109
+ }
2110
+ }
2111
+ });
2112
+ __publicField(this, "_loadYDocFromDurableStorage", async (doc, docId) => {
2113
+ const docUpdates = Object.fromEntries(
2114
+ await this.driver.iter_y_updates(docId)
2115
+ );
2116
+ await this._loadAndCompressYJSUpdates(docUpdates, doc, docId);
2117
+ this.lastUpdatesById.set(docId, {
2118
+ currentKey: _nanoid.nanoid.call(void 0, ),
2119
+ lastVector: Y.encodeStateVector(doc)
2120
+ });
2121
+ doc.emit("load", [doc]);
2122
+ return doc;
2123
+ });
2124
+ this.driver = driver;
2125
+ this.doc.on("subdocs", ({ removed }) => {
2126
+ removed.forEach((subdoc) => {
2127
+ subdoc.destroy();
2128
+ });
2129
+ });
2130
+ }
2131
+ // ------------------------------------------------------------------------------------
2132
+ // Public API
2133
+ // ------------------------------------------------------------------------------------
2134
+ async getYDoc(docId) {
2135
+ const doc = await this.loadDocByIdIfNotAlreadyLoaded(docId);
2136
+ return doc;
2137
+ }
2138
+ /**
2139
+ * If passed a state vector, an update with diff will be returned, if not the entire doc is returned.
2140
+ *
2141
+ * @param stateVector a base64 encoded target state vector created by running Y.encodeStateVector(Doc) on the client
2142
+ * @returns a base64 encoded array of YJS updates
2143
+ */
2144
+ async getYDocUpdate(logger, stateVector = "", guid, isV2 = false) {
2145
+ const update = await this.getYDocUpdateBinary(
2146
+ logger,
2147
+ stateVector,
2148
+ guid,
2149
+ isV2
2150
+ );
2151
+ if (!update) return null;
2152
+ return _jsbase64.Base64.fromUint8Array(update);
2153
+ }
2154
+ async getYDocUpdateBinary(logger, stateVector = "", guid, isV2 = false) {
2155
+ const doc = guid !== void 0 ? await this.getYSubdoc(guid) : this.doc;
2156
+ if (!doc) {
2157
+ return null;
2158
+ }
2159
+ let encodedTargetVector;
2160
+ try {
2161
+ encodedTargetVector = stateVector.length > 0 ? _jsbase64.Base64.toUint8Array(stateVector) : void 0;
2162
+ } catch (e) {
2163
+ logger.warn(
2164
+ "Could not get update from passed vector, returning all updates"
2165
+ );
2166
+ }
2167
+ if (isV2) {
2168
+ return Y.encodeStateAsUpdateV2(doc, encodedTargetVector);
2169
+ }
2170
+ return Y.encodeStateAsUpdate(doc, encodedTargetVector);
2171
+ }
2172
+ async getYStateVector(guid) {
2173
+ const doc = guid !== void 0 ? await this.getYSubdoc(guid) : this.doc;
2174
+ if (!doc) {
2175
+ return null;
2176
+ }
2177
+ return _jsbase64.Base64.fromUint8Array(Y.encodeStateVector(doc));
2178
+ }
2179
+ async getSnapshotHash(options) {
2180
+ const doc = options.guid !== void 0 ? await this.getYSubdoc(options.guid) : this.doc;
2181
+ if (!doc) {
2182
+ return null;
2183
+ }
2184
+ const snapshot2 = this._getOrPutLastSnapshot(doc);
2185
+ return this.calculateSnapshotHash(snapshot2, { isV2: options.isV2 });
2186
+ }
2187
+ /**
2188
+ * @param update base64 encoded uint8array
2189
+ * @returns
2190
+ */
2191
+ async addYDocUpdate(logger, update, guid, isV2) {
2192
+ const doc = guid !== void 0 ? await this.getYSubdoc(guid) : this.doc;
2193
+ if (!doc) {
2194
+ throw new Error(`YDoc with guid ${guid} not found`);
2195
+ }
2196
+ try {
2197
+ const beforeSnapshot = this._getOrPutLastSnapshot(doc);
2198
+ const updateAsU8 = typeof update === "string" ? _jsbase64.Base64.toUint8Array(update) : update;
2199
+ const applyUpdate2 = isV2 ? Y.applyUpdateV2 : Y.applyUpdate;
2200
+ applyUpdate2(doc, updateAsU8, "client");
2201
+ const afterSnapshot = this._putLastSnapshot(doc);
2202
+ const updated = !Y.equalSnapshots(beforeSnapshot, afterSnapshot);
2203
+ if (updated) {
2204
+ await this.handleYDocUpdate(doc);
2205
+ }
2206
+ return {
2207
+ isUpdated: updated,
2208
+ snapshotHash: await this.calculateSnapshotHash(afterSnapshot, { isV2 })
2209
+ };
2210
+ } catch (e) {
2211
+ logger.warn(`Ignored bad YDoc update: ${String(e)}`);
2212
+ throw new Error(
2213
+ "Bad YDoc update. Data is corrupted, or data does not match the encoding."
2214
+ );
2215
+ }
2216
+ }
2217
+ loadDocByIdIfNotAlreadyLoaded(docId) {
2218
+ let loaded$ = this.initPromisesById.get(docId);
2219
+ let doc = docId === ROOT_YDOC_ID ? this.doc : this.findYSubdocByGuid(docId);
2220
+ if (!doc) {
2221
+ doc = new Y.Doc();
2222
+ }
2223
+ if (loaded$ === void 0) {
2224
+ loaded$ = this._loadYDocFromDurableStorage(doc, docId);
2225
+ this.initPromisesById.set(docId, loaded$);
2226
+ }
2227
+ return loaded$;
2228
+ }
2229
+ async load(_logger) {
2230
+ await this.loadDocByIdIfNotAlreadyLoaded(ROOT_YDOC_ID);
2231
+ }
2232
+ /**
2233
+ * Unloads the Yjs documents from memory.
2234
+ */
2235
+ unload() {
2236
+ }
2237
+ // ------------------------------------------------------------------------------------
2238
+ // Private APIs
2239
+ // ------------------------------------------------------------------------------------
2240
+ // NOTE: We could instead store the hash of snapshot instead of the whole snapshot to optimize memory usage.
2241
+ _getOrPutLastSnapshot(doc) {
2242
+ const docId = doc.guid === this.doc.guid ? ROOT_YDOC_ID : doc.guid;
2243
+ const snapshot2 = this.lastSnapshotById.get(docId);
2244
+ if (snapshot2) {
2245
+ return snapshot2;
2246
+ }
2247
+ return this._putLastSnapshot(doc);
2248
+ }
2249
+ // NOTE: We could instead store the hash of snapshot instead of the whole snapshot to optimize memory usage.
2250
+ _putLastSnapshot(doc) {
2251
+ const docId = doc.guid === this.doc.guid ? ROOT_YDOC_ID : doc.guid;
2252
+ const snapshot2 = Y.snapshot(doc);
2253
+ this.lastSnapshotById.set(docId, snapshot2);
2254
+ return snapshot2;
2255
+ }
2256
+ findYSubdocByGuid(guid) {
2257
+ for (const subdoc of this.doc.getSubdocs()) {
2258
+ if (subdoc.guid === guid) {
2259
+ return subdoc;
2260
+ }
2261
+ }
2262
+ return null;
2263
+ }
2264
+ async calculateSnapshotHash(snapshot2, { isV2 }) {
2265
+ const encodedSnapshot = isV2 ? Y.encodeSnapshotV2(snapshot2) : Y.encodeSnapshot(snapshot2);
2266
+ return _jsbase64.Base64.fromUint8Array(
2267
+ new Uint8Array(
2268
+ await crypto.subtle.digest("SHA-256", new Uint8Array(encodedSnapshot))
2269
+ )
2270
+ );
2271
+ }
2272
+ // gets a subdoc, it will be loaded if not already loaded
2273
+ async getYSubdoc(guid) {
2274
+ const subdoc = this.findYSubdocByGuid(guid);
2275
+ if (!subdoc) {
2276
+ return null;
2277
+ }
2278
+ await this.loadDocByIdIfNotAlreadyLoaded(guid);
2279
+ return subdoc;
2280
+ }
2281
+ // When the YJS doc changes, update it in durable storage
2282
+ async handleYDocUpdate(doc) {
2283
+ const docId = doc.guid === this.doc.guid ? ROOT_YDOC_ID : doc.guid;
2284
+ const docUpdateInfo = this.lastUpdatesById.get(docId);
2285
+ const updateSinceLastVector = Y.encodeStateAsUpdate(
2286
+ doc,
2287
+ _optionalChain([docUpdateInfo, 'optionalAccess', _54 => _54.lastVector])
2288
+ );
2289
+ const storageKey = _nullishCoalesce(_optionalChain([docUpdateInfo, 'optionalAccess', _55 => _55.currentKey]), () => ( _nanoid.nanoid.call(void 0, )));
2290
+ if (updateSinceLastVector.length > MAX_Y_UPDATE_SIZE) {
2291
+ const newKey = _nanoid.nanoid.call(void 0, );
2292
+ await this.driver.write_y_updates(
2293
+ docId,
2294
+ newKey,
2295
+ Y.encodeStateAsUpdate(doc)
2296
+ );
2297
+ await this.driver.delete_y_updates(
2298
+ docId,
2299
+ Array.from(this.keysById.getOrCreate(docId))
2300
+ );
2301
+ this.keysById.set(docId, /* @__PURE__ */ new Set([newKey]));
2302
+ this.lastUpdatesById.set(docId, {
2303
+ currentKey: _nanoid.nanoid.call(void 0, ),
2304
+ // start writing to a new key
2305
+ lastVector: Y.encodeStateVector(doc)
2306
+ });
2307
+ } else {
2308
+ await this.driver.write_y_updates(
2309
+ docId,
2310
+ storageKey,
2311
+ updateSinceLastVector
2312
+ );
2313
+ const keys = [storageKey];
2314
+ const currentKeys = this.keysById.getOrCreate(docId);
2315
+ for (const key of keys) {
2316
+ currentKeys.add(key);
2317
+ }
2318
+ }
2319
+ }
2320
+ };
2321
+
2322
+ // src/lib/tryCatch.ts
2323
+ async function tryCatch(promise) {
2324
+ try {
2325
+ const data = await (typeof promise === "function" ? promise() : promise);
2326
+ return [data, void 0];
2327
+ } catch (error3) {
2328
+ return [void 0, error3];
2329
+ }
2330
+ }
2331
+
2332
+ // src/lib/UniqueMap.ts
2333
+ var __revMap, __keyFn;
2334
+ var UniqueMap = class extends Map {
2335
+ constructor(keyFn) {
2336
+ super();
2337
+ // / \
2338
+ // Primary key Unique key
2339
+ __privateAdd(this, __revMap);
2340
+ __privateAdd(this, __keyFn);
2341
+ __privateSet(this, __keyFn, keyFn);
2342
+ __privateSet(this, __revMap, /* @__PURE__ */ new Map());
2343
+ }
2344
+ lookupPrimaryKey(uniqKey) {
2345
+ return __privateGet(this, __revMap).get(uniqKey);
2346
+ }
2347
+ lookup(uniqKey) {
2348
+ const key = __privateGet(this, __revMap).get(uniqKey);
2349
+ return key !== void 0 ? this.get(key) : void 0;
2350
+ }
2351
+ set(key, value) {
2352
+ const uniqKey = __privateGet(this, __keyFn).call(this, value);
2353
+ const primaryKey = __privateGet(this, __revMap).get(uniqKey);
2354
+ if (primaryKey !== void 0 && primaryKey !== key) {
2355
+ throw new Error(`Unique key ${String(uniqKey)} already exists`);
2356
+ }
2357
+ __privateGet(this, __revMap).set(uniqKey, key);
2358
+ return super.set(key, value);
2359
+ }
2360
+ delete(primaryKey) {
2361
+ const value = this.get(primaryKey);
2362
+ if (value !== void 0) {
2363
+ const indexedKey = __privateGet(this, __keyFn).call(this, value);
2364
+ __privateGet(this, __revMap).delete(indexedKey);
2365
+ }
2366
+ return super.delete(primaryKey);
2367
+ }
2368
+ };
2369
+ __revMap = new WeakMap();
2370
+ __keyFn = new WeakMap();
2371
+
2372
+ // src/utils.ts
2373
+ function concatUint8Arrays(arrays) {
2374
+ const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
2375
+ const result = new Uint8Array(totalLength);
2376
+ let offset = 0;
2377
+ for (const arr of arrays) {
2378
+ result.set(arr, offset);
2379
+ offset += arr.length;
2380
+ }
2381
+ return result;
2382
+ }
2383
+ function makeRoomStateMsg(actor, nonce, scopes, users, publicMeta) {
2384
+ return {
2385
+ type: ServerMsgCode.ROOM_STATE,
2386
+ actor,
2387
+ nonce,
2388
+ scopes,
2389
+ users,
2390
+ meta: _nullishCoalesce(publicMeta, () => ( {}))
2391
+ };
2392
+ }
2393
+
2394
+ // src/Room.ts
2395
+ var messagesDecoder = _decoders.array.call(void 0, clientMsgDecoder);
2396
+ var HIGHEST_PROTOCOL_VERSION = Math.max(
2397
+ ...Object.values(ProtocolVersion).filter(
2398
+ (v) => typeof v === "number"
2399
+ )
2400
+ );
2401
+ var SERVER_MSG_CODE_NAMES = Object.fromEntries(
2402
+ Object.entries(ServerMsgCode).map(([k, v]) => [v, k])
2403
+ );
2404
+ var BLACK_HOLE = new Logger([
2405
+ /* No targets, i.e. black hole logger */
2406
+ ]);
2407
+ function collectSideEffects() {
2408
+ const deferred = [];
2409
+ return {
2410
+ defer: (p) => void deferred.push(p),
2411
+ waitAll: () => Promise.allSettled(deferred)
2412
+ };
2413
+ }
2414
+ function serialize(msgs) {
2415
+ return JSON.stringify(msgs);
2416
+ }
2417
+ function ackIgnoredOp(opId) {
2418
+ return { type: OpCode.DELETE_CRDT, id: "ACK", opId };
2419
+ }
2420
+ function stripOpId(op2) {
2421
+ const { opId: _, ...rest } = op2;
2422
+ return rest;
2423
+ }
2424
+ var __socket, __debug, __lastActiveAt, __hasNotifiedClientStorageUpdateError;
2425
+ var BrowserSession = class {
2426
+ /** @internal - Never create a BrowserSession instance manually. Use the room.startBrowserSession() API instead. */
2427
+ constructor(ticket, socket, debug) {
2428
+ // ^^ User-defined Session Metadata
2429
+ // ^^ User-defined Client Metadata (sent to client in ROOM_STATE)
2430
+ __publicField(this, "version");
2431
+ // Liveblocks protocol version this client will speak
2432
+ __publicField(this, "actor");
2433
+ // Must be unique within the room
2434
+ __publicField(this, "createdAt");
2435
+ // Externally provided (public!) user metadata. This information will get shared with other clients
2436
+ __publicField(this, "user");
2437
+ __publicField(this, "scopes");
2438
+ // Permissions for this session, sent to connected clients (so consider public info)
2439
+ __publicField(this, "meta");
2440
+ // Arbitrary *private* meta data to attach to this session (will NOT be shared)
2441
+ __publicField(this, "publicMeta");
2442
+ // Metadata sent to client in ROOM_STATE message's "meta" field
2443
+ __privateAdd(this, __socket);
2444
+ __privateAdd(this, __debug);
2445
+ __privateAdd(this, __lastActiveAt);
2446
+ // We keep a status in-memory in the session of whether we already sent a rejected ops message to the client.
2447
+ __privateAdd(this, __hasNotifiedClientStorageUpdateError);
2448
+ this.version = ticket.version;
2449
+ this.actor = ticket.actor;
2450
+ this.user = ticket.user;
2451
+ this.scopes = ticket.scopes;
2452
+ this.meta = _nullishCoalesce(ticket.meta, () => ( void 0));
2453
+ this.publicMeta = ticket.publicMeta;
2454
+ __privateSet(this, __socket, socket);
2455
+ __privateSet(this, __debug, debug);
2456
+ const now = /* @__PURE__ */ new Date();
2457
+ this.createdAt = now;
2458
+ __privateSet(this, __lastActiveAt, now);
2459
+ __privateSet(this, __hasNotifiedClientStorageUpdateError, false);
2460
+ }
2461
+ get lastActiveAt() {
2462
+ const lastPing = _optionalChain([__privateGet, 'call', _56 => _56(this, __socket), 'access', _57 => _57.getLastPongTimestamp, 'optionalCall', _58 => _58()]);
2463
+ if (lastPing && lastPing > __privateGet(this, __lastActiveAt)) {
2464
+ return lastPing;
2465
+ } else {
2466
+ return __privateGet(this, __lastActiveAt);
2467
+ }
2468
+ }
2469
+ get hasNotifiedClientStorageUpdateError() {
2470
+ return __privateGet(this, __hasNotifiedClientStorageUpdateError);
2471
+ }
2472
+ markActive(now = /* @__PURE__ */ new Date()) {
2473
+ if (now > __privateGet(this, __lastActiveAt)) {
2474
+ __privateSet(this, __lastActiveAt, now);
2475
+ }
2476
+ }
2477
+ setHasNotifiedClientStorageUpdateError() {
2478
+ __privateSet(this, __hasNotifiedClientStorageUpdateError, true);
2479
+ }
2480
+ sendPong() {
2481
+ this.markActive();
2482
+ const sent = __privateGet(this, __socket).send("pong");
2483
+ if (__privateGet(this, __debug)) {
2484
+ if (sent < 0) {
2485
+ console.error(
2486
+ `failed to send "pong" to actor=${this.actor} (back pressure)`
2487
+ );
2488
+ } else if (sent === 0) {
2489
+ console.error(
2490
+ `failed to send "pong" to actor=${this.actor} (connection issue)`
2491
+ );
2492
+ } else {
2493
+ console.log(`sent to actor=${this.actor}: "pong"`);
2494
+ }
2495
+ }
2496
+ return sent;
2497
+ }
2498
+ send(serverMsg) {
2499
+ const data = typeof serverMsg === "string" ? serverMsg : serialize(serverMsg);
2500
+ const sent = __privateGet(this, __socket).send(data);
2501
+ if (__privateGet(this, __debug)) {
2502
+ if (sent < 0) {
2503
+ console.error(
2504
+ `failed to send message to actor=${this.actor} (back pressure)`
2505
+ );
2506
+ } else if (sent === 0) {
2507
+ console.error(
2508
+ `failed to send message to actor=${this.actor} (connection issue)`
2509
+ );
2510
+ }
2511
+ const msgs = JSON.parse(data);
2512
+ for (const msg of Array.isArray(msgs) ? msgs : [msgs]) {
2513
+ console.log(
2514
+ `sent to actor=${this.actor}: [${_nullishCoalesce(SERVER_MSG_CODE_NAMES[msg.type], () => ( msg.type))}] ${JSON.stringify(msg)}`
2515
+ );
2516
+ }
2517
+ }
2518
+ return sent;
2519
+ }
2520
+ /**
2521
+ * @internal
2522
+ * Closes the socket associated to this BrowserSession.
2523
+ *
2524
+ * NOTE: Never call this API directly! Call .endBrowserSession() instead.
2525
+ */
2526
+ closeSocket(code, reason) {
2527
+ __privateGet(this, __socket).close(code, reason);
2528
+ }
2529
+ };
2530
+ __socket = new WeakMap();
2531
+ __debug = new WeakMap();
2532
+ __lastActiveAt = new WeakMap();
2533
+ __hasNotifiedClientStorageUpdateError = new WeakMap();
2534
+ var BackendSession = class extends BrowserSession {
2535
+ /** @internal Never call this constructor directly */
2536
+ constructor(ticket, socket, debug) {
2537
+ super(ticket, socket, debug);
2538
+ }
2539
+ };
2540
+ var __debug2, __allowStreaming;
2541
+ var Room = class {
2542
+ constructor(meta, options) {
2543
+ // ^^^^^^^^^^ User-defined Room Metadata, Session Metadata, and Client Metadata
2544
+ __publicField(this, "meta");
2545
+ __publicField(this, "driver");
2546
+ __publicField(this, "logger");
2547
+ __publicField(this, "_loadData$", null);
2548
+ __publicField(this, "_data", null);
2549
+ __publicField(this, "_qsize", 0);
2550
+ __publicField(this, "sessions", new UniqueMap((s) => s.actor));
2551
+ __publicField(this, "hooks");
2552
+ __privateAdd(this, __debug2);
2553
+ __privateAdd(this, __allowStreaming);
2554
+ const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _59 => _59.storage]), () => ( makeNewInMemoryDriver()));
2555
+ this.meta = meta;
2556
+ this.driver = driver;
2557
+ this.logger = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _60 => _60.logger]), () => ( BLACK_HOLE));
2558
+ __privateSet(this, __allowStreaming, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _61 => _61.allowStreaming]), () => ( true)));
2559
+ this.hooks = {
2560
+ isClientMsgAllowed: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _62 => _62.hooks, 'optionalAccess', _63 => _63.isClientMsgAllowed]), () => ( (() => {
2561
+ return {
2562
+ allowed: true
2563
+ };
2564
+ }))),
2565
+ // YYY .load() isn't called on the RoomServer yet! As soon as it does, these hooks will get called
2566
+ onRoomWillLoad: _optionalChain([options, 'optionalAccess', _64 => _64.hooks, 'optionalAccess', _65 => _65.onRoomWillLoad]),
2567
+ onRoomDidLoad: _optionalChain([options, 'optionalAccess', _66 => _66.hooks, 'optionalAccess', _67 => _67.onRoomDidLoad]),
2568
+ onRoomWillUnload: _optionalChain([options, 'optionalAccess', _68 => _68.hooks, 'optionalAccess', _69 => _69.onRoomWillUnload]),
2569
+ onRoomDidUnload: _optionalChain([options, 'optionalAccess', _70 => _70.hooks, 'optionalAccess', _71 => _71.onRoomDidUnload]),
2570
+ onSessionDidStart: _optionalChain([options, 'optionalAccess', _72 => _72.hooks, 'optionalAccess', _73 => _73.onSessionDidStart]),
2571
+ onSessionDidEnd: _optionalChain([options, 'optionalAccess', _74 => _74.hooks, 'optionalAccess', _75 => _75.onSessionDidEnd]),
2572
+ postClientMsgStorageDidUpdate: _optionalChain([options, 'optionalAccess', _76 => _76.hooks, 'optionalAccess', _77 => _77.postClientMsgStorageDidUpdate]),
2573
+ postClientMsgYdocDidUpdate: _optionalChain([options, 'optionalAccess', _78 => _78.hooks, 'optionalAccess', _79 => _79.postClientMsgYdocDidUpdate])
2574
+ };
2575
+ __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _80 => _80.enableDebugLogging]), () => ( false)));
2576
+ }
2577
+ get loadingState() {
2578
+ if (this._loadData$ === null) {
2579
+ return "initial";
2580
+ } else if (this._data === null) {
2581
+ return "loading";
2582
+ } else {
2583
+ return "loaded";
2584
+ }
2585
+ }
2586
+ get numSessions() {
2587
+ return this.sessions.size;
2588
+ }
2589
+ // prettier-ignore
2590
+ get storage() {
2591
+ return this.data.storage;
2592
+ }
2593
+ // prettier-ignore
2594
+ get yjsStorage() {
2595
+ return this.data.yjsStorage;
2596
+ }
2597
+ // prettier-ignore
2598
+ get mutex() {
2599
+ return this.data.mutex;
2600
+ }
2601
+ // prettier-ignore
2602
+ get data() {
2603
+ return _nullishCoalesce(this._data, () => ( raise("Cannot use room before it's loaded")));
2604
+ }
2605
+ // prettier-ignore
2606
+ // ------------------------------------------------------------------------------------
2607
+ // Public API
2608
+ // ------------------------------------------------------------------------------------
2609
+ /**
2610
+ * Initializes the Room, so it's ready to start accepting connections. Safe
2611
+ * to call multiple times. After awaiting `room.load()` the Room is ready to
2612
+ * be used.
2613
+ */
2614
+ async load(ctx) {
2615
+ if (this._loadData$ === null) {
2616
+ this._data = null;
2617
+ this._loadData$ = this._load(ctx).catch((e) => {
2618
+ this._data = null;
2619
+ this._loadData$ = null;
2620
+ throw e;
2621
+ });
2622
+ }
2623
+ return this._loadData$;
2624
+ }
2625
+ /**
2626
+ * Releases the currently-loaded storage tree from worker memory, freeing it
2627
+ * up to be garbage collected. The next time a user will join the room, the
2628
+ * room will be reloaded from storage.
2629
+ */
2630
+ unload(ctx) {
2631
+ _optionalChain([this, 'access', _81 => _81.hooks, 'access', _82 => _82.onRoomWillUnload, 'optionalCall', _83 => _83(ctx)]);
2632
+ if (this._data) {
2633
+ this.storage.unload();
2634
+ this.yjsStorage.unload();
2635
+ }
2636
+ this._loadData$ = null;
2637
+ _optionalChain([this, 'access', _84 => _84.hooks, 'access', _85 => _85.onRoomDidUnload, 'optionalCall', _86 => _86(ctx)]);
2638
+ }
2639
+ /**
2640
+ * Issues a Ticket with a new/unique actor ID
2641
+ *
2642
+ * IMPORTANT! As the caller of this function, you are responsible for
2643
+ * ensuring you trust the values passed in here. Never pass unauthorized
2644
+ * values in here.
2645
+ *
2646
+ * The returned Ticket can be turned into a active Session once the socket
2647
+ * connection is established. If the socket is never established, this
2648
+ * unused Ticket will simply get garbage collected.
2649
+ */
2650
+ async createTicket(options) {
2651
+ const actor$ = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _87 => _87.actor]), () => ( this.getNextActor()));
2652
+ const sessionKey = _nanoid.nanoid.call(void 0, );
2653
+ const info = _optionalChain([options, 'optionalAccess', _88 => _88.info]);
2654
+ const ticket = {
2655
+ version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _89 => _89.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
2656
+ actor: await actor$,
2657
+ sessionKey,
2658
+ meta: _optionalChain([options, 'optionalAccess', _90 => _90.meta]),
2659
+ publicMeta: _optionalChain([options, 'optionalAccess', _91 => _91.publicMeta]),
2660
+ user: _optionalChain([options, 'optionalAccess', _92 => _92.id]) ? { id: options.id, info } : { anonymousId: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _93 => _93.anonymousId]), () => ( _nanoid.nanoid.call(void 0, ))), info },
2661
+ scopes: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _94 => _94.scopes]), () => ( ["room:write"]))
2662
+ };
2663
+ if (__privateGet(this, __debug2)) {
2664
+ console.log(`new ticket created: ${JSON.stringify(ticket)}`);
2665
+ }
2666
+ return ticket;
2667
+ }
2668
+ async createBackendSession_experimental() {
2669
+ const ticket = await this.createTicket();
2670
+ const capturedServerMsgs = [];
2671
+ const stub = {
2672
+ send: (data) => {
2673
+ if (typeof data === "string") {
2674
+ capturedServerMsgs.push(data);
2675
+ }
2676
+ return 0;
2677
+ },
2678
+ close: () => {
2679
+ }
2680
+ // noop
2681
+ };
2682
+ const session = new BackendSession(ticket, stub, false);
2683
+ return [session, capturedServerMsgs];
2684
+ }
2685
+ /**
2686
+ * Restores the given sessions as the Room server's session list. Can only be
2687
+ * called as long as there are no existing sessions.
2688
+ *
2689
+ * The key difference with the .startBrowserSession() API is that restoreSessions is
2690
+ * used in cases where a session was hibernated and needs to be restored,
2691
+ * without _conceptually_ starting a new session.
2692
+ *
2693
+ * Because there are no side effects to restoreSession, it's synchronous.
2694
+ */
2695
+ restoreSessions(sessions) {
2696
+ if (this.sessions.size > 0) {
2697
+ throw new Error("This API can only be called before any sessions exist");
2698
+ }
2699
+ for (const { ticket, socket, lastActivity } of sessions) {
2700
+ const newSession = new BrowserSession(ticket, socket, __privateGet(this, __debug2));
2701
+ this.sessions.set(ticket.sessionKey, newSession);
2702
+ newSession.markActive(lastActivity);
2703
+ }
2704
+ }
2705
+ /**
2706
+ * Registers a new BrowserSession into the Room server's session list, along with
2707
+ * the socket connection to use for that BrowserSession, now that it is known.
2708
+ *
2709
+ * This kicks off a few side effects:
2710
+ * - Sends a ROOM_STATE message to the socket.
2711
+ * - Broadcasts a USER_JOINED message to all other sessions in the room.
2712
+ */
2713
+ startBrowserSession(ticket, socket, ctx, defer = () => {
2714
+ throw new Error(
2715
+ "One of your hook handlers returned a promise, but no side effect collector was provided. Pass a `defer` callback to startBrowserSession() to collect async side effects."
2716
+ );
2717
+ }) {
2718
+ let existing;
2719
+ while ((existing = this.sessions.lookupPrimaryKey(ticket.actor)) !== void 0) {
2720
+ this.endBrowserSession(
2721
+ existing,
2722
+ WebsocketCloseCodes.KICKED,
2723
+ "Closed stale connection",
2724
+ ctx,
2725
+ defer
2726
+ );
2727
+ this.logger.warn(
2728
+ `Previous session for actor ${ticket.actor} killed in favor of new session`
2729
+ );
2730
+ }
2731
+ const newSession = new BrowserSession(ticket, socket, __privateGet(this, __debug2));
2732
+ this.sessions.set(ticket.sessionKey, newSession);
2733
+ const users = {};
2734
+ for (const session of this.otherSessions(ticket.sessionKey)) {
2735
+ users[session.actor] = {
2736
+ id: session.user.id,
2737
+ info: session.user.info,
2738
+ scopes: session.scopes
2739
+ };
2740
+ }
2741
+ newSession.send(
2742
+ makeRoomStateMsg(
2743
+ newSession.actor,
2744
+ ticket.sessionKey,
2745
+ // called "nonce" in the protocol
2746
+ newSession.scopes,
2747
+ users,
2748
+ ticket.publicMeta
2749
+ )
2750
+ );
2751
+ this.sendToOthers(
2752
+ ticket.sessionKey,
2753
+ {
2754
+ type: ServerMsgCode.USER_JOINED,
2755
+ actor: newSession.actor,
2756
+ id: newSession.user.id,
2757
+ info: newSession.user.info,
2758
+ scopes: newSession.scopes
2759
+ },
2760
+ ctx,
2761
+ defer
2762
+ );
2763
+ const p$ = _optionalChain([this, 'access', _95 => _95.hooks, 'access', _96 => _96.onSessionDidStart, 'optionalCall', _97 => _97(newSession, ctx)]);
2764
+ if (p$) defer(p$);
2765
+ }
2766
+ /**
2767
+ * Unregisters the BrowserSession for the given actor. Call this when the socket has
2768
+ * been closed from the client's end.
2769
+ *
2770
+ * This kicks off a few side effects:
2771
+ * - Broadcasts a USER_LEFT message to all other sessions in the room.
2772
+ */
2773
+ endBrowserSession(key, code, reason, ctx, defer = () => {
2774
+ throw new Error(
2775
+ "Your onSessionDidEnd handler returned a promise, but no side effect collector was provided. Pass a `defer` callback to endBrowserSession() to collect async side effects."
2776
+ );
2777
+ }) {
2778
+ const sessions = this.sessions;
2779
+ const session = sessions.get(key);
2780
+ if (session === void 0) return;
2781
+ session.closeSocket(code, reason);
2782
+ const deleted = sessions.delete(key);
2783
+ if (deleted) {
2784
+ for (const other of this.otherSessions(key)) {
2785
+ other.send({ type: ServerMsgCode.USER_LEFT, actor: session.actor });
2786
+ }
2787
+ const p$ = _optionalChain([this, 'access', _98 => _98.hooks, 'access', _99 => _99.onSessionDidEnd, 'optionalCall', _100 => _100(session, ctx)]);
2788
+ if (p$) defer(p$);
2789
+ }
2790
+ }
2791
+ /**
2792
+ * Force-closes all sessions matching the given predicate.
2793
+ */
2794
+ endSessionBy(predicate, code, reason, ctx, defer = () => {
2795
+ throw new Error(
2796
+ "Your onSessionDidEnd handler returned a promise, but no side effect collector was provided. Pass a `defer` callback to endSessionBy() to collect async side effects."
2797
+ );
2798
+ }) {
2799
+ let count = 0;
2800
+ for (const [key, session] of this.sessions) {
2801
+ if (predicate(session)) {
2802
+ count++;
2803
+ this.endBrowserSession(key, code, reason, ctx, defer);
2804
+ }
2805
+ }
2806
+ return count;
2807
+ }
2808
+ /**
2809
+ * Handles a raw incoming socket message, which can be a ping, or an
2810
+ * JSON-encoded message batch.
2811
+ */
2812
+ async handleData(key, data, ctx, defer = () => {
2813
+ throw new Error(
2814
+ "One of your hook handlers returned a promise, but no side effect collector was provided. Pass a `defer` callback to handleData() to collect async side effects."
2815
+ );
2816
+ }) {
2817
+ const text = typeof data === "string" ? data : raise("Unsupported message format");
2818
+ if (text === "ping") {
2819
+ await this.handlePing(key, ctx);
2820
+ } else {
2821
+ const json = tryParseJson(text);
2822
+ const messages = messagesDecoder.decode(json);
2823
+ if (!messages.ok) {
2824
+ const reason = process.env.NODE_ENV !== "production" ? _decoders.formatInline.call(void 0, messages.error) : "Invalid message format";
2825
+ this.endBrowserSession(
2826
+ key,
2827
+ WebsocketCloseCodes.INVALID_MESSAGE_FORMAT,
2828
+ reason,
2829
+ ctx,
2830
+ defer
2831
+ );
2832
+ return;
2833
+ }
2834
+ if (this._qsize > 1e4) {
2835
+ } else if (this._qsize > 5e3) {
2836
+ }
2837
+ this._qsize++;
2838
+ try {
2839
+ await this.processClientMsg(key, messages.value, ctx);
2840
+ } finally {
2841
+ this._qsize--;
2842
+ }
2843
+ }
2844
+ }
2845
+ /**
2846
+ * Processes an incoming batch of 1 or more ClientMsgs on behalf of
2847
+ * a (regular user/browser) session.
2848
+ *
2849
+ * IMPORTANT: Only use this API on "trusted" data!
2850
+ * To handle untrusted input data, use `.handleData()` instead.
2851
+ *
2852
+ * Before calling this API, make sure:
2853
+ * 1. The call site is entitled to call this message on behalf of this session; and
2854
+ * 2. The ClientMsg payload has been validated to be correct.
2855
+ */
2856
+ async processClientMsg(key, messages, ctx) {
2857
+ await this.load(ctx);
2858
+ const { defer, waitAll } = collectSideEffects();
2859
+ await this.mutex.runExclusive(
2860
+ () => this._processClientMsg_withExclusiveAccess(key, messages, ctx, defer)
2861
+ );
2862
+ await waitAll();
2863
+ }
2864
+ /**
2865
+ * Processes an incoming batch of 1 or more ClientMsgs on behalf of
2866
+ * a BACKEND session.
2867
+ *
2868
+ * Difference 1: HTTP RESPONSE instead of WEB SOCKET RESPONSE
2869
+ * ----------------------------------------------------------
2870
+ * For "normal" sessions that have a socket attached, any "responses" (i.e.
2871
+ * server messages like acks or fixops) will be sent back through that
2872
+ * existing socket connection.
2873
+ *
2874
+ * The key difference when using this method is that there is no such socket,
2875
+ * so any "response" ServerMsgs will get sent back as an HTTP response.
2876
+ *
2877
+ * Difference 2: No auth check
2878
+ * ---------------------------
2879
+ * Another key difference is that when processing a backend session, no
2880
+ * "isClientMsgAllowed()" check is performed, because those checks assume
2881
+ * a session.
2882
+ */
2883
+ async processClientMsgFromBackendSession(session, messages, ctx) {
2884
+ await this.load(ctx);
2885
+ const { defer, waitAll } = collectSideEffects();
2886
+ await this.mutex.runExclusive(
2887
+ () => this._processClientMsgFromBackendSession_withExclusiveAccess(
2888
+ session,
2889
+ messages,
2890
+ ctx,
2891
+ defer
2892
+ )
2893
+ );
2894
+ await waitAll();
2895
+ }
2896
+ getSession(sessionKey) {
2897
+ return this.sessions.get(sessionKey);
2898
+ }
2899
+ listSessions() {
2900
+ return Array.from(this.sessions.values());
2901
+ }
2902
+ /**
2903
+ * Will send the given ServerMsg to all Sessions, except the Session
2904
+ * where the message originates from.
2905
+ */
2906
+ sendToOthers(sender, serverMsg, ctx, defer = () => {
2907
+ throw new Error(
2908
+ "One of your hook handlers returned a promise, but no side effect collector was provided. Pass a `defer` callback to sendToOthers() to collect async side effects."
2909
+ );
2910
+ }) {
2911
+ const msg = serialize(serverMsg);
2912
+ for (const [key, session] of this.otherSessionEntries(sender)) {
2913
+ const success = session.send(msg);
2914
+ if (success === 0) {
2915
+ this.endBrowserSession(
2916
+ key,
2917
+ WebsocketCloseCodes.KICKED,
2918
+ "Closed broken connection",
2919
+ ctx,
2920
+ defer
2921
+ );
2922
+ }
2923
+ }
2924
+ }
2925
+ /**
2926
+ * Will broadcast the given ServerMsg to all Sessions in the Room.
2927
+ */
2928
+ sendToAll(serverMsg, ctx, defer = () => {
2929
+ throw new Error(
2930
+ "One of your hook handlers returned a promise, but no side effect collector was provided. Pass a `defer` callback to sendToAll() to collect async side effects."
2931
+ );
2932
+ }) {
2933
+ const msg = serialize(serverMsg);
2934
+ for (const [key, session] of this.sessions) {
2935
+ const success = session.send(msg);
2936
+ if (success === 0) {
2937
+ this.endBrowserSession(
2938
+ key,
2939
+ WebsocketCloseCodes.KICKED,
2940
+ "Closed broken connection",
2941
+ ctx,
2942
+ defer
2943
+ );
2944
+ }
2945
+ }
2946
+ }
2947
+ // ------------------------------------------------------------------------------------
2948
+ // Private APIs
2949
+ // ------------------------------------------------------------------------------------
2950
+ async _loadStorage() {
2951
+ const storage = new Storage(this.driver);
2952
+ await storage.load(this.logger);
2953
+ return storage;
2954
+ }
2955
+ async _loadYjsStorage() {
2956
+ const yjsStorage = new YjsStorage(this.driver);
2957
+ await yjsStorage.load(this.logger);
2958
+ return yjsStorage;
2959
+ }
2960
+ // Don't ever manually call this!
2961
+ async _load(ctx) {
2962
+ await _optionalChain([this, 'access', _101 => _101.hooks, 'access', _102 => _102.onRoomWillLoad, 'optionalCall', _103 => _103(ctx)]);
2963
+ const storage = await this._loadStorage();
2964
+ const yjsStorage = await this._loadYjsStorage();
2965
+ this._data = {
2966
+ mutex: new (0, _asyncmutex.Mutex)(),
2967
+ storage,
2968
+ yjsStorage
2969
+ };
2970
+ await _optionalChain([this, 'access', _104 => _104.hooks, 'access', _105 => _105.onRoomDidLoad, 'optionalCall', _106 => _106(ctx)]);
2971
+ }
2972
+ /**
2973
+ * Returns a new, unique, actor ID.
2974
+ */
2975
+ async getNextActor() {
2976
+ return await this.driver.next_actor();
2977
+ }
2978
+ /**
2979
+ * Iterates over all *other* Sessions and their session keys.
2980
+ */
2981
+ *otherSessionEntries(currentKey) {
2982
+ for (const [key, session] of this.sessions) {
2983
+ if (key !== currentKey) {
2984
+ yield [key, session];
2985
+ }
2986
+ }
2987
+ }
2988
+ /**
2989
+ * Iterates over all *other* Sessions.
2990
+ */
2991
+ *otherSessions(currentKey) {
2992
+ for (const [key, session] of this.sessions) {
2993
+ if (key !== currentKey) {
2994
+ yield session;
2995
+ }
2996
+ }
2997
+ }
2998
+ /**
2999
+ * @internal
3000
+ * Handles an incoming ping, by sending a pong back.
3001
+ */
3002
+ // eslint-disable-next-line @typescript-eslint/require-await
3003
+ async handlePing(sessionKey, ctx) {
3004
+ const session = this.sessions.get(sessionKey);
3005
+ if (session === void 0) {
3006
+ this.logger.withContext({ sessionKey }).warn("[probe] in handlePing, no such session exists");
3007
+ return;
3008
+ }
3009
+ const sent = session.sendPong();
3010
+ if (sent !== 0) {
3011
+ await _optionalChain([this, 'access', _107 => _107.hooks, 'access', _108 => _108.onDidPong, 'optionalCall', _109 => _109(ctx)]);
3012
+ }
3013
+ }
3014
+ async _processClientMsg_withExclusiveAccess(sessionKey, messages, ctx, defer) {
3015
+ const session = this.sessions.get(sessionKey);
3016
+ if (!session) {
3017
+ this.logger.withContext({ sessionKey }).warn("[probe] in handleClientMsgs, no such session exists");
3018
+ return;
3019
+ }
3020
+ const toFanOut = [];
3021
+ const toReply = [];
3022
+ const replyImmediately = (msg) => void session.send(msg);
3023
+ const scheduleFanOut = (msg) => void toFanOut.push(msg);
3024
+ const scheduleReply = (msg) => void toReply.push(msg);
3025
+ for (const msg of messages) {
3026
+ const isMsgAllowed = this.hooks.isClientMsgAllowed(msg, session);
3027
+ if (isMsgAllowed.allowed) {
3028
+ await this.handleOne(
3029
+ session,
3030
+ msg,
3031
+ replyImmediately,
3032
+ scheduleFanOut,
3033
+ scheduleReply,
3034
+ ctx,
3035
+ defer
3036
+ );
3037
+ } else {
3038
+ if (!session.hasNotifiedClientStorageUpdateError) {
3039
+ toReply.push({
3040
+ type: ServerMsgCode.REJECT_STORAGE_OP,
3041
+ opIds: msg.type === ClientMsgCode.UPDATE_STORAGE ? msg.ops.map((op2) => op2.opId) : [],
3042
+ reason: isMsgAllowed.reason
3043
+ });
3044
+ session.setHasNotifiedClientStorageUpdateError();
3045
+ }
3046
+ }
3047
+ }
3048
+ if (toFanOut.length > 0) {
3049
+ this.sendToOthers(sessionKey, toFanOut, ctx, defer);
3050
+ }
3051
+ if (toReply.length > 0) {
3052
+ session.send(toReply);
3053
+ }
3054
+ }
3055
+ // TODO It's a bit bothering how much duplication there is between this method
3056
+ // and the _processClientMsg_withExclusiveAccess version. A better
3057
+ // abstraction is needed.
3058
+ async _processClientMsgFromBackendSession_withExclusiveAccess(session, messages, ctx, defer) {
3059
+ const toFanOut = [];
3060
+ const toReplyImmediately = [];
3061
+ const toReplyAfter = [];
3062
+ const replyImmediately = (msg) => {
3063
+ if (Array.isArray(msg)) {
3064
+ for (const m of msg) {
3065
+ toReplyImmediately.push(m);
3066
+ }
3067
+ } else {
3068
+ toReplyImmediately.push(msg);
3069
+ }
3070
+ };
3071
+ const scheduleFanOut = (msg) => void toFanOut.push(msg);
3072
+ const scheduleReply = (msg) => void toReplyAfter.push(msg);
3073
+ for (const msg of messages) {
3074
+ await this.handleOne(
3075
+ session,
3076
+ msg,
3077
+ replyImmediately,
3078
+ scheduleFanOut,
3079
+ scheduleReply,
3080
+ ctx,
3081
+ defer
3082
+ );
3083
+ }
3084
+ if (toReplyImmediately.length > 0) {
3085
+ session.send(toReplyImmediately);
3086
+ toReplyImmediately.length = 0;
3087
+ }
3088
+ if (toFanOut.length > 0) {
3089
+ this.sendToOthers("(transient)", toFanOut, ctx, defer);
3090
+ toFanOut.length = 0;
3091
+ }
3092
+ if (toReplyAfter.length > 0) {
3093
+ session.send(toReplyAfter);
3094
+ toReplyAfter.length = 0;
3095
+ }
3096
+ }
3097
+ async handleOne(session, msg, replyImmediately, scheduleFanOut, scheduleReply, ctx, defer) {
3098
+ if (!this.mutex.isLocked()) {
3099
+ throw new Error("Handling messages requires exclusive access");
3100
+ }
3101
+ switch (msg.type) {
3102
+ case ClientMsgCode.UPDATE_PRESENCE: {
3103
+ scheduleFanOut({
3104
+ type: ServerMsgCode.UPDATE_PRESENCE,
3105
+ actor: session.actor,
3106
+ data: msg.data,
3107
+ targetActor: msg.targetActor
3108
+ });
3109
+ break;
3110
+ }
3111
+ case ClientMsgCode.BROADCAST_EVENT: {
3112
+ scheduleFanOut({
3113
+ type: ServerMsgCode.BROADCASTED_EVENT,
3114
+ actor: session.actor,
3115
+ event: msg.event
3116
+ });
3117
+ break;
3118
+ }
3119
+ case ClientMsgCode.FETCH_STORAGE: {
3120
+ if (session.version >= 8 /* V8 */) {
3121
+ if (__privateGet(this, __allowStreaming)) {
3122
+ const NODES_PER_CHUNK = 250;
3123
+ for (const chunk of _itertools.chunked.call(void 0,
3124
+ nodeStreamToCompactNodes(this.storage.loadedDriver.iter_nodes()),
3125
+ NODES_PER_CHUNK
3126
+ )) {
3127
+ replyImmediately({
3128
+ type: ServerMsgCode.STORAGE_CHUNK,
3129
+ nodes: chunk
3130
+ });
3131
+ }
3132
+ } else {
3133
+ replyImmediately({
3134
+ type: ServerMsgCode.STORAGE_CHUNK,
3135
+ nodes: Array.from(
3136
+ nodeStreamToCompactNodes(this.storage.loadedDriver.iter_nodes())
3137
+ )
3138
+ });
3139
+ }
3140
+ replyImmediately({ type: ServerMsgCode.STORAGE_STREAM_END });
3141
+ } else {
3142
+ replyImmediately({
3143
+ type: ServerMsgCode.STORAGE_STATE_V7,
3144
+ items: Array.from(this.storage.loadedDriver.iter_nodes())
3145
+ });
3146
+ }
3147
+ break;
3148
+ }
3149
+ case ClientMsgCode.UPDATE_STORAGE: {
3150
+ _optionalChain([this, 'access', _110 => _110.driver, 'access', _111 => _111.bump_storage_version, 'optionalCall', _112 => _112()]);
3151
+ const result = await this.storage.applyOps(msg.ops);
3152
+ const opsToForward = result.flatMap(
3153
+ (r) => r.action === "accepted" ? [r.op] : []
3154
+ );
3155
+ const opsToSendBack = result.flatMap((r) => {
3156
+ switch (r.action) {
3157
+ case "ignored":
3158
+ return r.ignoredOpId !== void 0 ? [ackIgnoredOp(r.ignoredOpId)] : [];
3159
+ case "accepted":
3160
+ return r.fix !== void 0 ? [r.fix] : [];
3161
+ default:
3162
+ return assertNever(r, "Unhandled case");
3163
+ }
3164
+ });
3165
+ if (opsToForward.length > 0) {
3166
+ scheduleFanOut({
3167
+ type: ServerMsgCode.UPDATE_STORAGE,
3168
+ ops: opsToForward.map(stripOpId)
3169
+ });
3170
+ scheduleReply({
3171
+ type: ServerMsgCode.UPDATE_STORAGE,
3172
+ ops: opsToForward
3173
+ });
3174
+ }
3175
+ if (opsToSendBack.length > 0) {
3176
+ replyImmediately({
3177
+ type: ServerMsgCode.UPDATE_STORAGE,
3178
+ ops: opsToSendBack
3179
+ });
3180
+ }
3181
+ if (opsToForward.length > 0) {
3182
+ const p$ = _optionalChain([this, 'access', _113 => _113.hooks, 'access', _114 => _114.postClientMsgStorageDidUpdate, 'optionalCall', _115 => _115(ctx)]);
3183
+ if (p$) defer(p$);
3184
+ }
3185
+ break;
3186
+ }
3187
+ case ClientMsgCode.FETCH_YDOC: {
3188
+ const vector = msg.vector;
3189
+ const guid = msg.guid;
3190
+ const isV2 = msg.v2;
3191
+ const [update, stateVector, snapshotHash] = await Promise.all([
3192
+ this.yjsStorage.getYDocUpdate(this.logger, vector, guid, isV2),
3193
+ this.yjsStorage.getYStateVector(guid),
3194
+ this.yjsStorage.getSnapshotHash({ guid, isV2 })
3195
+ ]);
3196
+ if (update !== null && snapshotHash !== null) {
3197
+ replyImmediately({
3198
+ type: ServerMsgCode.UPDATE_YDOC,
3199
+ update,
3200
+ isSync: true,
3201
+ // this is no longer used by the client, instead we use the presence of stateVector
3202
+ stateVector,
3203
+ guid,
3204
+ v2: isV2,
3205
+ remoteSnapshotHash: snapshotHash
3206
+ });
3207
+ }
3208
+ break;
3209
+ }
3210
+ case ClientMsgCode.UPDATE_YDOC: {
3211
+ const update = msg.update;
3212
+ const guid = msg.guid;
3213
+ const isV2 = msg.v2;
3214
+ const [result, error3] = await tryCatch(
3215
+ this.yjsStorage.addYDocUpdate(this.logger, update, guid, isV2)
3216
+ );
3217
+ if (error3)
3218
+ break;
3219
+ this.sendToAll(
3220
+ {
3221
+ type: ServerMsgCode.UPDATE_YDOC,
3222
+ update,
3223
+ guid,
3224
+ isSync: false,
3225
+ stateVector: null,
3226
+ v2: isV2,
3227
+ remoteSnapshotHash: result.snapshotHash
3228
+ },
3229
+ ctx,
3230
+ defer
3231
+ );
3232
+ if (result.isUpdated) {
3233
+ const p$ = _optionalChain([this, 'access', _116 => _116.hooks, 'access', _117 => _117.postClientMsgYdocDidUpdate, 'optionalCall', _118 => _118(ctx, session)]);
3234
+ if (p$) defer(p$);
3235
+ }
3236
+ break;
3237
+ }
3238
+ default: {
3239
+ try {
3240
+ return assertNever(msg, "Unrecognized client msg");
3241
+ } catch (e2) {
3242
+ }
3243
+ }
3244
+ }
3245
+ }
3246
+ };
3247
+ __debug2 = new WeakMap();
3248
+ __allowStreaming = new WeakMap();
3249
+
3250
+
3251
+
3252
+
3253
+
3254
+
3255
+
3256
+
3257
+
3258
+
3259
+
3260
+
3261
+
3262
+
3263
+
3264
+
3265
+
3266
+
3267
+
3268
+
3269
+
3270
+
3271
+
3272
+
3273
+
3274
+
3275
+
3276
+
3277
+
3278
+
3279
+
3280
+
3281
+
3282
+
3283
+
3284
+ exports.BackendSession = BackendSession; exports.BrowserSession = BrowserSession; exports.ConsoleTarget = ConsoleTarget; exports.DefaultMap = DefaultMap2; exports.InMemoryDriver = InMemoryDriver; exports.LogLevel = LogLevel; exports.LogTarget = LogTarget; exports.Logger = Logger; exports.NestedMap = NestedMap; exports.ProtocolVersion = ProtocolVersion; exports.ROOT_YDOC_ID = ROOT_YDOC_ID; exports.Room = Room; exports.UniqueMap = UniqueMap; exports.ackIgnoredOp = ackIgnoredOp; exports.clientMsgDecoder = clientMsgDecoder; exports.concatUint8Arrays = concatUint8Arrays; exports.guidDecoder = guidDecoder; exports.jsonObjectYolo = jsonObjectYolo; exports.jsonYolo = jsonYolo; exports.makeInMemorySnapshot = makeInMemorySnapshot; exports.makeMetadataDB = makeMetadataDB; exports.plainLsonToNodeStream = plainLsonToNodeStream; exports.protocolVersionDecoder = protocolVersionDecoder; exports.quote = quote; exports.serializeServerMsg = serialize; exports.snapshotToLossyJson_eager = snapshotToLossyJson_eager; exports.snapshotToLossyJson_lazy = snapshotToLossyJson_lazy; exports.snapshotToNodeStream = snapshotToNodeStream; exports.snapshotToPlainLson_eager = snapshotToPlainLson_eager; exports.snapshotToPlainLson_lazy = snapshotToPlainLson_lazy; exports.test_only__Storage = Storage; exports.test_only__YjsStorage = YjsStorage; exports.transientClientMsgDecoder = transientClientMsgDecoder; exports.tryCatch = tryCatch;
3285
+ //# sourceMappingURL=index.cjs.map