@liveblocks/core 3.22.0-rc1 → 3.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -6,7 +6,7 @@ var __export = (target, all) => {
6
6
 
7
7
  // src/version.ts
8
8
  var PKG_NAME = "@liveblocks/core";
9
- var PKG_VERSION = "3.22.0-rc1";
9
+ var PKG_VERSION = "3.22.0";
10
10
  var PKG_FORMAT = "cjs";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -1930,7 +1930,7 @@ function createApiClient({
1930
1930
  if (attachment.size <= ATTACHMENT_PART_SIZE) {
1931
1931
  return autoRetry(
1932
1932
  async () => httpClient.putBlob(
1933
- url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/upload/${encodeURIComponent(attachment.name)}`,
1933
+ url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/upload/${attachment.name}`,
1934
1934
  await authManager.getAuthValue({
1935
1935
  roomId,
1936
1936
  resource: "comments",
@@ -1949,7 +1949,7 @@ function createApiClient({
1949
1949
  const uploadedParts = [];
1950
1950
  const createMultiPartUpload = await autoRetry(
1951
1951
  async () => httpClient.post(
1952
- url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${encodeURIComponent(attachment.name)}`,
1952
+ url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${attachment.name}`,
1953
1953
  await authManager.getAuthValue({
1954
1954
  roomId,
1955
1955
  resource: "comments",
@@ -2132,7 +2132,17 @@ function createApiClient({
2132
2132
  })
2133
2133
  );
2134
2134
  }
2135
- async function getYjsHistoryVersion(options) {
2135
+ async function fetchStorageHistoryVersion(options) {
2136
+ return httpClient.rawGet(
2137
+ url`/v2/c/rooms/${options.roomId}/versions/${options.versionId}/storage`,
2138
+ await authManager.getAuthValue({
2139
+ roomId: options.roomId,
2140
+ resource: "storage",
2141
+ access: "read"
2142
+ })
2143
+ );
2144
+ }
2145
+ async function fetchYjsHistoryVersion(options) {
2136
2146
  return httpClient.rawGet(
2137
2147
  url`/v2/c/rooms/${options.roomId}/versions/${options.versionId}/yjs`,
2138
2148
  await authManager.getAuthValue({
@@ -2152,6 +2162,16 @@ function createApiClient({
2152
2162
  })
2153
2163
  );
2154
2164
  }
2165
+ async function deleteHistoryVersion(options) {
2166
+ await httpClient.delete(
2167
+ url`/v2/c/rooms/${options.roomId}/versions/${options.versionId}`,
2168
+ await authManager.getAuthValue({
2169
+ roomId: options.roomId,
2170
+ resource: "storage",
2171
+ access: "write"
2172
+ })
2173
+ );
2174
+ }
2155
2175
  async function reportTextEditor(options) {
2156
2176
  await httpClient.rawPost(
2157
2177
  url`/v2/c/rooms/${options.roomId}/text-metadata`,
@@ -2475,8 +2495,10 @@ function createApiClient({
2475
2495
  // Room text editor
2476
2496
  createTextMention,
2477
2497
  deleteTextMention,
2478
- getYjsHistoryVersion,
2498
+ fetchStorageHistoryVersion,
2499
+ fetchYjsHistoryVersion,
2479
2500
  createVersionHistorySnapshot,
2501
+ deleteHistoryVersion,
2480
2502
  reportTextEditor,
2481
2503
  listHistoryVersions,
2482
2504
  listHistoryVersionsSince,
@@ -6180,7 +6202,7 @@ ${parentKey}`;
6180
6202
  };
6181
6203
 
6182
6204
  // src/crdts/AbstractCrdt.ts
6183
- function createManagedPool(roomId, options) {
6205
+ function createManagedPool(options) {
6184
6206
  const {
6185
6207
  getCurrentConnectionId,
6186
6208
  onDispatch,
@@ -6191,7 +6213,6 @@ function createManagedPool(roomId, options) {
6191
6213
  let opClock = 0;
6192
6214
  const nodes = /* @__PURE__ */ new Map();
6193
6215
  return {
6194
- roomId,
6195
6216
  nodes,
6196
6217
  getNode: (id) => nodes.get(id),
6197
6218
  addNode: (id, node) => void nodes.set(id, node),
@@ -6256,9 +6277,6 @@ var AbstractCrdt = class {
6256
6277
  get _pool() {
6257
6278
  return this.#pool;
6258
6279
  }
6259
- get roomId() {
6260
- return this.#pool ? this.#pool.roomId : null;
6261
- }
6262
6280
  /** @internal */
6263
6281
  get _id() {
6264
6282
  return this.#id;
@@ -8785,6 +8803,16 @@ function isSameNodeOrChildOf(node, parent) {
8785
8803
  }
8786
8804
  return false;
8787
8805
  }
8806
+ function liveObjectFromNodeStream(nodes) {
8807
+ const pool = createManagedPool({
8808
+ getCurrentConnectionId: () => {
8809
+ throw new Error(
8810
+ "Cannot mutate a historic storage version: it is a read-only snapshot"
8811
+ );
8812
+ }
8813
+ });
8814
+ return LiveObject._fromItems(nodes, pool);
8815
+ }
8788
8816
  function deserialize(node, parentToChildren, pool) {
8789
8817
  if (isObjectStorageNode(node)) {
8790
8818
  return LiveObject._deserialize(node, parentToChildren, pool);
@@ -8909,6 +8937,61 @@ function diffNodeMap(prev, next) {
8909
8937
  ops.push({ type: OpCode.DELETE_CRDT, id });
8910
8938
  }
8911
8939
  });
8940
+ const emitted = /* @__PURE__ */ new Set();
8941
+ function emitCreate(id, crdt) {
8942
+ if (emitted.has(id)) {
8943
+ return;
8944
+ }
8945
+ emitted.add(id);
8946
+ const parentId = crdt.parentId;
8947
+ if (parentId !== void 0 && !prev.has(parentId)) {
8948
+ const parentCrdt = next.get(parentId);
8949
+ if (parentCrdt !== void 0) {
8950
+ emitCreate(parentId, parentCrdt);
8951
+ }
8952
+ }
8953
+ switch (crdt.type) {
8954
+ case CrdtType.REGISTER:
8955
+ ops.push({
8956
+ type: OpCode.CREATE_REGISTER,
8957
+ id,
8958
+ parentId: crdt.parentId,
8959
+ parentKey: crdt.parentKey,
8960
+ data: crdt.data
8961
+ });
8962
+ break;
8963
+ case CrdtType.LIST:
8964
+ ops.push({
8965
+ type: OpCode.CREATE_LIST,
8966
+ id,
8967
+ parentId: crdt.parentId,
8968
+ parentKey: crdt.parentKey
8969
+ });
8970
+ break;
8971
+ case CrdtType.OBJECT:
8972
+ if (crdt.parentId === void 0 || crdt.parentKey === void 0) {
8973
+ throw new Error(
8974
+ "Internal error. Cannot serialize storage root into an operation"
8975
+ );
8976
+ }
8977
+ ops.push({
8978
+ type: OpCode.CREATE_OBJECT,
8979
+ id,
8980
+ parentId: crdt.parentId,
8981
+ parentKey: crdt.parentKey,
8982
+ data: crdt.data
8983
+ });
8984
+ break;
8985
+ case CrdtType.MAP:
8986
+ ops.push({
8987
+ type: OpCode.CREATE_MAP,
8988
+ id,
8989
+ parentId: crdt.parentId,
8990
+ parentKey: crdt.parentKey
8991
+ });
8992
+ break;
8993
+ }
8994
+ }
8912
8995
  next.forEach((crdt, id) => {
8913
8996
  const currentCrdt = prev.get(id);
8914
8997
  if (currentCrdt) {
@@ -8945,47 +9028,7 @@ function diffNodeMap(prev, next) {
8945
9028
  });
8946
9029
  }
8947
9030
  } else {
8948
- switch (crdt.type) {
8949
- case CrdtType.REGISTER:
8950
- ops.push({
8951
- type: OpCode.CREATE_REGISTER,
8952
- id,
8953
- parentId: crdt.parentId,
8954
- parentKey: crdt.parentKey,
8955
- data: crdt.data
8956
- });
8957
- break;
8958
- case CrdtType.LIST:
8959
- ops.push({
8960
- type: OpCode.CREATE_LIST,
8961
- id,
8962
- parentId: crdt.parentId,
8963
- parentKey: crdt.parentKey
8964
- });
8965
- break;
8966
- case CrdtType.OBJECT:
8967
- if (crdt.parentId === void 0 || crdt.parentKey === void 0) {
8968
- throw new Error(
8969
- "Internal error. Cannot serialize storage root into an operation"
8970
- );
8971
- }
8972
- ops.push({
8973
- type: OpCode.CREATE_OBJECT,
8974
- id,
8975
- parentId: crdt.parentId,
8976
- parentKey: crdt.parentKey,
8977
- data: crdt.data
8978
- });
8979
- break;
8980
- case CrdtType.MAP:
8981
- ops.push({
8982
- type: OpCode.CREATE_MAP,
8983
- id,
8984
- parentId: crdt.parentId,
8985
- parentKey: crdt.parentKey
8986
- });
8987
- break;
8988
- }
9031
+ emitCreate(id, crdt);
8989
9032
  }
8990
9033
  });
8991
9034
  return ops;
@@ -9973,7 +10016,7 @@ function createRoom(options, config) {
9973
10016
  yjsProvider: void 0,
9974
10017
  yjsProviderDidChange: makeEventSource(),
9975
10018
  // Storage
9976
- pool: createManagedPool(roomId, {
10019
+ pool: createManagedPool({
9977
10020
  getCurrentConnectionId,
9978
10021
  onDispatch,
9979
10022
  isStorageWritable,
@@ -10136,12 +10179,18 @@ function createRoom(options, config) {
10136
10179
  signal: options2.signal
10137
10180
  });
10138
10181
  }
10139
- async function getYjsHistoryVersion(versionId) {
10140
- return httpClient.getYjsHistoryVersion({ roomId, versionId });
10182
+ async function fetchStorageHistoryVersion(versionId) {
10183
+ return httpClient.fetchStorageHistoryVersion({ roomId, versionId });
10184
+ }
10185
+ async function fetchYjsHistoryVersion(versionId) {
10186
+ return httpClient.fetchYjsHistoryVersion({ roomId, versionId });
10141
10187
  }
10142
10188
  async function createVersionHistorySnapshot() {
10143
10189
  return httpClient.createVersionHistorySnapshot({ roomId });
10144
10190
  }
10191
+ async function deleteHistoryVersion(versionId) {
10192
+ return httpClient.deleteHistoryVersion({ roomId, versionId });
10193
+ }
10145
10194
  async function executeContextualPrompt(options2) {
10146
10195
  return httpClient.executeContextualPrompt({
10147
10196
  roomId,
@@ -10191,17 +10240,19 @@ function createRoom(options, config) {
10191
10240
  self,
10192
10241
  (me) => me !== null ? userToTreeNode("Me", me) : null
10193
10242
  );
10243
+ function diffCurrentStorageAgainst(target) {
10244
+ const current = /* @__PURE__ */ new Map();
10245
+ for (const [id, crdt] of context.pool.nodes) {
10246
+ current.set(id, crdt._serialize());
10247
+ }
10248
+ return diffNodeMap(current, target);
10249
+ }
10194
10250
  function createOrUpdateRootFromMessage(nodes) {
10195
10251
  if (nodes.size === 0) {
10196
10252
  throw new Error("Internal error: cannot load storage without items");
10197
10253
  }
10198
10254
  if (context.root !== void 0) {
10199
- const currentItems = /* @__PURE__ */ new Map();
10200
- for (const [id, crdt] of context.pool.nodes) {
10201
- currentItems.set(id, crdt._serialize());
10202
- }
10203
- const ops = diffNodeMap(currentItems, nodes);
10204
- const result = applyRemoteOps(ops);
10255
+ const result = applyRemoteOps(diffCurrentStorageAgainst(nodes));
10205
10256
  notify(result.updates);
10206
10257
  } else {
10207
10258
  context.root = LiveObject._fromItems(
@@ -10226,6 +10277,28 @@ function createRoom(options, config) {
10226
10277
  }
10227
10278
  });
10228
10279
  }
10280
+ function reconcileStorageWithNodes(nodes) {
10281
+ if (context.root === void 0) {
10282
+ throw new Error("Cannot reconcile storage before it is loaded");
10283
+ }
10284
+ const ops = diffCurrentStorageAgainst(
10285
+ new Map(nodes)
10286
+ );
10287
+ if (ops.length === 0) {
10288
+ return;
10289
+ }
10290
+ const result = applyLocalOps(ops);
10291
+ if (result.reverse.length > 0) {
10292
+ addToUndoStack(result.reverse);
10293
+ }
10294
+ context.redoStack.length = 0;
10295
+ for (const op of result.opsToEmit) {
10296
+ context.buffer.storageOperations.push(op);
10297
+ }
10298
+ notify(result.updates);
10299
+ onHistoryChange();
10300
+ flushNowOrSoon();
10301
+ }
10229
10302
  function _addToRealUndoStack(frames) {
10230
10303
  if (context.undoStack.length >= 50) {
10231
10304
  context.undoStack.shift();
@@ -10395,6 +10468,10 @@ function createRoom(options, config) {
10395
10468
  }
10396
10469
  return parentNode._attachChild(op, source);
10397
10470
  }
10471
+ // Unknown op codes can be received when older and newer clients are
10472
+ // both present in a same room. Older clients simply ignore them.
10473
+ default:
10474
+ return { modified: false };
10398
10475
  }
10399
10476
  }
10400
10477
  function updatePresence(patch, options2) {
@@ -11546,9 +11623,16 @@ function createRoom(options, config) {
11546
11623
  // List versions of the document since the specified date
11547
11624
  listHistoryVersionsSince,
11548
11625
  // get a specific version
11549
- getYjsHistoryVersion,
11626
+ fetchStorageHistoryVersion,
11627
+ fetchYjsHistoryVersion,
11628
+ // reconstruct a storage version's nodes into a read-only LiveObject tree
11629
+ liveObjectFromNodeStream,
11630
+ // restore live storage to match a version's nodes
11631
+ reconcileStorageWithNodes,
11550
11632
  // create a version
11551
11633
  createVersionHistorySnapshot,
11634
+ // delete a version
11635
+ deleteHistoryVersion,
11552
11636
  // execute a contextual prompt
11553
11637
  executeContextualPrompt,
11554
11638
  // Support for the Liveblocks browser extension