@liveblocks/server 1.6.2 → 1.8.0-pre1

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 CHANGED
@@ -165,7 +165,21 @@ var jsonObjectYolo = jsonYolo.refine(
165
165
 
166
166
 
167
167
 
168
+
169
+
170
+
171
+
172
+
173
+
168
174
  var intent = _decoders.oneOf.call(void 0, ["set", "push"]);
175
+ var storageFileId = _decoders.sized.call(void 0, _decoders.startsWith.call(void 0, "fl_"), { size: 24 });
176
+ var fileSize = _decoders.number.refine(
177
+ (value) => Number.isSafeInteger(value) && value >= 0,
178
+ "Must be a valid file size"
179
+ );
180
+ var liveTextVersion = _decoders.number.reject(
181
+ (value) => Number.isSafeInteger(value) && value >= 0 ? null : "Must be a non-negative safe integer"
182
+ );
169
183
  var updateObjectOp = _decoders.object.call(void 0, {
170
184
  type: _decoders.constant.call(void 0, _core.OpCode.UPDATE_OBJECT),
171
185
  opId: _decoders.string,
@@ -210,6 +224,64 @@ var createRegisterOp = _decoders.object.call(void 0, {
210
224
  intent: _decoders.optional.call(void 0, intent),
211
225
  deletedId: _decoders.optional.call(void 0, _decoders.string)
212
226
  });
227
+ var liveTextSegment = _decoders.either.call(void 0,
228
+ _decoders.tuple.call(void 0, _decoders.string),
229
+ _decoders.tuple.call(void 0, _decoders.string, jsonObjectYolo)
230
+ );
231
+ var liveTextData = _decoders.array.call(void 0, liveTextSegment);
232
+ var textOperation = _decoders.taggedUnion.call(void 0, "type", {
233
+ insert: _decoders.object.call(void 0, {
234
+ type: _decoders.constant.call(void 0, "insert"),
235
+ index: _decoders.number,
236
+ text: _decoders.string,
237
+ attributes: _decoders.optional.call(void 0, jsonObjectYolo)
238
+ }),
239
+ delete: _decoders.object.call(void 0, {
240
+ type: _decoders.constant.call(void 0, "delete"),
241
+ index: _decoders.number,
242
+ length: _decoders.number
243
+ }),
244
+ format: _decoders.object.call(void 0, {
245
+ type: _decoders.constant.call(void 0, "format"),
246
+ index: _decoders.number,
247
+ length: _decoders.number,
248
+ attributes: jsonObjectYolo
249
+ })
250
+ });
251
+ var createTextOp = _decoders.object.call(void 0, {
252
+ type: _decoders.constant.call(void 0, _core.OpCode.CREATE_TEXT),
253
+ opId: _decoders.string,
254
+ id: _decoders.string,
255
+ parentId: _decoders.string,
256
+ parentKey: _decoders.string,
257
+ data: liveTextData,
258
+ version: liveTextVersion,
259
+ intent: _decoders.optional.call(void 0, intent),
260
+ deletedId: _decoders.optional.call(void 0, _decoders.string)
261
+ });
262
+ var createFileOp = _decoders.object.call(void 0, {
263
+ type: _decoders.constant.call(void 0, _core.OpCode.CREATE_FILE),
264
+ opId: _decoders.string,
265
+ id: _decoders.string,
266
+ parentId: _decoders.string,
267
+ parentKey: _decoders.string,
268
+ data: _decoders.object.call(void 0, {
269
+ id: storageFileId,
270
+ name: _decoders.string,
271
+ size: fileSize,
272
+ mimeType: _decoders.string
273
+ }),
274
+ intent: _decoders.optional.call(void 0, intent),
275
+ deletedId: _decoders.optional.call(void 0, _decoders.string)
276
+ });
277
+ var updateTextOp = _decoders.object.call(void 0, {
278
+ type: _decoders.constant.call(void 0, _core.OpCode.UPDATE_TEXT),
279
+ opId: _decoders.string,
280
+ id: _decoders.string,
281
+ baseVersion: liveTextVersion,
282
+ version: _decoders.optional.call(void 0, liveTextVersion),
283
+ ops: _decoders.array.call(void 0, textOperation)
284
+ });
213
285
  var deleteCrdtOp = _decoders.object.call(void 0, {
214
286
  type: _decoders.constant.call(void 0, _core.OpCode.DELETE_CRDT),
215
287
  opId: _decoders.string,
@@ -233,6 +305,9 @@ var op = _decoders.taggedUnion.call(void 0, "type", {
233
305
  [_core.OpCode.CREATE_LIST]: createListOp,
234
306
  [_core.OpCode.CREATE_MAP]: createMapOp,
235
307
  [_core.OpCode.CREATE_REGISTER]: createRegisterOp,
308
+ [_core.OpCode.CREATE_TEXT]: createTextOp,
309
+ [_core.OpCode.UPDATE_TEXT]: updateTextOp,
310
+ [_core.OpCode.CREATE_FILE]: createFileOp,
236
311
  [_core.OpCode.DELETE_CRDT]: deleteCrdtOp,
237
312
  [_core.OpCode.SET_PARENT_KEY]: setParentKeyOp,
238
313
  [_core.OpCode.DELETE_OBJECT_KEY]: deleteObjectKeyOp
@@ -372,6 +447,10 @@ function buildNode(snapshot2, id) {
372
447
  return buildList(snapshot2, id);
373
448
  } else if (node.type === _core.CrdtType.MAP) {
374
449
  return buildMap(snapshot2, id);
450
+ } else if (node.type === _core.CrdtType.TEXT) {
451
+ return node.data;
452
+ } else if (node.type === _core.CrdtType.FILE) {
453
+ return node.data;
375
454
  } else {
376
455
  return node.data;
377
456
  }
@@ -415,6 +494,10 @@ function* emit(snapshot2, id) {
415
494
  yield* emitMap(snapshot2, id);
416
495
  } else if (node.type === _core.CrdtType.REGISTER) {
417
496
  yield JSON.stringify(node.data);
497
+ } else if (node.type === _core.CrdtType.TEXT) {
498
+ yield JSON.stringify(node.data);
499
+ } else if (node.type === _core.CrdtType.FILE) {
500
+ yield JSON.stringify(node.data);
418
501
  }
419
502
  }
420
503
  function* emitObject(snapshot2, id, staticJson) {
@@ -486,6 +569,29 @@ function* iterJson(key, data, parent, state) {
486
569
  case "LiveMap":
487
570
  yield* iterMap(key, data.data, parent, state);
488
571
  return;
572
+ case "LiveText":
573
+ yield [
574
+ generateId(state),
575
+ {
576
+ type: _core.CrdtType.TEXT,
577
+ data: data.data,
578
+ version: _nullishCoalesce(data.version, () => ( 0)),
579
+ parentId: parent[0],
580
+ parentKey: key
581
+ }
582
+ ];
583
+ return;
584
+ case "LiveFile":
585
+ yield [
586
+ generateId(state),
587
+ {
588
+ type: _core.CrdtType.FILE,
589
+ data: data.data,
590
+ parentId: parent[0],
591
+ parentKey: key
592
+ }
593
+ ];
594
+ return;
489
595
  // istanbul ignore next
490
596
  default:
491
597
  _core.assertNever.call(void 0, data, "Unknown `liveblocksType` field");
@@ -570,6 +676,13 @@ function buildNode2(snapshot2, id) {
570
676
  return buildList2(snapshot2, id);
571
677
  } else if (node.type === _core.CrdtType.MAP) {
572
678
  return buildMap2(snapshot2, id);
679
+ } else if (node.type === _core.CrdtType.TEXT) {
680
+ return {
681
+ liveblocksType: "LiveText",
682
+ data: node.data
683
+ };
684
+ } else if (node.type === _core.CrdtType.FILE) {
685
+ return { liveblocksType: "LiveFile", data: node.data };
573
686
  } else {
574
687
  return _nullishCoalesce(node.data, () => ( null));
575
688
  }
@@ -616,6 +729,15 @@ function* emit2(snapshot2, id) {
616
729
  yield* emitMap2(snapshot2, id);
617
730
  } else if (node.type === _core.CrdtType.REGISTER) {
618
731
  yield JSON.stringify(_nullishCoalesce(node.data, () => ( null)));
732
+ } else if (node.type === _core.CrdtType.TEXT) {
733
+ yield JSON.stringify({
734
+ liveblocksType: "LiveText",
735
+ data: node.data
736
+ });
737
+ } else if (node.type === _core.CrdtType.FILE) {
738
+ yield '{"liveblocksType":"LiveFile","data":';
739
+ yield JSON.stringify(node.data);
740
+ yield "}";
619
741
  }
620
742
  }
621
743
  function* emitObject2(snapshot2, id, staticJson) {
@@ -1012,9 +1134,10 @@ function buildReverseLookup(nodes) {
1012
1134
  delete node.data[key];
1013
1135
  }
1014
1136
  }
1015
- if (node.type !== _core.CrdtType.REGISTER) {
1137
+ const isLeafNode = node.type === _core.CrdtType.REGISTER || node.type === _core.CrdtType.FILE || node.type === _core.CrdtType.TEXT;
1138
+ if (!isLeafNode) {
1016
1139
  queue.push(...revNodes.valuesAt(nodeId));
1017
- } else {
1140
+ } else if (node.type === _core.CrdtType.REGISTER) {
1018
1141
  const parent = nodes.get(node.parentId);
1019
1142
  if (_optionalChain([parent, 'optionalAccess', _34 => _34.type]) === _core.CrdtType.OBJECT) {
1020
1143
  continue;
@@ -1035,7 +1158,6 @@ function hasStaticDataAt(node, key) {
1035
1158
  return node.type === _core.CrdtType.OBJECT && Object.prototype.hasOwnProperty.call(node.data, key) && node.data[key] !== void 0;
1036
1159
  }
1037
1160
  var InMemoryDriver = class {
1038
- // Key: `${feedId}:${messageId}`
1039
1161
  constructor(options) {
1040
1162
  __publicField(this, "_nextActor");
1041
1163
  __publicField(this, "_nodes");
@@ -1045,12 +1167,15 @@ var InMemoryDriver = class {
1045
1167
  __publicField(this, "_leasedSessions");
1046
1168
  __publicField(this, "_feeds");
1047
1169
  __publicField(this, "_feedMessages");
1170
+ // Key: `${feedId}:${messageId}`
1171
+ __publicField(this, "_liveTextHistory");
1048
1172
  this._nodes = /* @__PURE__ */ new Map();
1049
1173
  this._metadb = /* @__PURE__ */ new Map();
1050
1174
  this._ydb = /* @__PURE__ */ new Map();
1051
1175
  this._leasedSessions = /* @__PURE__ */ new Map();
1052
1176
  this._feeds = /* @__PURE__ */ new Map();
1053
1177
  this._feedMessages = /* @__PURE__ */ new Map();
1178
+ this._liveTextHistory = /* @__PURE__ */ new Map();
1054
1179
  this._nextActor = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _35 => _35.initialActor]), () => ( -1));
1055
1180
  for (const [key, value] of _nullishCoalesce(_optionalChain([options, 'optionalAccess', _36 => _36.initialNodes]), () => ( []))) {
1056
1181
  this._nodes.set(key, value);
@@ -1066,10 +1191,40 @@ var InMemoryDriver = class {
1066
1191
  DANGEROUSLY_reset_nodes(doc) {
1067
1192
  this.reinitialize();
1068
1193
  this._nodes.clear();
1194
+ this._liveTextHistory.clear();
1069
1195
  for (const [id, node] of plainLsonToNodeStream(doc)) {
1070
1196
  this._nodes.set(id, node);
1071
1197
  }
1072
1198
  }
1199
+ get_live_text_history_since(nodeId, version) {
1200
+ return (_nullishCoalesce(this._liveTextHistory.get(nodeId), () => ( []))).filter((entry) => entry.version > version).sort((left, right) => left.version - right.version).map((entry) => ({ ...entry, ops: [...entry.ops] }));
1201
+ }
1202
+ get_live_text_history_by_op_id(nodeId, opId) {
1203
+ const entry = (_nullishCoalesce(this._liveTextHistory.get(nodeId), () => ( []))).find(
1204
+ (item) => item.opId === opId
1205
+ );
1206
+ return entry === void 0 ? void 0 : { ...entry, ops: [...entry.ops] };
1207
+ }
1208
+ append_live_text_history(entry) {
1209
+ const history = _nullishCoalesce(this._liveTextHistory.get(entry.nodeId), () => ( []));
1210
+ history.push({ ...entry, ops: [...entry.ops] });
1211
+ history.sort((left, right) => left.version - right.version);
1212
+ this._liveTextHistory.set(entry.nodeId, history);
1213
+ }
1214
+ purge_live_text_history_before(nodeId, minVersionToKeep) {
1215
+ const history = this._liveTextHistory.get(nodeId);
1216
+ if (history === void 0) {
1217
+ return;
1218
+ }
1219
+ const retained = history.filter(
1220
+ (entry) => entry.version >= minVersionToKeep
1221
+ );
1222
+ if (retained.length === 0) {
1223
+ this._liveTextHistory.delete(nodeId);
1224
+ } else {
1225
+ this._liveTextHistory.set(nodeId, retained);
1226
+ }
1227
+ }
1073
1228
  get_meta(key) {
1074
1229
  return this._metadb.get(key);
1075
1230
  }
@@ -1345,6 +1500,7 @@ var InMemoryDriver = class {
1345
1500
  }
1346
1501
  _loadNodesApi() {
1347
1502
  const nodes = this._nodes;
1503
+ const liveTextHistory = this._liveTextHistory;
1348
1504
  if (!nodes.has("root")) {
1349
1505
  nodes.set("root", { type: _core.CrdtType.OBJECT, data: {} });
1350
1506
  }
@@ -1377,6 +1533,9 @@ var InMemoryDriver = class {
1377
1533
  if (node.type === _core.CrdtType.REGISTER && parentNode.type === _core.CrdtType.OBJECT) {
1378
1534
  throw new Error("Cannot add register under object");
1379
1535
  }
1536
+ if (parentNode.type === _core.CrdtType.FILE) {
1537
+ throw new Error("Cannot add child under file");
1538
+ }
1380
1539
  const conflictingSiblingId = revNodes.get(node.parentId, node.parentKey);
1381
1540
  if (conflictingSiblingId !== id) {
1382
1541
  const parentNode2 = nodes.get(node.parentId);
@@ -1432,6 +1591,7 @@ var InMemoryDriver = class {
1432
1591
  const currid = queue.pop();
1433
1592
  queue.push(...revNodes.valuesAt(currid));
1434
1593
  nodes.delete(currid);
1594
+ liveTextHistory.delete(currid);
1435
1595
  revNodes.deleteAll(currid);
1436
1596
  }
1437
1597
  }
@@ -1557,18 +1717,21 @@ function makeNewInMemoryDriver(options) {
1557
1717
 
1558
1718
 
1559
1719
 
1720
+
1721
+
1722
+ var LIVE_TEXT_HISTORY_LIMIT = 1e3;
1723
+ var LIVE_TEXT_HISTORY_TOO_OLD_REASON = "LiveText operation is older than retained history";
1560
1724
  function accept(op2, fix) {
1561
1725
  return { action: "accepted", op: op2, fix };
1562
1726
  }
1563
1727
  function ignore(ignoredOp) {
1564
1728
  return { action: "ignored", ignoredOpId: ignoredOp.opId };
1565
1729
  }
1566
- function rectify(op2, parentKey) {
1567
- return {
1568
- action: "rectified",
1569
- ackOp: { ...op2, parentKey },
1570
- fix: { type: _core.OpCode.SET_PARENT_KEY, id: op2.id, parentKey }
1571
- };
1730
+ function reject(op2, reason) {
1731
+ return { action: "rejected", opIds: [op2.opId], reason };
1732
+ }
1733
+ function rectify(ackOp, fix) {
1734
+ return { action: "rectified", ackOp, fix };
1572
1735
  }
1573
1736
  function nodeFromCreateChildOp(op2) {
1574
1737
  switch (op2.type) {
@@ -1598,6 +1761,21 @@ function nodeFromCreateChildOp(op2) {
1598
1761
  parentKey: op2.parentKey,
1599
1762
  data: op2.data
1600
1763
  };
1764
+ case _core.OpCode.CREATE_TEXT:
1765
+ return {
1766
+ type: _core.CrdtType.TEXT,
1767
+ parentId: op2.parentId,
1768
+ parentKey: op2.parentKey,
1769
+ data: op2.data,
1770
+ version: op2.version
1771
+ };
1772
+ case _core.OpCode.CREATE_FILE:
1773
+ return {
1774
+ type: _core.CrdtType.FILE,
1775
+ parentId: op2.parentId,
1776
+ parentKey: op2.parentKey,
1777
+ data: op2.data
1778
+ };
1601
1779
  // istanbul ignore next
1602
1780
  default:
1603
1781
  return _core.assertNever.call(void 0, op2, "Unknown op code");
@@ -1639,9 +1817,13 @@ var Storage = class {
1639
1817
  case _core.OpCode.CREATE_MAP:
1640
1818
  case _core.OpCode.CREATE_REGISTER:
1641
1819
  case _core.OpCode.CREATE_OBJECT:
1820
+ case _core.OpCode.CREATE_TEXT:
1821
+ case _core.OpCode.CREATE_FILE:
1642
1822
  return this.applyCreateOp(op2);
1643
1823
  case _core.OpCode.UPDATE_OBJECT:
1644
1824
  return this.applyUpdateObjectOp(op2);
1825
+ case _core.OpCode.UPDATE_TEXT:
1826
+ return this.applyUpdateTextOp(op2);
1645
1827
  case _core.OpCode.SET_PARENT_KEY:
1646
1828
  return this.applySetParentKeyOp(op2);
1647
1829
  case _core.OpCode.DELETE_OBJECT_KEY:
@@ -1662,7 +1844,14 @@ var Storage = class {
1662
1844
  if (op2.intent === "push") {
1663
1845
  const stored = this.driver.get_node(op2.id);
1664
1846
  if (_optionalChain([stored, 'optionalAccess', _47 => _47.parentId]) !== void 0 && _optionalChain([this, 'access', _48 => _48.driver, 'access', _49 => _49.get_node, 'call', _50 => _50(stored.parentId), 'optionalAccess', _51 => _51.type]) === _core.CrdtType.LIST) {
1665
- return rectify(op2, stored.parentKey);
1847
+ return rectify(
1848
+ { ...op2, parentKey: stored.parentKey },
1849
+ {
1850
+ type: _core.OpCode.SET_PARENT_KEY,
1851
+ id: op2.id,
1852
+ parentKey: stored.parentKey
1853
+ }
1854
+ );
1666
1855
  }
1667
1856
  }
1668
1857
  return ignore(op2);
@@ -1684,6 +1873,8 @@ var Storage = class {
1684
1873
  case _core.CrdtType.LIST:
1685
1874
  return this.createChildAsListItem(op2, node);
1686
1875
  case _core.CrdtType.REGISTER:
1876
+ case _core.CrdtType.TEXT:
1877
+ case _core.CrdtType.FILE:
1687
1878
  return ignore(op2);
1688
1879
  // istanbul ignore next
1689
1880
  default:
@@ -1740,6 +1931,59 @@ var Storage = class {
1740
1931
  this.driver.set_object_data(op2.id, op2.data, true);
1741
1932
  return accept(op2);
1742
1933
  }
1934
+ applyUpdateTextOp(op2) {
1935
+ const node = this.driver.get_node(op2.id);
1936
+ if (_optionalChain([node, 'optionalAccess', _56 => _56.type]) !== _core.CrdtType.TEXT) {
1937
+ return ignore(op2);
1938
+ }
1939
+ const duplicate = this.driver.get_live_text_history_by_op_id(
1940
+ op2.id,
1941
+ op2.opId
1942
+ );
1943
+ if (duplicate !== void 0) {
1944
+ return rectify({
1945
+ ...op2,
1946
+ baseVersion: duplicate.baseVersion,
1947
+ version: duplicate.version,
1948
+ ops: [...duplicate.ops]
1949
+ });
1950
+ }
1951
+ if (op2.ops.length === 0) {
1952
+ return ignore(op2);
1953
+ }
1954
+ if (op2.baseVersion > node.version) {
1955
+ return reject(op2, "LiveText operation base version is ahead of storage");
1956
+ }
1957
+ const history = op2.baseVersion < node.version ? this.driver.get_live_text_history_since(op2.id, op2.baseVersion) : [];
1958
+ if (op2.baseVersion < node.version && history.length !== node.version - op2.baseVersion) {
1959
+ return reject(op2, LIVE_TEXT_HISTORY_TOO_OLD_REASON);
1960
+ }
1961
+ const acceptedOps = history.flatMap((entry) => entry.ops);
1962
+ const ops = acceptedOps.length > 0 ? _core.transformTextOperations.call(void 0, op2.ops, acceptedOps, "after") : op2.ops;
1963
+ const version = node.version + 1;
1964
+ const data = _core.applyLiveTextOperations.call(void 0, node.data, ops);
1965
+ this.driver.set_child(
1966
+ op2.id,
1967
+ {
1968
+ ...node,
1969
+ data,
1970
+ version
1971
+ },
1972
+ true
1973
+ );
1974
+ this.driver.append_live_text_history({
1975
+ nodeId: op2.id,
1976
+ baseVersion: node.version,
1977
+ version,
1978
+ opId: op2.opId,
1979
+ ops: [...ops]
1980
+ });
1981
+ this.driver.purge_live_text_history_before(
1982
+ op2.id,
1983
+ Math.max(0, version - LIVE_TEXT_HISTORY_LIMIT + 1)
1984
+ );
1985
+ return accept({ ...op2, baseVersion: node.version, version, ops: [...ops] });
1986
+ }
1743
1987
  applyDeleteCrdtOp(op2) {
1744
1988
  this.driver.delete_node(op2.id);
1745
1989
  return accept(op2);
@@ -1811,10 +2055,10 @@ var Storage = class {
1811
2055
  */
1812
2056
  moveToPosInList(id, targetKey) {
1813
2057
  const node = this.driver.get_node(id);
1814
- if (_optionalChain([node, 'optionalAccess', _56 => _56.parentId]) === void 0) {
2058
+ if (_optionalChain([node, 'optionalAccess', _57 => _57.parentId]) === void 0) {
1815
2059
  return;
1816
2060
  }
1817
- if (_optionalChain([this, 'access', _57 => _57.driver, 'access', _58 => _58.get_node, 'call', _59 => _59(node.parentId), 'optionalAccess', _60 => _60.type]) !== _core.CrdtType.LIST) {
2061
+ if (_optionalChain([this, 'access', _58 => _58.driver, 'access', _59 => _59.get_node, 'call', _60 => _60(node.parentId), 'optionalAccess', _61 => _61.type]) !== _core.CrdtType.LIST) {
1818
2062
  return;
1819
2063
  }
1820
2064
  if (node.parentKey === targetKey) {
@@ -2225,13 +2469,13 @@ var BrowserSession = class {
2225
2469
  this.publicMeta = ticket.publicMeta;
2226
2470
  __privateSet(this, __socket, socket);
2227
2471
  __privateSet(this, __debug, debug);
2228
- const now = _nullishCoalesce(_optionalChain([createdAt, 'optionalAccess', _61 => _61.getTime, 'call', _62 => _62()]), () => ( Date.now()));
2472
+ const now = _nullishCoalesce(_optionalChain([createdAt, 'optionalAccess', _62 => _62.getTime, 'call', _63 => _63()]), () => ( Date.now()));
2229
2473
  this.createdAt = now;
2230
2474
  __privateSet(this, __lastActiveAt, now);
2231
2475
  __privateSet(this, __hasNotifiedClientStorageUpdateError, false);
2232
2476
  }
2233
2477
  get lastActiveAt() {
2234
- const lastPing = _optionalChain([__privateGet, 'call', _63 => _63(this, __socket), 'access', _64 => _64.getLastPongTimestamp, 'optionalCall', _65 => _65()]);
2478
+ const lastPing = _optionalChain([__privateGet, 'call', _64 => _64(this, __socket), 'access', _65 => _65.getLastPongTimestamp, 'optionalCall', _66 => _66()]);
2235
2479
  if (lastPing && lastPing.getTime() > __privateGet(this, __lastActiveAt)) {
2236
2480
  return lastPing.getTime();
2237
2481
  } else {
@@ -2332,25 +2576,25 @@ var Room = class {
2332
2576
  __publicField(this, "sessions", new UniqueMap((s) => s.actor));
2333
2577
  __publicField(this, "hooks");
2334
2578
  __privateAdd(this, __debug2);
2335
- const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _66 => _66.storage]), () => ( makeNewInMemoryDriver()));
2579
+ const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _67 => _67.storage]), () => ( makeNewInMemoryDriver()));
2336
2580
  this.meta = meta;
2337
2581
  this.driver = driver;
2338
2582
  this._storage = new Storage(this.driver);
2339
2583
  this._yjsStorage = new YjsStorage(this.driver);
2340
- __privateSet(this, _logger, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _67 => _67.logger]), () => ( BLACK_HOLE)));
2584
+ __privateSet(this, _logger, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _68 => _68.logger]), () => ( BLACK_HOLE)));
2341
2585
  this.hooks = {
2342
- isClientMsgAllowed: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _68 => _68.hooks, 'optionalAccess', _69 => _69.isClientMsgAllowed]), () => ( (() => {
2586
+ isClientMsgAllowed: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _69 => _69.hooks, 'optionalAccess', _70 => _70.isClientMsgAllowed]), () => ( (() => {
2343
2587
  return {
2344
2588
  allowed: true
2345
2589
  };
2346
2590
  }))),
2347
- onRoomWillUnload: _optionalChain([options, 'optionalAccess', _70 => _70.hooks, 'optionalAccess', _71 => _71.onRoomWillUnload]),
2348
- onSessionDidStart: _optionalChain([options, 'optionalAccess', _72 => _72.hooks, 'optionalAccess', _73 => _73.onSessionDidStart]),
2349
- onSessionDidEnd: _optionalChain([options, 'optionalAccess', _74 => _74.hooks, 'optionalAccess', _75 => _75.onSessionDidEnd]),
2350
- postClientMsgStorageDidUpdate: _optionalChain([options, 'optionalAccess', _76 => _76.hooks, 'optionalAccess', _77 => _77.postClientMsgStorageDidUpdate]),
2351
- postClientMsgYdocDidUpdate: _optionalChain([options, 'optionalAccess', _78 => _78.hooks, 'optionalAccess', _79 => _79.postClientMsgYdocDidUpdate])
2591
+ onRoomWillUnload: _optionalChain([options, 'optionalAccess', _71 => _71.hooks, 'optionalAccess', _72 => _72.onRoomWillUnload]),
2592
+ onSessionDidStart: _optionalChain([options, 'optionalAccess', _73 => _73.hooks, 'optionalAccess', _74 => _74.onSessionDidStart]),
2593
+ onSessionDidEnd: _optionalChain([options, 'optionalAccess', _75 => _75.hooks, 'optionalAccess', _76 => _76.onSessionDidEnd]),
2594
+ postClientMsgStorageDidUpdate: _optionalChain([options, 'optionalAccess', _77 => _77.hooks, 'optionalAccess', _78 => _78.postClientMsgStorageDidUpdate]),
2595
+ postClientMsgYdocDidUpdate: _optionalChain([options, 'optionalAccess', _79 => _79.hooks, 'optionalAccess', _80 => _80.postClientMsgYdocDidUpdate])
2352
2596
  };
2353
- __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _80 => _80.enableDebugLogging]), () => ( false)));
2597
+ __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _81 => _81.enableDebugLogging]), () => ( false)));
2354
2598
  }
2355
2599
  get storage() {
2356
2600
  return this._storage;
@@ -2396,7 +2640,7 @@ var Room = class {
2396
2640
  * is used, fresh instances will lazily be created.
2397
2641
  */
2398
2642
  unload(ctx) {
2399
- _optionalChain([this, 'access', _81 => _81.hooks, 'access', _82 => _82.onRoomWillUnload, 'optionalCall', _83 => _83(ctx)]);
2643
+ _optionalChain([this, 'access', _82 => _82.hooks, 'access', _83 => _83.onRoomWillUnload, 'optionalCall', _84 => _84(ctx)]);
2400
2644
  this.driver.reinitialize();
2401
2645
  this._storage = new Storage(this.driver);
2402
2646
  this._yjsStorage = new YjsStorage(this.driver);
@@ -2413,17 +2657,17 @@ var Room = class {
2413
2657
  * unused Ticket will simply get garbage collected.
2414
2658
  */
2415
2659
  createTicket(options) {
2416
- const actor = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _84 => _84.actor]), () => ( this.getNextActor()));
2660
+ const actor = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _85 => _85.actor]), () => ( this.getNextActor()));
2417
2661
  const sessionKey = _nanoid.nanoid.call(void 0, );
2418
- const info = _optionalChain([options, 'optionalAccess', _85 => _85.info]);
2662
+ const info = _optionalChain([options, 'optionalAccess', _86 => _86.info]);
2419
2663
  const ticket = {
2420
- version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _86 => _86.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
2664
+ version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _87 => _87.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
2421
2665
  actor,
2422
2666
  sessionKey,
2423
- meta: _optionalChain([options, 'optionalAccess', _87 => _87.meta]),
2424
- publicMeta: _optionalChain([options, 'optionalAccess', _88 => _88.publicMeta]),
2425
- user: _optionalChain([options, 'optionalAccess', _89 => _89.id]) ? { id: options.id, info } : { anonymousId: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _90 => _90.anonymousId]), () => ( _nanoid.nanoid.call(void 0, ))), info },
2426
- scopes: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _91 => _91.scopes]), () => ( ["room:write"]))
2667
+ meta: _optionalChain([options, 'optionalAccess', _88 => _88.meta]),
2668
+ publicMeta: _optionalChain([options, 'optionalAccess', _89 => _89.publicMeta]),
2669
+ user: _optionalChain([options, 'optionalAccess', _90 => _90.id]) ? { id: options.id, info } : { anonymousId: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _91 => _91.anonymousId]), () => ( _nanoid.nanoid.call(void 0, ))), info },
2670
+ scopes: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _92 => _92.scopes]), () => ( ["room:write"]))
2427
2671
  };
