@liveblocks/server 1.7.0 → 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
@@ -168,12 +168,18 @@ var jsonObjectYolo = jsonYolo.refine(
168
168
 
169
169
 
170
170
 
171
+
172
+
173
+
171
174
  var intent = _decoders.oneOf.call(void 0, ["set", "push"]);
172
175
  var storageFileId = _decoders.sized.call(void 0, _decoders.startsWith.call(void 0, "fl_"), { size: 24 });
173
176
  var fileSize = _decoders.number.refine(
174
177
  (value) => Number.isSafeInteger(value) && value >= 0,
175
178
  "Must be a valid file size"
176
179
  );
180
+ var liveTextVersion = _decoders.number.reject(
181
+ (value) => Number.isSafeInteger(value) && value >= 0 ? null : "Must be a non-negative safe integer"
182
+ );
177
183
  var updateObjectOp = _decoders.object.call(void 0, {
178
184
  type: _decoders.constant.call(void 0, _core.OpCode.UPDATE_OBJECT),
179
185
  opId: _decoders.string,
@@ -218,6 +224,41 @@ var createRegisterOp = _decoders.object.call(void 0, {
218
224
  intent: _decoders.optional.call(void 0, intent),
219
225
  deletedId: _decoders.optional.call(void 0, _decoders.string)
220
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
+ });
221
262
  var createFileOp = _decoders.object.call(void 0, {
222
263
  type: _decoders.constant.call(void 0, _core.OpCode.CREATE_FILE),
223
264
  opId: _decoders.string,
@@ -233,6 +274,14 @@ var createFileOp = _decoders.object.call(void 0, {
233
274
  intent: _decoders.optional.call(void 0, intent),
234
275
  deletedId: _decoders.optional.call(void 0, _decoders.string)
235
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
+ });
236
285
  var deleteCrdtOp = _decoders.object.call(void 0, {
237
286
  type: _decoders.constant.call(void 0, _core.OpCode.DELETE_CRDT),
238
287
  opId: _decoders.string,
@@ -256,6 +305,8 @@ var op = _decoders.taggedUnion.call(void 0, "type", {
256
305
  [_core.OpCode.CREATE_LIST]: createListOp,
257
306
  [_core.OpCode.CREATE_MAP]: createMapOp,
258
307
  [_core.OpCode.CREATE_REGISTER]: createRegisterOp,
308
+ [_core.OpCode.CREATE_TEXT]: createTextOp,
309
+ [_core.OpCode.UPDATE_TEXT]: updateTextOp,
259
310
  [_core.OpCode.CREATE_FILE]: createFileOp,
260
311
  [_core.OpCode.DELETE_CRDT]: deleteCrdtOp,
261
312
  [_core.OpCode.SET_PARENT_KEY]: setParentKeyOp,
@@ -396,6 +447,8 @@ function buildNode(snapshot2, id) {
396
447
  return buildList(snapshot2, id);
397
448
  } else if (node.type === _core.CrdtType.MAP) {
398
449
  return buildMap(snapshot2, id);
450
+ } else if (node.type === _core.CrdtType.TEXT) {
451
+ return node.data;
399
452
  } else if (node.type === _core.CrdtType.FILE) {
400
453
  return node.data;
401
454
  } else {
@@ -441,6 +494,8 @@ function* emit(snapshot2, id) {
441
494
  yield* emitMap(snapshot2, id);
442
495
  } else if (node.type === _core.CrdtType.REGISTER) {
443
496
  yield JSON.stringify(node.data);
497
+ } else if (node.type === _core.CrdtType.TEXT) {
498
+ yield JSON.stringify(node.data);
444
499
  } else if (node.type === _core.CrdtType.FILE) {
445
500
  yield JSON.stringify(node.data);
446
501
  }
@@ -514,6 +569,18 @@ function* iterJson(key, data, parent, state) {
514
569
  case "LiveMap":
515
570
  yield* iterMap(key, data.data, parent, state);
516
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;
517
584
  case "LiveFile":
518
585
  yield [
519
586
  generateId(state),
@@ -609,6 +676,11 @@ function buildNode2(snapshot2, id) {
609
676
  return buildList2(snapshot2, id);
610
677
  } else if (node.type === _core.CrdtType.MAP) {
611
678
  return buildMap2(snapshot2, id);
679
+ } else if (node.type === _core.CrdtType.TEXT) {
680
+ return {
681
+ liveblocksType: "LiveText",
682
+ data: node.data
683
+ };
612
684
  } else if (node.type === _core.CrdtType.FILE) {
613
685
  return { liveblocksType: "LiveFile", data: node.data };
614
686
  } else {
@@ -657,6 +729,11 @@ function* emit2(snapshot2, id) {
657
729
  yield* emitMap2(snapshot2, id);
658
730
  } else if (node.type === _core.CrdtType.REGISTER) {
659
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
+ });
660
737
  } else if (node.type === _core.CrdtType.FILE) {
661
738
  yield '{"liveblocksType":"LiveFile","data":';
662
739
  yield JSON.stringify(node.data);
@@ -1057,7 +1134,7 @@ function buildReverseLookup(nodes) {
1057
1134
  delete node.data[key];
1058
1135
  }
1059
1136
  }
1060
- const isLeafNode = node.type === _core.CrdtType.REGISTER || node.type === _core.CrdtType.FILE;
1137
+ const isLeafNode = node.type === _core.CrdtType.REGISTER || node.type === _core.CrdtType.FILE || node.type === _core.CrdtType.TEXT;
1061
1138
  if (!isLeafNode) {
1062
1139
  queue.push(...revNodes.valuesAt(nodeId));
1063
1140
  } else if (node.type === _core.CrdtType.REGISTER) {
@@ -1081,7 +1158,6 @@ function hasStaticDataAt(node, key) {
1081
1158
  return node.type === _core.CrdtType.OBJECT && Object.prototype.hasOwnProperty.call(node.data, key) && node.data[key] !== void 0;
1082
1159
  }
1083
1160
  var InMemoryDriver = class {
1084
- // Key: `${feedId}:${messageId}`
1085
1161
  constructor(options) {
1086
1162
  __publicField(this, "_nextActor");
1087
1163
  __publicField(this, "_nodes");
@@ -1091,12 +1167,15 @@ var InMemoryDriver = class {
1091
1167
  __publicField(this, "_leasedSessions");
1092
1168
  __publicField(this, "_feeds");
1093
1169
  __publicField(this, "_feedMessages");
1170
+ // Key: `${feedId}:${messageId}`
1171
+ __publicField(this, "_liveTextHistory");
1094
1172
  this._nodes = /* @__PURE__ */ new Map();
1095
1173
  this._metadb = /* @__PURE__ */ new Map();
1096
1174
  this._ydb = /* @__PURE__ */ new Map();
1097
1175
  this._leasedSessions = /* @__PURE__ */ new Map();
1098
1176
  this._feeds = /* @__PURE__ */ new Map();
1099
1177
  this._feedMessages = /* @__PURE__ */ new Map();
1178
+ this._liveTextHistory = /* @__PURE__ */ new Map();
1100
1179
  this._nextActor = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _35 => _35.initialActor]), () => ( -1));
1101
1180
  for (const [key, value] of _nullishCoalesce(_optionalChain([options, 'optionalAccess', _36 => _36.initialNodes]), () => ( []))) {
1102
1181
  this._nodes.set(key, value);
@@ -1112,10 +1191,40 @@ var InMemoryDriver = class {
1112
1191
  DANGEROUSLY_reset_nodes(doc) {
1113
1192
  this.reinitialize();
1114
1193
  this._nodes.clear();
1194
+ this._liveTextHistory.clear();
1115
1195
  for (const [id, node] of plainLsonToNodeStream(doc)) {
1116
1196
  this._nodes.set(id, node);
1117
1197
  }
1118
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
+ }
1119
1228
  get_meta(key) {
1120
1229
  return this._metadb.get(key);
1121
1230
  }
@@ -1391,6 +1500,7 @@ var InMemoryDriver = class {
1391
1500
  }
1392
1501
  _loadNodesApi() {
1393
1502
  const nodes = this._nodes;
1503
+ const liveTextHistory = this._liveTextHistory;
1394
1504
  if (!nodes.has("root")) {
1395
1505
  nodes.set("root", { type: _core.CrdtType.OBJECT, data: {} });
1396
1506
  }
@@ -1481,6 +1591,7 @@ var InMemoryDriver = class {
1481
1591
  const currid = queue.pop();
1482
1592
  queue.push(...revNodes.valuesAt(currid));
1483
1593
  nodes.delete(currid);
1594
+ liveTextHistory.delete(currid);
1484
1595
  revNodes.deleteAll(currid);
1485
1596
  }
1486
1597
  }
@@ -1606,18 +1717,21 @@ function makeNewInMemoryDriver(options) {
1606
1717
 
1607
1718
 
1608
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";
1609
1724
  function accept(op2, fix) {
1610
1725
  return { action: "accepted", op: op2, fix };
1611
1726
  }
1612
1727
  function ignore(ignoredOp) {
1613
1728
  return { action: "ignored", ignoredOpId: ignoredOp.opId };
1614
1729
  }
1615
- function rectify(op2, parentKey) {
1616
- return {
1617
- action: "rectified",
1618
- ackOp: { ...op2, parentKey },
1619
- fix: { type: _core.OpCode.SET_PARENT_KEY, id: op2.id, parentKey }
1620
- };
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 };
1621
1735
  }
1622
1736
  function nodeFromCreateChildOp(op2) {
1623
1737
  switch (op2.type) {
@@ -1647,6 +1761,14 @@ function nodeFromCreateChildOp(op2) {
1647
1761
  parentKey: op2.parentKey,
1648
1762
  data: op2.data
1649
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
+ };
1650
1772
  case _core.OpCode.CREATE_FILE:
1651
1773
  return {
1652
1774
  type: _core.CrdtType.FILE,
@@ -1695,10 +1817,13 @@ var Storage = class {
1695
1817
  case _core.OpCode.CREATE_MAP:
1696
1818
  case _core.OpCode.CREATE_REGISTER:
1697
1819
  case _core.OpCode.CREATE_OBJECT:
1820
+ case _core.OpCode.CREATE_TEXT:
1698
1821
  case _core.OpCode.CREATE_FILE:
1699
1822
  return this.applyCreateOp(op2);
1700
1823
  case _core.OpCode.UPDATE_OBJECT:
1701
1824
  return this.applyUpdateObjectOp(op2);
1825
+ case _core.OpCode.UPDATE_TEXT:
1826
+ return this.applyUpdateTextOp(op2);
1702
1827
  case _core.OpCode.SET_PARENT_KEY:
1703
1828
  return this.applySetParentKeyOp(op2);
1704
1829
  case _core.OpCode.DELETE_OBJECT_KEY:
@@ -1719,7 +1844,14 @@ var Storage = class {
1719
1844
  if (op2.intent === "push") {
1720
1845
  const stored = this.driver.get_node(op2.id);
1721
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) {
1722
- 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
+ );
1723
1855
  }
1724
1856
  }
1725
1857
  return ignore(op2);
@@ -1741,6 +1873,7 @@ var Storage = class {
1741
1873
  case _core.CrdtType.LIST:
1742
1874
  return this.createChildAsListItem(op2, node);
1743
1875
  case _core.CrdtType.REGISTER:
1876
+ case _core.CrdtType.TEXT:
1744
1877
  case _core.CrdtType.FILE:
1745
1878
  return ignore(op2);
1746
1879
  // istanbul ignore next
@@ -1798,6 +1931,59 @@ var Storage = class {
1798
1931
  this.driver.set_object_data(op2.id, op2.data, true);
1799
1932
  return accept(op2);
1800
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
+ }
1801
1987
  applyDeleteCrdtOp(op2) {
1802
1988
  this.driver.delete_node(op2.id);
1803
1989
  return accept(op2);
@@ -1869,10 +2055,10 @@ var Storage = class {
1869
2055
  */
1870
2056
  moveToPosInList(id, targetKey) {
1871
2057
  const node = this.driver.get_node(id);
1872
- if (_optionalChain([node, 'optionalAccess', _56 => _56.parentId]) === void 0) {
2058
+ if (_optionalChain([node, 'optionalAccess', _57 => _57.parentId]) === void 0) {
1873
2059
  return;
1874
2060
  }
1875
- 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) {
1876
2062
  return;
1877
2063
  }
1878
2064
  if (node.parentKey === targetKey) {
@@ -2283,13 +2469,13 @@ var BrowserSession = class {
2283
2469
  this.publicMeta = ticket.publicMeta;
2284
2470
  __privateSet(this, __socket, socket);
2285
2471
  __privateSet(this, __debug, debug);
2286
- 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()));
2287
2473
  this.createdAt = now;
2288
2474
  __privateSet(this, __lastActiveAt, now);
2289
2475
  __privateSet(this, __hasNotifiedClientStorageUpdateError, false);
2290
2476
  }
2291
2477
  get lastActiveAt() {
2292
- 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()]);
2293
2479
  if (lastPing && lastPing.getTime() > __privateGet(this, __lastActiveAt)) {
2294
2480
  return lastPing.getTime();
2295
2481
  } else {
@@ -2390,25 +2576,25 @@ var Room = class {
2390
2576
  __publicField(this, "sessions", new UniqueMap((s) => s.actor));
2391
2577
  __publicField(this, "hooks");
2392
2578
  __privateAdd(this, __debug2);
2393
- const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _66 => _66.storage]), () => ( makeNewInMemoryDriver()));
2579
+ const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _67 => _67.storage]), () => ( makeNewInMemoryDriver()));
2394
2580
  this.meta = meta;
2395
2581
  this.driver = driver;
2396
2582
  this._storage = new Storage(this.driver);
2397
2583
  this._yjsStorage = new YjsStorage(this.driver);
2398
- __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)));
2399
2585
  this.hooks = {
2400
- 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]), () => ( (() => {
2401
2587
  return {
2402
2588
  allowed: true
2403
2589
  };
2404
2590
  }))),
2405
- onRoomWillUnload: _optionalChain([options, 'optionalAccess', _70 => _70.hooks, 'optionalAccess', _71 => _71.onRoomWillUnload]),
2406
- onSessionDidStart: _optionalChain([options, 'optionalAccess', _72 => _72.hooks, 'optionalAccess', _73 => _73.onSessionDidStart]),
2407
- onSessionDidEnd: _optionalChain([options, 'optionalAccess', _74 => _74.hooks, 'optionalAccess', _75 => _75.onSessionDidEnd]),
2408
- postClientMsgStorageDidUpdate: _optionalChain([options, 'optionalAccess', _76 => _76.hooks, 'optionalAccess', _77 => _77.postClientMsgStorageDidUpdate]),
2409
- 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])
2410
2596
  };
2411
- __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _80 => _80.enableDebugLogging]), () => ( false)));
2597
+ __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _81 => _81.enableDebugLogging]), () => ( false)));
2412
2598
  }