2428
2672
  if (__privateGet(this, __debug2)) {
2429
2673
  console.log(`new ticket created: ${JSON.stringify(ticket)}`);
@@ -2554,7 +2798,7 @@ var Room = class {
2554
2798
  ctx,
2555
2799
  defer
2556
2800
  );
2557
- const p$ = _optionalChain([this, 'access', _92 => _92.hooks, 'access', _93 => _93.onSessionDidStart, 'optionalCall', _94 => _94(newSession, ctx)]);
2801
+ const p$ = _optionalChain([this, 'access', _93 => _93.hooks, 'access', _94 => _94.onSessionDidStart, 'optionalCall', _95 => _95(newSession, ctx)]);
2558
2802
  if (p$) defer(p$);
2559
2803
  }
2560
2804
  /**
@@ -2578,7 +2822,7 @@ var Room = class {
2578
2822
  for (const other of this.otherSessions(key)) {
2579
2823
  other.send({ type: ServerMsgCode2.USER_LEFT, actor: session.actor });
2580
2824
  }
2581
- const p$ = _optionalChain([this, 'access', _95 => _95.hooks, 'access', _96 => _96.onSessionDidEnd, 'optionalCall', _97 => _97(session, ctx)]);
2825
+ const p$ = _optionalChain([this, 'access', _96 => _96.hooks, 'access', _97 => _97.onSessionDidEnd, 'optionalCall', _98 => _98(session, ctx)]);
2582
2826
  if (p$) defer(p$);
2583
2827
  }
2584
2828
  }
@@ -2609,7 +2853,7 @@ var Room = class {
2609
2853
  );
2610
2854
  }) {
2611
2855
  const text = typeof data === "string" ? data : _core.raise.call(void 0, "Unsupported message format");
2612
- _optionalChain([this, 'access', _98 => _98.sessions, 'access', _99 => _99.get, 'call', _100 => _100(key), 'optionalAccess', _101 => _101.markActive, 'call', _102 => _102()]);
2856
+ _optionalChain([this, 'access', _99 => _99.sessions, 'access', _100 => _100.get, 'call', _101 => _101(key), 'optionalAccess', _102 => _102.markActive, 'call', _103 => _103()]);
2613
2857
  if (text === "ping") {
2614
2858
  await this.handlePing(key, ctx);
2615
2859
  } else {
@@ -2986,7 +3230,7 @@ var Room = class {
2986
3230
  }
2987
3231
  const sent = session.sendPong();
2988
3232
  if (sent !== 0) {
2989
- await _optionalChain([this, 'access', _103 => _103.hooks, 'access', _104 => _104.onDidPong, 'optionalCall', _105 => _105(ctx)]);
3233
+ await _optionalChain([this, 'access', _104 => _104.hooks, 'access', _105 => _105.onDidPong, 'optionalCall', _106 => _106(ctx)]);
2990
3234
  }
2991
3235
  }
2992
3236
  _processClientMsg_withExclusiveAccess(sessionKey, messages, ctx, defer) {
@@ -3117,7 +3361,7 @@ var Room = class {
3117
3361
  break;
3118
3362
  }
3119
3363
  case _core.ClientMsgCode.UPDATE_STORAGE: {
3120
- _optionalChain([this, 'access', _106 => _106.driver, 'access', _107 => _107.bump_storage_version, 'optionalCall', _108 => _108()]);
3364
+ _optionalChain([this, 'access', _107 => _107.driver, 'access', _108 => _108.bump_storage_version, 'optionalCall', _109 => _109()]);
3121
3365
  const result = this.storage.applyOps(msg.ops);
3122
3366
  const opsToForward = result.flatMap(
3123
3367
  (r) => r.action === "accepted" ? [r.op] : []
@@ -3128,9 +3372,11 @@ var Room = class {
3128
3372
  case "ignored":
3129
3373
  return r.ignoredOpId !== void 0 ? [ackIgnoredOp(r.ignoredOpId)] : [];
3130
3374
  case "rectified":
3131
- return [r.ackOp, r.fix];
3375
+ return r.fix !== void 0 ? [r.ackOp, r.fix] : [r.ackOp];
3132
3376
  case "accepted":
3133
3377
  return r.fix !== void 0 ? [r.fix] : [];
3378
+ case "rejected":
3379
+ return [];
3134
3380
  // istanbul ignore next
3135
3381
  default:
3136
3382
  return _core.assertNever.call(void 0, r, "Unhandled case");
@@ -3153,8 +3399,15 @@ var Room = class {
3153
3399
  ops: opsToSendBack
3154
3400
  });
3155
3401
  }
3402
+ for (const rejected of result.filter((r) => r.action === "rejected")) {
3403
+ replyImmediately({
3404
+ type: ServerMsgCode2.REJECT_STORAGE_OP,
3405
+ opIds: rejected.opIds,
3406
+ reason: rejected.reason
3407
+ });
3408
+ }
3156
3409
  if (opsToForward.length > 0) {
3157
- const p$ = _optionalChain([this, 'access', _109 => _109.hooks, 'access', _110 => _110.postClientMsgStorageDidUpdate, 'optionalCall', _111 => _111(ctx, session)]);
3410
+ const p$ = _optionalChain([this, 'access', _110 => _110.hooks, 'access', _111 => _111.postClientMsgStorageDidUpdate, 'optionalCall', _112 => _112(ctx, session)]);
3158
3411
  if (p$) defer(p$);
3159
3412
  }
3160
3413
  break;
@@ -3211,7 +3464,7 @@ var Room = class {
3211
3464
  defer
3212
3465
  );
3213
3466
  if (result.isUpdated) {
3214
- const p$ = _optionalChain([this, 'access', _112 => _112.hooks, 'access', _113 => _113.postClientMsgYdocDidUpdate, 'optionalCall', _114 => _114(ctx, session)]);
3467
+ const p$ = _optionalChain([this, 'access', _113 => _113.hooks, 'access', _114 => _114.postClientMsgYdocDidUpdate, 'optionalCall', _115 => _115(ctx, session)]);
3215
3468
  if (p$) defer(p$);
3216
3469
  }
3217
3470
  break;