2413
2599
  get storage() {
2414
2600
  return this._storage;
@@ -2454,7 +2640,7 @@ var Room = class {
2454
2640
  * is used, fresh instances will lazily be created.
2455
2641
  */
2456
2642
  unload(ctx) {
2457
- _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)]);
2458
2644
  this.driver.reinitialize();
2459
2645
  this._storage = new Storage(this.driver);
2460
2646
  this._yjsStorage = new YjsStorage(this.driver);
@@ -2471,17 +2657,17 @@ var Room = class {
2471
2657
  * unused Ticket will simply get garbage collected.
2472
2658
  */
2473
2659
  createTicket(options) {
2474
- const actor = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _84 => _84.actor]), () => ( this.getNextActor()));
2660
+ const actor = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _85 => _85.actor]), () => ( this.getNextActor()));
2475
2661
  const sessionKey = _nanoid.nanoid.call(void 0, );
2476
- const info = _optionalChain([options, 'optionalAccess', _85 => _85.info]);
2662
+ const info = _optionalChain([options, 'optionalAccess', _86 => _86.info]);
2477
2663
  const ticket = {
2478
- version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _86 => _86.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
2664
+ version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _87 => _87.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
2479
2665
  actor,
2480
2666
  sessionKey,
2481
- meta: _optionalChain([options, 'optionalAccess', _87 => _87.meta]),
2482
- publicMeta: _optionalChain([options, 'optionalAccess', _88 => _88.publicMeta]),
2483
- 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 },
2484
- 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"]))
2485
2671
  };
2486
2672
  if (__privateGet(this, __debug2)) {
2487
2673
  console.log(`new ticket created: ${JSON.stringify(ticket)}`);
@@ -2612,7 +2798,7 @@ var Room = class {
2612
2798
  ctx,
2613
2799
  defer
2614
2800
  );
2615
- 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)]);
2616
2802
  if (p$) defer(p$);
2617
2803
  }
2618
2804
  /**
@@ -2636,7 +2822,7 @@ var Room = class {
2636
2822
  for (const other of this.otherSessions(key)) {
2637
2823
  other.send({ type: ServerMsgCode2.USER_LEFT, actor: session.actor });
2638
2824
  }
2639
- 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)]);
2640
2826
  if (p$) defer(p$);
2641
2827
  }
2642
2828
  }
@@ -2667,7 +2853,7 @@ var Room = class {
2667
2853
  );
2668
2854
  }) {
2669
2855
  const text = typeof data === "string" ? data : _core.raise.call(void 0, "Unsupported message format");
2670
- _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()]);
2671
2857
  if (text === "ping") {
2672
2858
  await this.handlePing(key, ctx);
2673
2859
  } else {
@@ -3044,7 +3230,7 @@ var Room = class {
3044
3230
  }
3045
3231
  const sent = session.sendPong();
3046
3232
  if (sent !== 0) {
3047
- 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)]);
3048
3234
  }
3049
3235
  }
3050
3236
  _processClientMsg_withExclusiveAccess(sessionKey, messages, ctx, defer) {
@@ -3175,7 +3361,7 @@ var Room = class {
3175
3361
  break;
3176
3362
  }
3177
3363
  case _core.ClientMsgCode.UPDATE_STORAGE: {
3178
- _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()]);
3179
3365
  const result = this.storage.applyOps(msg.ops);
3180
3366
  const opsToForward = result.flatMap(
3181
3367
  (r) => r.action === "accepted" ? [r.op] : []
@@ -3186,9 +3372,11 @@ var Room = class {
3186
3372
  case "ignored":
3187
3373
  return r.ignoredOpId !== void 0 ? [ackIgnoredOp(r.ignoredOpId)] : [];
3188
3374
  case "rectified":
3189
- return [r.ackOp, r.fix];
3375
+ return r.fix !== void 0 ? [r.ackOp, r.fix] : [r.ackOp];
3190
3376
  case "accepted":
3191
3377
  return r.fix !== void 0 ? [r.fix] : [];
3378
+ case "rejected":
3379
+ return [];
3192
3380
  // istanbul ignore next
3193
3381
  default:
3194
3382
  return _core.assertNever.call(void 0, r, "Unhandled case");
@@ -3211,8 +3399,15 @@ var Room = class {
3211
3399
  ops: opsToSendBack
3212
3400
  });
3213
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
+ }
3214
3409
  if (opsToForward.length > 0) {
3215
- 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)]);
3216
3411
  if (p$) defer(p$);
3217
3412
  }
3218
3413
  break;
@@ -3269,7 +3464,7 @@ var Room = class {
3269
3464
  defer
3270
3465
  );
3271
3466
  if (result.isUpdated) {
3272
- 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)]);
3273
3468
  if (p$) defer(p$);
3274
3469
  }
3275
3470
  break;