@liveblocks/core 3.16.0-flow3 → 3.17.0-rc1
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 +993 -567
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +294 -56
- package/dist/index.d.ts +294 -56
- package/dist/index.js +962 -536
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
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.
|
|
9
|
+
var PKG_VERSION = "3.17.0-rc1";
|
|
10
10
|
var PKG_FORMAT = "esm";
|
|
11
11
|
|
|
12
12
|
// src/dupe-detection.ts
|
|
@@ -3219,10 +3219,26 @@ var ServerMsgCode = Object.freeze({
|
|
|
3219
3219
|
COMMENT_REACTION_ADDED: 405,
|
|
3220
3220
|
COMMENT_REACTION_REMOVED: 406,
|
|
3221
3221
|
COMMENT_METADATA_UPDATED: 409,
|
|
3222
|
+
// For Feeds
|
|
3223
|
+
FEEDS_LIST: 500,
|
|
3224
|
+
FEEDS_ADDED: 501,
|
|
3225
|
+
FEEDS_UPDATED: 502,
|
|
3226
|
+
FEED_DELETED: 503,
|
|
3227
|
+
FEED_MESSAGES_LIST: 504,
|
|
3228
|
+
FEED_MESSAGES_ADDED: 505,
|
|
3229
|
+
FEED_MESSAGES_UPDATED: 506,
|
|
3230
|
+
FEED_MESSAGES_DELETED: 507,
|
|
3231
|
+
FEED_REQUEST_FAILED: 508,
|
|
3222
3232
|
// Error codes
|
|
3223
3233
|
REJECT_STORAGE_OP: 299
|
|
3224
3234
|
// Sent if a mutation was not allowed on the server (i.e. due to permissions, limit exceeded, etc)
|
|
3225
3235
|
});
|
|
3236
|
+
var FeedRequestErrorCode = {
|
|
3237
|
+
INTERNAL: "INTERNAL",
|
|
3238
|
+
FEED_ALREADY_EXISTS: "FEED_ALREADY_EXISTS",
|
|
3239
|
+
FEED_NOT_FOUND: "FEED_NOT_FOUND",
|
|
3240
|
+
FEED_MESSAGE_NOT_FOUND: "FEED_MESSAGE_NOT_FOUND"
|
|
3241
|
+
};
|
|
3226
3242
|
|
|
3227
3243
|
// src/types/IWebSocket.ts
|
|
3228
3244
|
var WebsocketCloseCodes = /* @__PURE__ */ ((WebsocketCloseCodes2) => {
|
|
@@ -5186,6 +5202,7 @@ var Permission = /* @__PURE__ */ ((Permission2) => {
|
|
|
5186
5202
|
Permission2["PresenceWrite"] = "room:presence:write";
|
|
5187
5203
|
Permission2["CommentsWrite"] = "comments:write";
|
|
5188
5204
|
Permission2["CommentsRead"] = "comments:read";
|
|
5205
|
+
Permission2["FeedsWrite"] = "feeds:write";
|
|
5189
5206
|
return Permission2;
|
|
5190
5207
|
})(Permission || {});
|
|
5191
5208
|
function canWriteStorage(scopes) {
|
|
@@ -6718,7 +6735,10 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
6718
6735
|
};
|
|
6719
6736
|
} else {
|
|
6720
6737
|
if (indexOfItemWithSamePosition !== -1) {
|
|
6721
|
-
nn(
|
|
6738
|
+
const displaced = nn(
|
|
6739
|
+
this.#items.removeAt(indexOfItemWithSamePosition)
|
|
6740
|
+
);
|
|
6741
|
+
this.#implicitlyDeletedItems.add(displaced);
|
|
6722
6742
|
}
|
|
6723
6743
|
const { newItem, newIndex } = this.#createAttachItemAndSort(
|
|
6724
6744
|
op,
|
|
@@ -7866,61 +7886,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
7866
7886
|
}
|
|
7867
7887
|
};
|
|
7868
7888
|
|
|
7869
|
-
// src/
|
|
7870
|
-
function isJsonScalar(data) {
|
|
7871
|
-
return data === null || typeof data === "string" || typeof data === "number" || typeof data === "boolean";
|
|
7872
|
-
}
|
|
7873
|
-
function isJsonArray(data) {
|
|
7874
|
-
return Array.isArray(data);
|
|
7875
|
-
}
|
|
7876
|
-
function isJsonObject(data) {
|
|
7877
|
-
return !isJsonScalar(data) && !isJsonArray(data);
|
|
7878
|
-
}
|
|
7879
|
-
|
|
7880
|
-
// src/immutable.ts
|
|
7881
|
-
function lsonObjectToJson(obj) {
|
|
7882
|
-
const result = {};
|
|
7883
|
-
for (const key in obj) {
|
|
7884
|
-
const val = obj[key];
|
|
7885
|
-
if (val !== void 0) {
|
|
7886
|
-
result[key] = lsonToJson(val);
|
|
7887
|
-
}
|
|
7888
|
-
}
|
|
7889
|
-
return result;
|
|
7890
|
-
}
|
|
7891
|
-
function liveObjectToJson(liveObject) {
|
|
7892
|
-
return lsonObjectToJson(liveObject.toObject());
|
|
7893
|
-
}
|
|
7894
|
-
function liveMapToJson(map) {
|
|
7895
|
-
const result = {};
|
|
7896
|
-
for (const [key, value] of map.entries()) {
|
|
7897
|
-
result[key] = lsonToJson(value);
|
|
7898
|
-
}
|
|
7899
|
-
return result;
|
|
7900
|
-
}
|
|
7901
|
-
function lsonListToJson(value) {
|
|
7902
|
-
return value.map(lsonToJson);
|
|
7903
|
-
}
|
|
7904
|
-
function liveListToJson(value) {
|
|
7905
|
-
return lsonListToJson(value.toArray());
|
|
7906
|
-
}
|
|
7907
|
-
function lsonToJson(value) {
|
|
7908
|
-
if (value instanceof LiveObject) {
|
|
7909
|
-
return liveObjectToJson(value);
|
|
7910
|
-
} else if (value instanceof LiveList) {
|
|
7911
|
-
return liveListToJson(value);
|
|
7912
|
-
} else if (value instanceof LiveMap) {
|
|
7913
|
-
return liveMapToJson(value);
|
|
7914
|
-
} else if (value instanceof LiveRegister) {
|
|
7915
|
-
return value.data;
|
|
7916
|
-
}
|
|
7917
|
-
if (Array.isArray(value)) {
|
|
7918
|
-
return lsonListToJson(value);
|
|
7919
|
-
} else if (isPlainObject(value)) {
|
|
7920
|
-
return lsonObjectToJson(value);
|
|
7921
|
-
}
|
|
7922
|
-
return value;
|
|
7923
|
-
}
|
|
7889
|
+
// src/crdts/reconcile.ts
|
|
7924
7890
|
function deepLiveify(value, config) {
|
|
7925
7891
|
if (Array.isArray(value)) {
|
|
7926
7892
|
return new LiveList(value.map((v) => deepLiveify(v, config)));
|
|
@@ -8023,492 +7989,251 @@ function reconcileLiveList(liveList, jsonArr, config) {
|
|
|
8023
7989
|
}
|
|
8024
7990
|
return liveList;
|
|
8025
7991
|
}
|
|
8026
|
-
|
|
8027
|
-
|
|
8028
|
-
|
|
8029
|
-
|
|
8030
|
-
|
|
8031
|
-
|
|
8032
|
-
|
|
8033
|
-
|
|
8034
|
-
|
|
8035
|
-
|
|
8036
|
-
|
|
7992
|
+
|
|
7993
|
+
// src/crdts/LiveObject.ts
|
|
7994
|
+
var MAX_LIVE_OBJECT_SIZE = 128 * 1024;
|
|
7995
|
+
var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
7996
|
+
#synced;
|
|
7997
|
+
#local = /* @__PURE__ */ new Map();
|
|
7998
|
+
/**
|
|
7999
|
+
* Tracks unacknowledged local changes per property to preserve optimistic
|
|
8000
|
+
* updates. Maps property keys to their pending operation IDs.
|
|
8001
|
+
*
|
|
8002
|
+
* INVARIANT: Only locally-generated opIds are ever stored here. Remote opIds
|
|
8003
|
+
* are only compared against (to detect ACKs), never stored.
|
|
8004
|
+
*
|
|
8005
|
+
* When a local change is made, the opId is stored here. When a remote op
|
|
8006
|
+
* arrives for the same key:
|
|
8007
|
+
* - If no entry exists → apply remote op
|
|
8008
|
+
* - If opId matches → it's an ACK, clear the entry
|
|
8009
|
+
* - If opId differs → ignore remote op to preserve optimistic update
|
|
8010
|
+
*/
|
|
8011
|
+
#unackedOpsByKey;
|
|
8012
|
+
/**
|
|
8013
|
+
* Enable or disable detection of too large LiveObjects.
|
|
8014
|
+
* When enabled, throws an error if LiveObject static data exceeds 128KB, which
|
|
8015
|
+
* is the maximum value the server will be able to accept.
|
|
8016
|
+
* By default, this behavior is disabled to avoid the runtime performance
|
|
8017
|
+
* overhead on every LiveObject.set() or LiveObject.update() call.
|
|
8018
|
+
*
|
|
8019
|
+
* @experimental
|
|
8020
|
+
*/
|
|
8021
|
+
static detectLargeObjects = false;
|
|
8022
|
+
static #buildRootAndParentToChildren(nodes) {
|
|
8023
|
+
const parentToChildren = /* @__PURE__ */ new Map();
|
|
8024
|
+
let root = null;
|
|
8025
|
+
for (const node of nodes) {
|
|
8026
|
+
if (isRootStorageNode(node)) {
|
|
8027
|
+
root = node[1];
|
|
8028
|
+
} else {
|
|
8029
|
+
const crdt = node[1];
|
|
8030
|
+
const children = parentToChildren.get(crdt.parentId);
|
|
8031
|
+
if (children !== void 0) {
|
|
8032
|
+
children.push(node);
|
|
8033
|
+
} else {
|
|
8034
|
+
parentToChildren.set(crdt.parentId, [node]);
|
|
8035
|
+
}
|
|
8037
8036
|
}
|
|
8038
|
-
prevNode = prev[i];
|
|
8039
|
-
nextNode = next[i];
|
|
8040
8037
|
}
|
|
8041
|
-
|
|
8042
|
-
|
|
8043
|
-
while (prevNode === nextNode) {
|
|
8044
|
-
prevEnd--;
|
|
8045
|
-
nextEnd--;
|
|
8046
|
-
if (i > prevEnd || i > nextEnd) {
|
|
8047
|
-
break outer;
|
|
8048
|
-
}
|
|
8049
|
-
prevNode = prev[prevEnd];
|
|
8050
|
-
nextNode = next[nextEnd];
|
|
8038
|
+
if (root === null) {
|
|
8039
|
+
throw new Error("Root can't be null");
|
|
8051
8040
|
}
|
|
8041
|
+
return [root, parentToChildren];
|
|
8052
8042
|
}
|
|
8053
|
-
|
|
8054
|
-
|
|
8055
|
-
|
|
8056
|
-
|
|
8057
|
-
|
|
8043
|
+
/** @private Do not use this API directly */
|
|
8044
|
+
static _fromItems(nodes, pool) {
|
|
8045
|
+
const [root, parentToChildren] = _LiveObject.#buildRootAndParentToChildren(nodes);
|
|
8046
|
+
return _LiveObject._deserialize(
|
|
8047
|
+
["root", root],
|
|
8048
|
+
parentToChildren,
|
|
8049
|
+
pool
|
|
8050
|
+
);
|
|
8051
|
+
}
|
|
8052
|
+
constructor(obj = {}) {
|
|
8053
|
+
super();
|
|
8054
|
+
this.#unackedOpsByKey = /* @__PURE__ */ new Map();
|
|
8055
|
+
const o = compactObject(obj);
|
|
8056
|
+
for (const key of Object.keys(o)) {
|
|
8057
|
+
const value = o[key];
|
|
8058
|
+
if (isLiveNode(value)) {
|
|
8059
|
+
value._setParentLink(this, key);
|
|
8058
8060
|
}
|
|
8059
8061
|
}
|
|
8060
|
-
|
|
8061
|
-
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
|
|
8062
|
+
this.#synced = new Map(Object.entries(o));
|
|
8063
|
+
}
|
|
8064
|
+
/** @internal */
|
|
8065
|
+
_toOps(parentId, parentKey) {
|
|
8066
|
+
if (this._id === void 0) {
|
|
8067
|
+
throw new Error("Cannot serialize item is not attached");
|
|
8065
8068
|
}
|
|
8066
|
-
|
|
8067
|
-
|
|
8068
|
-
|
|
8069
|
-
|
|
8070
|
-
|
|
8071
|
-
|
|
8072
|
-
|
|
8069
|
+
const ops = [];
|
|
8070
|
+
const op = {
|
|
8071
|
+
type: OpCode.CREATE_OBJECT,
|
|
8072
|
+
id: this._id,
|
|
8073
|
+
parentId,
|
|
8074
|
+
parentKey,
|
|
8075
|
+
data: {}
|
|
8076
|
+
};
|
|
8077
|
+
ops.push(op);
|
|
8078
|
+
for (const [key, value] of this.#synced) {
|
|
8079
|
+
if (isLiveNode(value)) {
|
|
8080
|
+
for (const childOp of value._toOps(this._id, key)) {
|
|
8081
|
+
ops.push(childOp);
|
|
8082
|
+
}
|
|
8073
8083
|
} else {
|
|
8074
|
-
|
|
8084
|
+
op.data[key] = value;
|
|
8075
8085
|
}
|
|
8076
|
-
i++;
|
|
8077
8086
|
}
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8087
|
+
return ops;
|
|
8088
|
+
}
|
|
8089
|
+
/** @internal */
|
|
8090
|
+
static _deserialize([id, item], parentToChildren, pool) {
|
|
8091
|
+
const liveObj = new _LiveObject(item.data);
|
|
8092
|
+
liveObj._attach(id, pool);
|
|
8093
|
+
return this._deserializeChildren(liveObj, parentToChildren, pool);
|
|
8094
|
+
}
|
|
8095
|
+
/** @internal */
|
|
8096
|
+
static _deserializeChildren(liveObj, parentToChildren, pool) {
|
|
8097
|
+
const children = parentToChildren.get(nn(liveObj._id));
|
|
8098
|
+
if (children === void 0) {
|
|
8099
|
+
return liveObj;
|
|
8081
8100
|
}
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8101
|
+
for (const node of children) {
|
|
8102
|
+
const child = deserializeToLson(node, parentToChildren, pool);
|
|
8103
|
+
const crdt = node[1];
|
|
8104
|
+
if (isLiveStructure(child)) {
|
|
8105
|
+
child._setParentLink(liveObj, crdt.parentKey);
|
|
8106
|
+
}
|
|
8107
|
+
liveObj.#synced.set(crdt.parentKey, child);
|
|
8108
|
+
liveObj.invalidate();
|
|
8086
8109
|
}
|
|
8110
|
+
return liveObj;
|
|
8087
8111
|
}
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
const
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
|
|
8095
|
-
nonSerializableValue.value
|
|
8096
|
-
)}' is not serializable.
|
|
8097
|
-
Only serializable value can be synced with Liveblocks.`
|
|
8098
|
-
);
|
|
8099
|
-
return;
|
|
8112
|
+
/** @internal */
|
|
8113
|
+
_attach(id, pool) {
|
|
8114
|
+
super._attach(id, pool);
|
|
8115
|
+
for (const [_key, value] of this.#synced) {
|
|
8116
|
+
if (isLiveNode(value)) {
|
|
8117
|
+
value._attach(pool.generateId(), pool);
|
|
8118
|
+
}
|
|
8100
8119
|
}
|
|
8101
8120
|
}
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
}
|
|
8122
|
-
for (const key in prev) {
|
|
8123
|
-
if (next[key] === void 0) {
|
|
8124
|
-
root.delete(key);
|
|
8125
|
-
}
|
|
8126
|
-
}
|
|
8127
|
-
if (Object.keys(updates).length > 0) {
|
|
8128
|
-
root.update(updates);
|
|
8129
|
-
}
|
|
8130
|
-
}
|
|
8131
|
-
function getParentsPath(node) {
|
|
8132
|
-
const path = [];
|
|
8133
|
-
while (node.parent.type === "HasParent") {
|
|
8134
|
-
if (isLiveList(node.parent.node)) {
|
|
8135
|
-
path.push(node.parent.node._indexOfPosition(node.parent.key));
|
|
8121
|
+
/** @internal */
|
|
8122
|
+
_attachChild(op, source) {
|
|
8123
|
+
if (this._pool === void 0) {
|
|
8124
|
+
throw new Error("Can't attach child if managed pool is not present");
|
|
8125
|
+
}
|
|
8126
|
+
const { id, opId, parentKey: key } = op;
|
|
8127
|
+
const child = creationOpToLson(op);
|
|
8128
|
+
if (this._pool.getNode(id) !== void 0) {
|
|
8129
|
+
if (this.#unackedOpsByKey.get(key) === opId) {
|
|
8130
|
+
this.#unackedOpsByKey.delete(key);
|
|
8131
|
+
}
|
|
8132
|
+
return { modified: false };
|
|
8133
|
+
}
|
|
8134
|
+
if (source === 0 /* LOCAL */) {
|
|
8135
|
+
this.#unackedOpsByKey.set(key, nn(opId));
|
|
8136
|
+
} else if (this.#unackedOpsByKey.get(key) === void 0) {
|
|
8137
|
+
} else if (this.#unackedOpsByKey.get(key) === opId) {
|
|
8138
|
+
this.#unackedOpsByKey.delete(key);
|
|
8139
|
+
return { modified: false };
|
|
8136
8140
|
} else {
|
|
8137
|
-
|
|
8141
|
+
return { modified: false };
|
|
8138
8142
|
}
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
}
|
|
8153
|
-
function legacy_patchImmutableNode(state, path, update) {
|
|
8154
|
-
const pathItem = path.pop();
|
|
8155
|
-
if (pathItem === void 0) {
|
|
8156
|
-
switch (update.type) {
|
|
8157
|
-
case "LiveObject": {
|
|
8158
|
-
if (!isJsonObject(state)) {
|
|
8159
|
-
throw new Error(
|
|
8160
|
-
"Internal: received update on LiveObject but state was not an object"
|
|
8161
|
-
);
|
|
8162
|
-
}
|
|
8163
|
-
const newState = Object.assign({}, state);
|
|
8164
|
-
for (const key in update.updates) {
|
|
8165
|
-
if (update.updates[key]?.type === "update") {
|
|
8166
|
-
const val = update.node.get(key);
|
|
8167
|
-
if (val !== void 0) {
|
|
8168
|
-
newState[key] = lsonToJson(val);
|
|
8169
|
-
}
|
|
8170
|
-
} else if (update.updates[key]?.type === "delete") {
|
|
8171
|
-
delete newState[key];
|
|
8172
|
-
}
|
|
8143
|
+
const thisId = nn(this._id);
|
|
8144
|
+
const previousValue = this.#synced.get(key);
|
|
8145
|
+
let reverse;
|
|
8146
|
+
if (isLiveNode(previousValue)) {
|
|
8147
|
+
reverse = previousValue._toOps(thisId, key);
|
|
8148
|
+
previousValue._detach();
|
|
8149
|
+
} else if (previousValue === void 0) {
|
|
8150
|
+
reverse = [{ type: OpCode.DELETE_OBJECT_KEY, id: thisId, key }];
|
|
8151
|
+
} else {
|
|
8152
|
+
reverse = [
|
|
8153
|
+
{
|
|
8154
|
+
type: OpCode.UPDATE_OBJECT,
|
|
8155
|
+
id: thisId,
|
|
8156
|
+
data: { [key]: previousValue }
|
|
8173
8157
|
}
|
|
8174
|
-
|
|
8158
|
+
];
|
|
8159
|
+
}
|
|
8160
|
+
this.#local.delete(key);
|
|
8161
|
+
this.#synced.set(key, child);
|
|
8162
|
+
this.invalidate();
|
|
8163
|
+
if (isLiveStructure(child)) {
|
|
8164
|
+
child._setParentLink(this, key);
|
|
8165
|
+
child._attach(id, this._pool);
|
|
8166
|
+
}
|
|
8167
|
+
return {
|
|
8168
|
+
reverse,
|
|
8169
|
+
modified: {
|
|
8170
|
+
node: this,
|
|
8171
|
+
type: "LiveObject",
|
|
8172
|
+
updates: { [key]: { type: "update" } }
|
|
8175
8173
|
}
|
|
8176
|
-
|
|
8177
|
-
|
|
8178
|
-
|
|
8179
|
-
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
} else if (listUpdate.type === "insert") {
|
|
8189
|
-
if (listUpdate.index === newState.length) {
|
|
8190
|
-
newState.push(lsonToJson(listUpdate.item));
|
|
8191
|
-
} else {
|
|
8192
|
-
newState = [
|
|
8193
|
-
...newState.slice(0, listUpdate.index),
|
|
8194
|
-
lsonToJson(listUpdate.item),
|
|
8195
|
-
...newState.slice(listUpdate.index)
|
|
8196
|
-
];
|
|
8197
|
-
}
|
|
8198
|
-
} else if (listUpdate.type === "delete") {
|
|
8199
|
-
newState.splice(listUpdate.index, 1);
|
|
8200
|
-
} else if (listUpdate.type === "move") {
|
|
8201
|
-
if (listUpdate.previousIndex > listUpdate.index) {
|
|
8202
|
-
newState = [
|
|
8203
|
-
...newState.slice(0, listUpdate.index),
|
|
8204
|
-
lsonToJson(listUpdate.item),
|
|
8205
|
-
...newState.slice(listUpdate.index, listUpdate.previousIndex),
|
|
8206
|
-
...newState.slice(listUpdate.previousIndex + 1)
|
|
8207
|
-
];
|
|
8208
|
-
} else {
|
|
8209
|
-
newState = [
|
|
8210
|
-
...newState.slice(0, listUpdate.previousIndex),
|
|
8211
|
-
...newState.slice(
|
|
8212
|
-
listUpdate.previousIndex + 1,
|
|
8213
|
-
listUpdate.index + 1
|
|
8214
|
-
),
|
|
8215
|
-
lsonToJson(listUpdate.item),
|
|
8216
|
-
...newState.slice(listUpdate.index + 1)
|
|
8217
|
-
];
|
|
8218
|
-
}
|
|
8219
|
-
}
|
|
8174
|
+
};
|
|
8175
|
+
}
|
|
8176
|
+
/** @internal */
|
|
8177
|
+
_detachChild(child) {
|
|
8178
|
+
if (child) {
|
|
8179
|
+
const id = nn(this._id);
|
|
8180
|
+
const parentKey = nn(child._parentKey);
|
|
8181
|
+
const reverse = child._toOps(id, parentKey);
|
|
8182
|
+
for (const [key, value] of this.#synced) {
|
|
8183
|
+
if (value === child) {
|
|
8184
|
+
this.#synced.delete(key);
|
|
8185
|
+
this.invalidate();
|
|
8220
8186
|
}
|
|
8221
|
-
return newState;
|
|
8222
8187
|
}
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
const newState = Object.assign({}, state);
|
|
8230
|
-
for (const key in update.updates) {
|
|
8231
|
-
if (update.updates[key]?.type === "update") {
|
|
8232
|
-
const value = update.node.get(key);
|
|
8233
|
-
if (value !== void 0) {
|
|
8234
|
-
newState[key] = lsonToJson(value);
|
|
8235
|
-
}
|
|
8236
|
-
} else if (update.updates[key]?.type === "delete") {
|
|
8237
|
-
delete newState[key];
|
|
8238
|
-
}
|
|
8188
|
+
child._detach();
|
|
8189
|
+
const storageUpdate = {
|
|
8190
|
+
node: this,
|
|
8191
|
+
type: "LiveObject",
|
|
8192
|
+
updates: {
|
|
8193
|
+
[parentKey]: { type: "delete" }
|
|
8239
8194
|
}
|
|
8240
|
-
|
|
8195
|
+
};
|
|
8196
|
+
return { modified: storageUpdate, reverse };
|
|
8197
|
+
}
|
|
8198
|
+
return { modified: false };
|
|
8199
|
+
}
|
|
8200
|
+
/** @internal */
|
|
8201
|
+
_detach() {
|
|
8202
|
+
super._detach();
|
|
8203
|
+
for (const value of this.#synced.values()) {
|
|
8204
|
+
if (isLiveNode(value)) {
|
|
8205
|
+
value._detach();
|
|
8241
8206
|
}
|
|
8242
8207
|
}
|
|
8243
8208
|
}
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
return
|
|
8252
|
-
}
|
|
8253
|
-
|
|
8254
|
-
|
|
8255
|
-
|
|
8209
|
+
/** @internal */
|
|
8210
|
+
_apply(op, isLocal) {
|
|
8211
|
+
if (op.type === OpCode.UPDATE_OBJECT) {
|
|
8212
|
+
return this.#applyUpdate(op, isLocal);
|
|
8213
|
+
} else if (op.type === OpCode.DELETE_OBJECT_KEY) {
|
|
8214
|
+
return this.#applyDeleteObjectKey(op, isLocal);
|
|
8215
|
+
}
|
|
8216
|
+
return super._apply(op, isLocal);
|
|
8217
|
+
}
|
|
8218
|
+
/** @internal */
|
|
8219
|
+
_serialize() {
|
|
8220
|
+
const data = {};
|
|
8221
|
+
for (const [key, value] of this.#synced) {
|
|
8222
|
+
if (!isLiveNode(value)) {
|
|
8223
|
+
data[key] = value;
|
|
8224
|
+
}
|
|
8225
|
+
}
|
|
8226
|
+
if (this.parent.type === "HasParent" && this.parent.node._id) {
|
|
8227
|
+
return {
|
|
8228
|
+
type: CrdtType.OBJECT,
|
|
8229
|
+
parentId: this.parent.node._id,
|
|
8230
|
+
parentKey: this.parent.key,
|
|
8231
|
+
data
|
|
8232
|
+
};
|
|
8256
8233
|
} else {
|
|
8257
|
-
const stateAsObj = state;
|
|
8258
8234
|
return {
|
|
8259
|
-
|
|
8260
|
-
|
|
8261
|
-
};
|
|
8262
|
-
}
|
|
8263
|
-
} else {
|
|
8264
|
-
return state;
|
|
8265
|
-
}
|
|
8266
|
-
}
|
|
8267
|
-
|
|
8268
|
-
// src/crdts/LiveObject.ts
|
|
8269
|
-
var MAX_LIVE_OBJECT_SIZE = 128 * 1024;
|
|
8270
|
-
var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
8271
|
-
#synced;
|
|
8272
|
-
#local = /* @__PURE__ */ new Map();
|
|
8273
|
-
/**
|
|
8274
|
-
* Tracks unacknowledged local changes per property to preserve optimistic
|
|
8275
|
-
* updates. Maps property keys to their pending operation IDs.
|
|
8276
|
-
*
|
|
8277
|
-
* INVARIANT: Only locally-generated opIds are ever stored here. Remote opIds
|
|
8278
|
-
* are only compared against (to detect ACKs), never stored.
|
|
8279
|
-
*
|
|
8280
|
-
* When a local change is made, the opId is stored here. When a remote op
|
|
8281
|
-
* arrives for the same key:
|
|
8282
|
-
* - If no entry exists → apply remote op
|
|
8283
|
-
* - If opId matches → it's an ACK, clear the entry
|
|
8284
|
-
* - If opId differs → ignore remote op to preserve optimistic update
|
|
8285
|
-
*/
|
|
8286
|
-
#unackedOpsByKey;
|
|
8287
|
-
/**
|
|
8288
|
-
* Enable or disable detection of too large LiveObjects.
|
|
8289
|
-
* When enabled, throws an error if LiveObject static data exceeds 128KB, which
|
|
8290
|
-
* is the maximum value the server will be able to accept.
|
|
8291
|
-
* By default, this behavior is disabled to avoid the runtime performance
|
|
8292
|
-
* overhead on every LiveObject.set() or LiveObject.update() call.
|
|
8293
|
-
*
|
|
8294
|
-
* @experimental
|
|
8295
|
-
*/
|
|
8296
|
-
static detectLargeObjects = false;
|
|
8297
|
-
static #buildRootAndParentToChildren(nodes) {
|
|
8298
|
-
const parentToChildren = /* @__PURE__ */ new Map();
|
|
8299
|
-
let root = null;
|
|
8300
|
-
for (const node of nodes) {
|
|
8301
|
-
if (isRootStorageNode(node)) {
|
|
8302
|
-
root = node[1];
|
|
8303
|
-
} else {
|
|
8304
|
-
const crdt = node[1];
|
|
8305
|
-
const children = parentToChildren.get(crdt.parentId);
|
|
8306
|
-
if (children !== void 0) {
|
|
8307
|
-
children.push(node);
|
|
8308
|
-
} else {
|
|
8309
|
-
parentToChildren.set(crdt.parentId, [node]);
|
|
8310
|
-
}
|
|
8311
|
-
}
|
|
8312
|
-
}
|
|
8313
|
-
if (root === null) {
|
|
8314
|
-
throw new Error("Root can't be null");
|
|
8315
|
-
}
|
|
8316
|
-
return [root, parentToChildren];
|
|
8317
|
-
}
|
|
8318
|
-
/** @private Do not use this API directly */
|
|
8319
|
-
static _fromItems(nodes, pool) {
|
|
8320
|
-
const [root, parentToChildren] = _LiveObject.#buildRootAndParentToChildren(nodes);
|
|
8321
|
-
return _LiveObject._deserialize(
|
|
8322
|
-
["root", root],
|
|
8323
|
-
parentToChildren,
|
|
8324
|
-
pool
|
|
8325
|
-
);
|
|
8326
|
-
}
|
|
8327
|
-
constructor(obj = {}) {
|
|
8328
|
-
super();
|
|
8329
|
-
this.#unackedOpsByKey = /* @__PURE__ */ new Map();
|
|
8330
|
-
const o = compactObject(obj);
|
|
8331
|
-
for (const key of Object.keys(o)) {
|
|
8332
|
-
const value = o[key];
|
|
8333
|
-
if (isLiveNode(value)) {
|
|
8334
|
-
value._setParentLink(this, key);
|
|
8335
|
-
}
|
|
8336
|
-
}
|
|
8337
|
-
this.#synced = new Map(Object.entries(o));
|
|
8338
|
-
}
|
|
8339
|
-
/** @internal */
|
|
8340
|
-
_toOps(parentId, parentKey) {
|
|
8341
|
-
if (this._id === void 0) {
|
|
8342
|
-
throw new Error("Cannot serialize item is not attached");
|
|
8343
|
-
}
|
|
8344
|
-
const ops = [];
|
|
8345
|
-
const op = {
|
|
8346
|
-
type: OpCode.CREATE_OBJECT,
|
|
8347
|
-
id: this._id,
|
|
8348
|
-
parentId,
|
|
8349
|
-
parentKey,
|
|
8350
|
-
data: {}
|
|
8351
|
-
};
|
|
8352
|
-
ops.push(op);
|
|
8353
|
-
for (const [key, value] of this.#synced) {
|
|
8354
|
-
if (isLiveNode(value)) {
|
|
8355
|
-
for (const childOp of value._toOps(this._id, key)) {
|
|
8356
|
-
ops.push(childOp);
|
|
8357
|
-
}
|
|
8358
|
-
} else {
|
|
8359
|
-
op.data[key] = value;
|
|
8360
|
-
}
|
|
8361
|
-
}
|
|
8362
|
-
return ops;
|
|
8363
|
-
}
|
|
8364
|
-
/** @internal */
|
|
8365
|
-
static _deserialize([id, item], parentToChildren, pool) {
|
|
8366
|
-
const liveObj = new _LiveObject(item.data);
|
|
8367
|
-
liveObj._attach(id, pool);
|
|
8368
|
-
return this._deserializeChildren(liveObj, parentToChildren, pool);
|
|
8369
|
-
}
|
|
8370
|
-
/** @internal */
|
|
8371
|
-
static _deserializeChildren(liveObj, parentToChildren, pool) {
|
|
8372
|
-
const children = parentToChildren.get(nn(liveObj._id));
|
|
8373
|
-
if (children === void 0) {
|
|
8374
|
-
return liveObj;
|
|
8375
|
-
}
|
|
8376
|
-
for (const node of children) {
|
|
8377
|
-
const child = deserializeToLson(node, parentToChildren, pool);
|
|
8378
|
-
const crdt = node[1];
|
|
8379
|
-
if (isLiveStructure(child)) {
|
|
8380
|
-
child._setParentLink(liveObj, crdt.parentKey);
|
|
8381
|
-
}
|
|
8382
|
-
liveObj.#synced.set(crdt.parentKey, child);
|
|
8383
|
-
liveObj.invalidate();
|
|
8384
|
-
}
|
|
8385
|
-
return liveObj;
|
|
8386
|
-
}
|
|
8387
|
-
/** @internal */
|
|
8388
|
-
_attach(id, pool) {
|
|
8389
|
-
super._attach(id, pool);
|
|
8390
|
-
for (const [_key, value] of this.#synced) {
|
|
8391
|
-
if (isLiveNode(value)) {
|
|
8392
|
-
value._attach(pool.generateId(), pool);
|
|
8393
|
-
}
|
|
8394
|
-
}
|
|
8395
|
-
}
|
|
8396
|
-
/** @internal */
|
|
8397
|
-
_attachChild(op, source) {
|
|
8398
|
-
if (this._pool === void 0) {
|
|
8399
|
-
throw new Error("Can't attach child if managed pool is not present");
|
|
8400
|
-
}
|
|
8401
|
-
const { id, opId, parentKey: key } = op;
|
|
8402
|
-
const child = creationOpToLson(op);
|
|
8403
|
-
if (this._pool.getNode(id) !== void 0) {
|
|
8404
|
-
if (this.#unackedOpsByKey.get(key) === opId) {
|
|
8405
|
-
this.#unackedOpsByKey.delete(key);
|
|
8406
|
-
}
|
|
8407
|
-
return { modified: false };
|
|
8408
|
-
}
|
|
8409
|
-
if (source === 0 /* LOCAL */) {
|
|
8410
|
-
this.#unackedOpsByKey.set(key, nn(opId));
|
|
8411
|
-
} else if (this.#unackedOpsByKey.get(key) === void 0) {
|
|
8412
|
-
} else if (this.#unackedOpsByKey.get(key) === opId) {
|
|
8413
|
-
this.#unackedOpsByKey.delete(key);
|
|
8414
|
-
return { modified: false };
|
|
8415
|
-
} else {
|
|
8416
|
-
return { modified: false };
|
|
8417
|
-
}
|
|
8418
|
-
const thisId = nn(this._id);
|
|
8419
|
-
const previousValue = this.#synced.get(key);
|
|
8420
|
-
let reverse;
|
|
8421
|
-
if (isLiveNode(previousValue)) {
|
|
8422
|
-
reverse = previousValue._toOps(thisId, key);
|
|
8423
|
-
previousValue._detach();
|
|
8424
|
-
} else if (previousValue === void 0) {
|
|
8425
|
-
reverse = [{ type: OpCode.DELETE_OBJECT_KEY, id: thisId, key }];
|
|
8426
|
-
} else {
|
|
8427
|
-
reverse = [
|
|
8428
|
-
{
|
|
8429
|
-
type: OpCode.UPDATE_OBJECT,
|
|
8430
|
-
id: thisId,
|
|
8431
|
-
data: { [key]: previousValue }
|
|
8432
|
-
}
|
|
8433
|
-
];
|
|
8434
|
-
}
|
|
8435
|
-
this.#local.delete(key);
|
|
8436
|
-
this.#synced.set(key, child);
|
|
8437
|
-
this.invalidate();
|
|
8438
|
-
if (isLiveStructure(child)) {
|
|
8439
|
-
child._setParentLink(this, key);
|
|
8440
|
-
child._attach(id, this._pool);
|
|
8441
|
-
}
|
|
8442
|
-
return {
|
|
8443
|
-
reverse,
|
|
8444
|
-
modified: {
|
|
8445
|
-
node: this,
|
|
8446
|
-
type: "LiveObject",
|
|
8447
|
-
updates: { [key]: { type: "update" } }
|
|
8448
|
-
}
|
|
8449
|
-
};
|
|
8450
|
-
}
|
|
8451
|
-
/** @internal */
|
|
8452
|
-
_detachChild(child) {
|
|
8453
|
-
if (child) {
|
|
8454
|
-
const id = nn(this._id);
|
|
8455
|
-
const parentKey = nn(child._parentKey);
|
|
8456
|
-
const reverse = child._toOps(id, parentKey);
|
|
8457
|
-
for (const [key, value] of this.#synced) {
|
|
8458
|
-
if (value === child) {
|
|
8459
|
-
this.#synced.delete(key);
|
|
8460
|
-
this.invalidate();
|
|
8461
|
-
}
|
|
8462
|
-
}
|
|
8463
|
-
child._detach();
|
|
8464
|
-
const storageUpdate = {
|
|
8465
|
-
node: this,
|
|
8466
|
-
type: "LiveObject",
|
|
8467
|
-
updates: {
|
|
8468
|
-
[parentKey]: { type: "delete" }
|
|
8469
|
-
}
|
|
8470
|
-
};
|
|
8471
|
-
return { modified: storageUpdate, reverse };
|
|
8472
|
-
}
|
|
8473
|
-
return { modified: false };
|
|
8474
|
-
}
|
|
8475
|
-
/** @internal */
|
|
8476
|
-
_detach() {
|
|
8477
|
-
super._detach();
|
|
8478
|
-
for (const value of this.#synced.values()) {
|
|
8479
|
-
if (isLiveNode(value)) {
|
|
8480
|
-
value._detach();
|
|
8481
|
-
}
|
|
8482
|
-
}
|
|
8483
|
-
}
|
|
8484
|
-
/** @internal */
|
|
8485
|
-
_apply(op, isLocal) {
|
|
8486
|
-
if (op.type === OpCode.UPDATE_OBJECT) {
|
|
8487
|
-
return this.#applyUpdate(op, isLocal);
|
|
8488
|
-
} else if (op.type === OpCode.DELETE_OBJECT_KEY) {
|
|
8489
|
-
return this.#applyDeleteObjectKey(op, isLocal);
|
|
8490
|
-
}
|
|
8491
|
-
return super._apply(op, isLocal);
|
|
8492
|
-
}
|
|
8493
|
-
/** @internal */
|
|
8494
|
-
_serialize() {
|
|
8495
|
-
const data = {};
|
|
8496
|
-
for (const [key, value] of this.#synced) {
|
|
8497
|
-
if (!isLiveNode(value)) {
|
|
8498
|
-
data[key] = value;
|
|
8499
|
-
}
|
|
8500
|
-
}
|
|
8501
|
-
if (this.parent.type === "HasParent" && this.parent.node._id) {
|
|
8502
|
-
return {
|
|
8503
|
-
type: CrdtType.OBJECT,
|
|
8504
|
-
parentId: this.parent.node._id,
|
|
8505
|
-
parentKey: this.parent.key,
|
|
8506
|
-
data
|
|
8507
|
-
};
|
|
8508
|
-
} else {
|
|
8509
|
-
return {
|
|
8510
|
-
type: CrdtType.OBJECT,
|
|
8511
|
-
data
|
|
8235
|
+
type: CrdtType.OBJECT,
|
|
8236
|
+
data
|
|
8512
8237
|
};
|
|
8513
8238
|
}
|
|
8514
8239
|
}
|
|
@@ -8824,6 +8549,9 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
8824
8549
|
continue;
|
|
8825
8550
|
}
|
|
8826
8551
|
const oldValue = this.#synced.get(key);
|
|
8552
|
+
if (oldValue === newValue) {
|
|
8553
|
+
continue;
|
|
8554
|
+
}
|
|
8827
8555
|
if (isLiveNode(oldValue)) {
|
|
8828
8556
|
for (const childOp of oldValue._toOps(this._id, key)) {
|
|
8829
8557
|
reverseOps.push(childOp);
|
|
@@ -8871,6 +8599,9 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
8871
8599
|
data: updatedProps
|
|
8872
8600
|
});
|
|
8873
8601
|
}
|
|
8602
|
+
if (ops.length === 0 && reverseOps.length === 0 && Object.keys(updateDelta).length === 0) {
|
|
8603
|
+
return;
|
|
8604
|
+
}
|
|
8874
8605
|
const storageUpdates = /* @__PURE__ */ new Map();
|
|
8875
8606
|
storageUpdates.set(this._id, {
|
|
8876
8607
|
node: this,
|
|
@@ -9249,6 +8980,17 @@ var Deque = class {
|
|
|
9249
8980
|
}
|
|
9250
8981
|
};
|
|
9251
8982
|
|
|
8983
|
+
// src/lib/Json.ts
|
|
8984
|
+
function isJsonScalar(data) {
|
|
8985
|
+
return data === null || typeof data === "string" || typeof data === "number" || typeof data === "boolean";
|
|
8986
|
+
}
|
|
8987
|
+
function isJsonArray(data) {
|
|
8988
|
+
return Array.isArray(data);
|
|
8989
|
+
}
|
|
8990
|
+
function isJsonObject(data) {
|
|
8991
|
+
return !isJsonScalar(data) && !isJsonArray(data);
|
|
8992
|
+
}
|
|
8993
|
+
|
|
9252
8994
|
// src/lib/stopwatch.ts
|
|
9253
8995
|
function makeStopWatch() {
|
|
9254
8996
|
let startTime = 0;
|
|
@@ -9282,7 +9024,16 @@ var ClientMsgCode = Object.freeze({
|
|
|
9282
9024
|
UPDATE_STORAGE: 201,
|
|
9283
9025
|
// For Yjs support
|
|
9284
9026
|
FETCH_YDOC: 300,
|
|
9285
|
-
UPDATE_YDOC: 301
|
|
9027
|
+
UPDATE_YDOC: 301,
|
|
9028
|
+
// For Feeds
|
|
9029
|
+
FETCH_FEEDS: 510,
|
|
9030
|
+
FETCH_FEED_MESSAGES: 511,
|
|
9031
|
+
ADD_FEED: 512,
|
|
9032
|
+
UPDATE_FEED: 513,
|
|
9033
|
+
DELETE_FEED: 514,
|
|
9034
|
+
ADD_FEED_MESSAGE: 515,
|
|
9035
|
+
UPDATE_FEED_MESSAGE: 516,
|
|
9036
|
+
DELETE_FEED_MESSAGE: 517
|
|
9286
9037
|
});
|
|
9287
9038
|
|
|
9288
9039
|
// src/refs/ManagedOthers.ts
|
|
@@ -9518,12 +9269,15 @@ function defaultMessageFromContext(context) {
|
|
|
9518
9269
|
return "Could not update notification settings";
|
|
9519
9270
|
case "LARGE_MESSAGE_ERROR":
|
|
9520
9271
|
return "Could not send large message";
|
|
9272
|
+
case "FEED_REQUEST_ERROR":
|
|
9273
|
+
return context.reason ?? "Feed request failed";
|
|
9521
9274
|
default:
|
|
9522
9275
|
return assertNever(context, "Unhandled case");
|
|
9523
9276
|
}
|
|
9524
9277
|
}
|
|
9525
9278
|
|
|
9526
9279
|
// src/room.ts
|
|
9280
|
+
var FEEDS_TIMEOUT = 5e3;
|
|
9527
9281
|
function makeIdFactory(connectionId) {
|
|
9528
9282
|
let count = 0;
|
|
9529
9283
|
return () => `${connectionId}:${count++}`;
|
|
@@ -9762,6 +9516,7 @@ function createRoom(options, config) {
|
|
|
9762
9516
|
storageStatus: makeEventSource(),
|
|
9763
9517
|
ydoc: makeEventSource(),
|
|
9764
9518
|
comments: makeEventSource(),
|
|
9519
|
+
feeds: makeEventSource(),
|
|
9765
9520
|
roomWillDestroy: makeEventSource()
|
|
9766
9521
|
};
|
|
9767
9522
|
async function createTextMention(mentionId, mention) {
|
|
@@ -10183,6 +9938,9 @@ function createRoom(options, config) {
|
|
|
10183
9938
|
notify(result.updates);
|
|
10184
9939
|
sendMessages(messages);
|
|
10185
9940
|
}
|
|
9941
|
+
function isFeedRequestFailedMsg(msg) {
|
|
9942
|
+
return msg.type === ServerMsgCode.FEED_REQUEST_FAILED;
|
|
9943
|
+
}
|
|
10186
9944
|
function handleServerMessage(event) {
|
|
10187
9945
|
if (typeof event.data !== "string") {
|
|
10188
9946
|
return;
|
|
@@ -10296,23 +10054,111 @@ function createRoom(options, config) {
|
|
|
10296
10054
|
eventHub.comments.notify(message);
|
|
10297
10055
|
break;
|
|
10298
10056
|
}
|
|
10299
|
-
case ServerMsgCode.
|
|
10300
|
-
|
|
10301
|
-
|
|
10057
|
+
case ServerMsgCode.FEEDS_LIST: {
|
|
10058
|
+
const feedsListMsg = message;
|
|
10059
|
+
const pending = pendingFeedsRequests.get(feedsListMsg.requestId);
|
|
10060
|
+
if (pending) {
|
|
10061
|
+
pending.resolve({
|
|
10062
|
+
feeds: feedsListMsg.feeds,
|
|
10063
|
+
nextCursor: feedsListMsg.nextCursor
|
|
10064
|
+
});
|
|
10065
|
+
pendingFeedsRequests.delete(feedsListMsg.requestId);
|
|
10066
|
+
}
|
|
10067
|
+
eventHub.feeds.notify(feedsListMsg);
|
|
10302
10068
|
break;
|
|
10303
|
-
|
|
10304
|
-
|
|
10305
|
-
|
|
10306
|
-
|
|
10307
|
-
|
|
10308
|
-
|
|
10309
|
-
|
|
10310
|
-
|
|
10311
|
-
|
|
10312
|
-
|
|
10313
|
-
|
|
10314
|
-
|
|
10315
|
-
|
|
10069
|
+
}
|
|
10070
|
+
case ServerMsgCode.FEEDS_ADDED: {
|
|
10071
|
+
const feedsAddedMsg = message;
|
|
10072
|
+
eventHub.feeds.notify(feedsAddedMsg);
|
|
10073
|
+
tryResolvePendingFeedMutationsFromFeedsEvent(feedsAddedMsg);
|
|
10074
|
+
break;
|
|
10075
|
+
}
|
|
10076
|
+
case ServerMsgCode.FEEDS_UPDATED: {
|
|
10077
|
+
const feedsUpdatedMsg = message;
|
|
10078
|
+
eventHub.feeds.notify(feedsUpdatedMsg);
|
|
10079
|
+
tryResolvePendingFeedMutationsFromFeedsEvent(feedsUpdatedMsg);
|
|
10080
|
+
break;
|
|
10081
|
+
}
|
|
10082
|
+
case ServerMsgCode.FEED_DELETED: {
|
|
10083
|
+
eventHub.feeds.notify(message);
|
|
10084
|
+
tryResolvePendingFeedMutationsFromFeedsEvent(message);
|
|
10085
|
+
break;
|
|
10086
|
+
}
|
|
10087
|
+
case ServerMsgCode.FEED_MESSAGES_LIST: {
|
|
10088
|
+
const feedMsgsListMsg = message;
|
|
10089
|
+
const pending = pendingFeedMessagesRequests.get(
|
|
10090
|
+
feedMsgsListMsg.requestId
|
|
10091
|
+
);
|
|
10092
|
+
if (pending) {
|
|
10093
|
+
pending.resolve({
|
|
10094
|
+
messages: feedMsgsListMsg.messages,
|
|
10095
|
+
nextCursor: feedMsgsListMsg.nextCursor
|
|
10096
|
+
});
|
|
10097
|
+
pendingFeedMessagesRequests.delete(feedMsgsListMsg.requestId);
|
|
10098
|
+
}
|
|
10099
|
+
eventHub.feeds.notify(feedMsgsListMsg);
|
|
10100
|
+
break;
|
|
10101
|
+
}
|
|
10102
|
+
case ServerMsgCode.FEED_MESSAGES_ADDED: {
|
|
10103
|
+
const feedMsgsAddedMsg = message;
|
|
10104
|
+
eventHub.feeds.notify(feedMsgsAddedMsg);
|
|
10105
|
+
tryResolvePendingFeedMutationsFromFeedsEvent(feedMsgsAddedMsg);
|
|
10106
|
+
break;
|
|
10107
|
+
}
|
|
10108
|
+
case ServerMsgCode.FEED_MESSAGES_UPDATED: {
|
|
10109
|
+
const feedMsgsUpdatedMsg = message;
|
|
10110
|
+
eventHub.feeds.notify(feedMsgsUpdatedMsg);
|
|
10111
|
+
tryResolvePendingFeedMutationsFromFeedsEvent(feedMsgsUpdatedMsg);
|
|
10112
|
+
break;
|
|
10113
|
+
}
|
|
10114
|
+
case ServerMsgCode.FEED_MESSAGES_DELETED: {
|
|
10115
|
+
eventHub.feeds.notify(message);
|
|
10116
|
+
tryResolvePendingFeedMutationsFromFeedsEvent(message);
|
|
10117
|
+
break;
|
|
10118
|
+
}
|
|
10119
|
+
case ServerMsgCode.FEED_REQUEST_FAILED: {
|
|
10120
|
+
if (!isFeedRequestFailedMsg(message)) {
|
|
10121
|
+
break;
|
|
10122
|
+
}
|
|
10123
|
+
const { requestId, code, reason } = message;
|
|
10124
|
+
const err = new LiveblocksError(reason ?? "Feed request failed", {
|
|
10125
|
+
type: "FEED_REQUEST_ERROR",
|
|
10126
|
+
roomId,
|
|
10127
|
+
requestId,
|
|
10128
|
+
code,
|
|
10129
|
+
reason
|
|
10130
|
+
});
|
|
10131
|
+
if (pendingFeedMutations.has(requestId)) {
|
|
10132
|
+
settleFeedMutation(requestId, "error", err);
|
|
10133
|
+
} else if (pendingFeedsRequests.has(requestId)) {
|
|
10134
|
+
const pending = pendingFeedsRequests.get(requestId);
|
|
10135
|
+
pendingFeedsRequests.delete(requestId);
|
|
10136
|
+
pending?.reject(err);
|
|
10137
|
+
} else if (pendingFeedMessagesRequests.has(requestId)) {
|
|
10138
|
+
const pending = pendingFeedMessagesRequests.get(requestId);
|
|
10139
|
+
pendingFeedMessagesRequests.delete(requestId);
|
|
10140
|
+
pending?.reject(err);
|
|
10141
|
+
}
|
|
10142
|
+
eventHub.feeds.notify(message);
|
|
10143
|
+
break;
|
|
10144
|
+
}
|
|
10145
|
+
case ServerMsgCode.STORAGE_STATE_V7:
|
|
10146
|
+
// No longer used in V8
|
|
10147
|
+
default:
|
|
10148
|
+
break;
|
|
10149
|
+
}
|
|
10150
|
+
}
|
|
10151
|
+
notify(updates);
|
|
10152
|
+
}
|
|
10153
|
+
function flushNowOrSoon() {
|
|
10154
|
+
const storageOps = context.buffer.storageOperations;
|
|
10155
|
+
if (storageOps.length > 0) {
|
|
10156
|
+
for (const op of storageOps) {
|
|
10157
|
+
context.unacknowledgedOps.set(op.opId, op);
|
|
10158
|
+
}
|
|
10159
|
+
notifyStorageStatus();
|
|
10160
|
+
}
|
|
10161
|
+
if (managedSocket.getStatus() !== "connected") {
|
|
10316
10162
|
context.buffer.storageOperations = [];
|
|
10317
10163
|
return;
|
|
10318
10164
|
}
|
|
@@ -10399,6 +10245,141 @@ function createRoom(options, config) {
|
|
|
10399
10245
|
}
|
|
10400
10246
|
let _getStorage$ = null;
|
|
10401
10247
|
let _resolveStoragePromise = null;
|
|
10248
|
+
const pendingFeedsRequests = /* @__PURE__ */ new Map();
|
|
10249
|
+
const pendingFeedMessagesRequests = /* @__PURE__ */ new Map();
|
|
10250
|
+
const pendingFeedMutations = /* @__PURE__ */ new Map();
|
|
10251
|
+
const pendingAddMessageFifoByFeed = /* @__PURE__ */ new Map();
|
|
10252
|
+
function settleFeedMutation(requestId, outcome, error3) {
|
|
10253
|
+
const pending = pendingFeedMutations.get(requestId);
|
|
10254
|
+
if (pending === void 0) {
|
|
10255
|
+
return;
|
|
10256
|
+
}
|
|
10257
|
+
clearTimeout(pending.timeoutId);
|
|
10258
|
+
pendingFeedMutations.delete(requestId);
|
|
10259
|
+
if (pending.kind === "add-message" && !pending.expectedClientMessageId) {
|
|
10260
|
+
const q = pendingAddMessageFifoByFeed.get(pending.feedId);
|
|
10261
|
+
if (q !== void 0) {
|
|
10262
|
+
const idx = q.indexOf(requestId);
|
|
10263
|
+
if (idx >= 0) {
|
|
10264
|
+
q.splice(idx, 1);
|
|
10265
|
+
}
|
|
10266
|
+
if (q.length === 0) {
|
|
10267
|
+
pendingAddMessageFifoByFeed.delete(pending.feedId);
|
|
10268
|
+
}
|
|
10269
|
+
}
|
|
10270
|
+
}
|
|
10271
|
+
if (outcome === "ok") {
|
|
10272
|
+
pending.resolve();
|
|
10273
|
+
} else {
|
|
10274
|
+
pending.reject(error3 ?? new Error("Feed mutation failed"));
|
|
10275
|
+
}
|
|
10276
|
+
}
|
|
10277
|
+
function registerFeedMutation(requestId, kind, feedId, options2) {
|
|
10278
|
+
const { promise, resolve, reject } = Promise_withResolvers();
|
|
10279
|
+
const timeoutId = setTimeout(() => {
|
|
10280
|
+
if (pendingFeedMutations.has(requestId)) {
|
|
10281
|
+
settleFeedMutation(
|
|
10282
|
+
requestId,
|
|
10283
|
+
"error",
|
|
10284
|
+
new Error("Feed mutation timeout")
|
|
10285
|
+
);
|
|
10286
|
+
}
|
|
10287
|
+
}, FEEDS_TIMEOUT);
|
|
10288
|
+
pendingFeedMutations.set(requestId, {
|
|
10289
|
+
resolve,
|
|
10290
|
+
reject,
|
|
10291
|
+
timeoutId,
|
|
10292
|
+
kind,
|
|
10293
|
+
feedId,
|
|
10294
|
+
messageId: options2?.messageId,
|
|
10295
|
+
expectedClientMessageId: options2?.expectedClientMessageId
|
|
10296
|
+
});
|
|
10297
|
+
if (kind === "add-message" && options2?.expectedClientMessageId === void 0) {
|
|
10298
|
+
const q = pendingAddMessageFifoByFeed.get(feedId) ?? [];
|
|
10299
|
+
q.push(requestId);
|
|
10300
|
+
pendingAddMessageFifoByFeed.set(feedId, q);
|
|
10301
|
+
}
|
|
10302
|
+
return promise;
|
|
10303
|
+
}
|
|
10304
|
+
function tryResolvePendingFeedMutationsFromFeedsEvent(message) {
|
|
10305
|
+
switch (message.type) {
|
|
10306
|
+
case ServerMsgCode.FEEDS_ADDED: {
|
|
10307
|
+
for (const feed of message.feeds) {
|
|
10308
|
+
for (const [requestId, pending] of [...pendingFeedMutations]) {
|
|
10309
|
+
if (pending.kind === "add-feed" && pending.feedId === feed.feedId) {
|
|
10310
|
+
settleFeedMutation(requestId, "ok");
|
|
10311
|
+
break;
|
|
10312
|
+
}
|
|
10313
|
+
}
|
|
10314
|
+
}
|
|
10315
|
+
break;
|
|
10316
|
+
}
|
|
10317
|
+
case ServerMsgCode.FEEDS_UPDATED: {
|
|
10318
|
+
for (const feed of message.feeds) {
|
|
10319
|
+
for (const [requestId, pending] of [...pendingFeedMutations]) {
|
|
10320
|
+
if (pending.kind === "update-feed" && pending.feedId === feed.feedId) {
|
|
10321
|
+
settleFeedMutation(requestId, "ok");
|
|
10322
|
+
}
|
|
10323
|
+
}
|
|
10324
|
+
}
|
|
10325
|
+
break;
|
|
10326
|
+
}
|
|
10327
|
+
case ServerMsgCode.FEED_DELETED: {
|
|
10328
|
+
for (const [requestId, pending] of [...pendingFeedMutations]) {
|
|
10329
|
+
if (pending.kind === "delete-feed" && pending.feedId === message.feedId) {
|
|
10330
|
+
settleFeedMutation(requestId, "ok");
|
|
10331
|
+
break;
|
|
10332
|
+
}
|
|
10333
|
+
}
|
|
10334
|
+
break;
|
|
10335
|
+
}
|
|
10336
|
+
case ServerMsgCode.FEED_MESSAGES_ADDED: {
|
|
10337
|
+
for (const m of message.messages) {
|
|
10338
|
+
let matched = false;
|
|
10339
|
+
for (const [requestId, pending] of [...pendingFeedMutations]) {
|
|
10340
|
+
if (pending.kind === "add-message" && pending.feedId === message.feedId && pending.expectedClientMessageId === m.id) {
|
|
10341
|
+
settleFeedMutation(requestId, "ok");
|
|
10342
|
+
matched = true;
|
|
10343
|
+
break;
|
|
10344
|
+
}
|
|
10345
|
+
}
|
|
10346
|
+
if (!matched) {
|
|
10347
|
+
const q = pendingAddMessageFifoByFeed.get(message.feedId);
|
|
10348
|
+
const headId = q?.[0];
|
|
10349
|
+
if (headId !== void 0) {
|
|
10350
|
+
const pending = pendingFeedMutations.get(headId);
|
|
10351
|
+
if (pending?.kind === "add-message" && pending.expectedClientMessageId === void 0) {
|
|
10352
|
+
settleFeedMutation(headId, "ok");
|
|
10353
|
+
}
|
|
10354
|
+
}
|
|
10355
|
+
}
|
|
10356
|
+
}
|
|
10357
|
+
break;
|
|
10358
|
+
}
|
|
10359
|
+
case ServerMsgCode.FEED_MESSAGES_UPDATED: {
|
|
10360
|
+
for (const m of message.messages) {
|
|
10361
|
+
for (const [requestId, pending] of [...pendingFeedMutations]) {
|
|
10362
|
+
if (pending.kind === "update-message" && pending.feedId === message.feedId && pending.messageId === m.id) {
|
|
10363
|
+
settleFeedMutation(requestId, "ok");
|
|
10364
|
+
}
|
|
10365
|
+
}
|
|
10366
|
+
}
|
|
10367
|
+
break;
|
|
10368
|
+
}
|
|
10369
|
+
case ServerMsgCode.FEED_MESSAGES_DELETED: {
|
|
10370
|
+
for (const mid of message.messageIds) {
|
|
10371
|
+
for (const [requestId, pending] of [...pendingFeedMutations]) {
|
|
10372
|
+
if (pending.kind === "delete-message" && pending.feedId === message.feedId && pending.messageId === mid) {
|
|
10373
|
+
settleFeedMutation(requestId, "ok");
|
|
10374
|
+
}
|
|
10375
|
+
}
|
|
10376
|
+
}
|
|
10377
|
+
break;
|
|
10378
|
+
}
|
|
10379
|
+
default:
|
|
10380
|
+
break;
|
|
10381
|
+
}
|
|
10382
|
+
}
|
|
10402
10383
|
function processInitialStorage(nodes) {
|
|
10403
10384
|
const unacknowledgedOps = new Map(context.unacknowledgedOps);
|
|
10404
10385
|
createOrUpdateRootFromMessage(nodes);
|
|
@@ -10470,6 +10451,138 @@ function createRoom(options, config) {
|
|
|
10470
10451
|
}
|
|
10471
10452
|
flushNowOrSoon();
|
|
10472
10453
|
}
|
|
10454
|
+
async function fetchFeeds(options2) {
|
|
10455
|
+
const requestId = nanoid();
|
|
10456
|
+
const { promise, resolve, reject } = Promise_withResolvers();
|
|
10457
|
+
pendingFeedsRequests.set(requestId, { resolve, reject });
|
|
10458
|
+
const message = {
|
|
10459
|
+
type: ClientMsgCode.FETCH_FEEDS,
|
|
10460
|
+
requestId,
|
|
10461
|
+
cursor: options2?.cursor,
|
|
10462
|
+
since: options2?.since,
|
|
10463
|
+
limit: options2?.limit,
|
|
10464
|
+
metadata: options2?.metadata
|
|
10465
|
+
};
|
|
10466
|
+
context.buffer.messages.push(message);
|
|
10467
|
+
flushNowOrSoon();
|
|
10468
|
+
setTimeout(() => {
|
|
10469
|
+
if (pendingFeedsRequests.has(requestId)) {
|
|
10470
|
+
pendingFeedsRequests.delete(requestId);
|
|
10471
|
+
reject(new Error("Feeds fetch timeout"));
|
|
10472
|
+
}
|
|
10473
|
+
}, FEEDS_TIMEOUT);
|
|
10474
|
+
return promise;
|
|
10475
|
+
}
|
|
10476
|
+
async function fetchFeedMessages(feedId, options2) {
|
|
10477
|
+
const requestId = nanoid();
|
|
10478
|
+
const { promise, resolve, reject } = Promise_withResolvers();
|
|
10479
|
+
pendingFeedMessagesRequests.set(requestId, { resolve, reject });
|
|
10480
|
+
const message = {
|
|
10481
|
+
type: ClientMsgCode.FETCH_FEED_MESSAGES,
|
|
10482
|
+
requestId,
|
|
10483
|
+
feedId,
|
|
10484
|
+
cursor: options2?.cursor,
|
|
10485
|
+
since: options2?.since,
|
|
10486
|
+
limit: options2?.limit
|
|
10487
|
+
};
|
|
10488
|
+
context.buffer.messages.push(message);
|
|
10489
|
+
flushNowOrSoon();
|
|
10490
|
+
setTimeout(() => {
|
|
10491
|
+
if (pendingFeedMessagesRequests.has(requestId)) {
|
|
10492
|
+
pendingFeedMessagesRequests.delete(requestId);
|
|
10493
|
+
reject(new Error("Feed messages fetch timeout"));
|
|
10494
|
+
}
|
|
10495
|
+
}, FEEDS_TIMEOUT);
|
|
10496
|
+
return promise;
|
|
10497
|
+
}
|
|
10498
|
+
function addFeed(feedId, options2) {
|
|
10499
|
+
const requestId = nanoid();
|
|
10500
|
+
const promise = registerFeedMutation(requestId, "add-feed", feedId);
|
|
10501
|
+
const message = {
|
|
10502
|
+
type: ClientMsgCode.ADD_FEED,
|
|
10503
|
+
requestId,
|
|
10504
|
+
feedId,
|
|
10505
|
+
metadata: options2?.metadata,
|
|
10506
|
+
createdAt: options2?.createdAt
|
|
10507
|
+
};
|
|
10508
|
+
context.buffer.messages.push(message);
|
|
10509
|
+
flushNowOrSoon();
|
|
10510
|
+
return promise;
|
|
10511
|
+
}
|
|
10512
|
+
function updateFeed(feedId, metadata) {
|
|
10513
|
+
const requestId = nanoid();
|
|
10514
|
+
const promise = registerFeedMutation(requestId, "update-feed", feedId);
|
|
10515
|
+
const message = {
|
|
10516
|
+
type: ClientMsgCode.UPDATE_FEED,
|
|
10517
|
+
requestId,
|
|
10518
|
+
feedId,
|
|
10519
|
+
metadata
|
|
10520
|
+
};
|
|
10521
|
+
context.buffer.messages.push(message);
|
|
10522
|
+
flushNowOrSoon();
|
|
10523
|
+
return promise;
|
|
10524
|
+
}
|
|
10525
|
+
function deleteFeed(feedId) {
|
|
10526
|
+
const requestId = nanoid();
|
|
10527
|
+
const promise = registerFeedMutation(requestId, "delete-feed", feedId);
|
|
10528
|
+
const message = {
|
|
10529
|
+
type: ClientMsgCode.DELETE_FEED,
|
|
10530
|
+
requestId,
|
|
10531
|
+
feedId
|
|
10532
|
+
};
|
|
10533
|
+
context.buffer.messages.push(message);
|
|
10534
|
+
flushNowOrSoon();
|
|
10535
|
+
return promise;
|
|
10536
|
+
}
|
|
10537
|
+
function addFeedMessage(feedId, data, options2) {
|
|
10538
|
+
const requestId = nanoid();
|
|
10539
|
+
const promise = registerFeedMutation(requestId, "add-message", feedId, {
|
|
10540
|
+
expectedClientMessageId: options2?.id
|
|
10541
|
+
});
|
|
10542
|
+
const message = {
|
|
10543
|
+
type: ClientMsgCode.ADD_FEED_MESSAGE,
|
|
10544
|
+
requestId,
|
|
10545
|
+
feedId,
|
|
10546
|
+
data,
|
|
10547
|
+
id: options2?.id,
|
|
10548
|
+
createdAt: options2?.createdAt
|
|
10549
|
+
};
|
|
10550
|
+
context.buffer.messages.push(message);
|
|
10551
|
+
flushNowOrSoon();
|
|
10552
|
+
return promise;
|
|
10553
|
+
}
|
|
10554
|
+
function updateFeedMessage(feedId, messageId, data, options2) {
|
|
10555
|
+
const requestId = nanoid();
|
|
10556
|
+
const promise = registerFeedMutation(requestId, "update-message", feedId, {
|
|
10557
|
+
messageId
|
|
10558
|
+
});
|
|
10559
|
+
const message = {
|
|
10560
|
+
type: ClientMsgCode.UPDATE_FEED_MESSAGE,
|
|
10561
|
+
requestId,
|
|
10562
|
+
feedId,
|
|
10563
|
+
messageId,
|
|
10564
|
+
data,
|
|
10565
|
+
updatedAt: options2?.updatedAt
|
|
10566
|
+
};
|
|
10567
|
+
context.buffer.messages.push(message);
|
|
10568
|
+
flushNowOrSoon();
|
|
10569
|
+
return promise;
|
|
10570
|
+
}
|
|
10571
|
+
function deleteFeedMessage(feedId, messageId) {
|
|
10572
|
+
const requestId = nanoid();
|
|
10573
|
+
const promise = registerFeedMutation(requestId, "delete-message", feedId, {
|
|
10574
|
+
messageId
|
|
10575
|
+
});
|
|
10576
|
+
const message = {
|
|
10577
|
+
type: ClientMsgCode.DELETE_FEED_MESSAGE,
|
|
10578
|
+
requestId,
|
|
10579
|
+
feedId,
|
|
10580
|
+
messageId
|
|
10581
|
+
};
|
|
10582
|
+
context.buffer.messages.push(message);
|
|
10583
|
+
flushNowOrSoon();
|
|
10584
|
+
return promise;
|
|
10585
|
+
}
|
|
10473
10586
|
function undo() {
|
|
10474
10587
|
if (context.activeBatch) {
|
|
10475
10588
|
throw new Error("undo is not allowed during a batch");
|
|
@@ -10522,7 +10635,8 @@ function createRoom(options, config) {
|
|
|
10522
10635
|
presence: false,
|
|
10523
10636
|
others: []
|
|
10524
10637
|
},
|
|
10525
|
-
reverseOps: new Deque()
|
|
10638
|
+
reverseOps: new Deque(),
|
|
10639
|
+
scheduleHistoryResume: false
|
|
10526
10640
|
};
|
|
10527
10641
|
try {
|
|
10528
10642
|
returnValue = callback();
|
|
@@ -10532,6 +10646,9 @@ function createRoom(options, config) {
|
|
|
10532
10646
|
if (currentBatch.reverseOps.length > 0) {
|
|
10533
10647
|
addToUndoStack(Array.from(currentBatch.reverseOps));
|
|
10534
10648
|
}
|
|
10649
|
+
if (currentBatch.scheduleHistoryResume) {
|
|
10650
|
+
commitPausedHistoryToUndoStack();
|
|
10651
|
+
}
|
|
10535
10652
|
if (currentBatch.ops.length > 0) {
|
|
10536
10653
|
context.redoStack.length = 0;
|
|
10537
10654
|
}
|
|
@@ -10548,13 +10665,20 @@ function createRoom(options, config) {
|
|
|
10548
10665
|
context.pausedHistory = new Deque();
|
|
10549
10666
|
}
|
|
10550
10667
|
}
|
|
10551
|
-
function
|
|
10668
|
+
function commitPausedHistoryToUndoStack() {
|
|
10552
10669
|
const frames = context.pausedHistory;
|
|
10553
10670
|
context.pausedHistory = null;
|
|
10554
10671
|
if (frames !== null && frames.length > 0) {
|
|
10555
10672
|
_addToRealUndoStack(Array.from(frames));
|
|
10556
10673
|
}
|
|
10557
10674
|
}
|
|
10675
|
+
function resumeHistory() {
|
|
10676
|
+
if (context.activeBatch !== null) {
|
|
10677
|
+
context.activeBatch.scheduleHistoryResume = true;
|
|
10678
|
+
return;
|
|
10679
|
+
}
|
|
10680
|
+
commitPausedHistoryToUndoStack();
|
|
10681
|
+
}
|
|
10558
10682
|
function withoutHistory(fn) {
|
|
10559
10683
|
const undoBefore = context.undoStack.length;
|
|
10560
10684
|
const redoBefore = context.redoStack.length;
|
|
@@ -10622,6 +10746,7 @@ function createRoom(options, config) {
|
|
|
10622
10746
|
storageStatus: eventHub.storageStatus.observable,
|
|
10623
10747
|
ydoc: eventHub.ydoc.observable,
|
|
10624
10748
|
comments: eventHub.comments.observable,
|
|
10749
|
+
feeds: eventHub.feeds.observable,
|
|
10625
10750
|
roomWillDestroy: eventHub.roomWillDestroy.observable
|
|
10626
10751
|
};
|
|
10627
10752
|
async function getThreadsSince(options2) {
|
|
@@ -10831,13 +10956,19 @@ function createRoom(options, config) {
|
|
|
10831
10956
|
id: roomId,
|
|
10832
10957
|
subscribe: makeClassicSubscribeFn(
|
|
10833
10958
|
roomId,
|
|
10834
|
-
|
|
10959
|
+
eventHub,
|
|
10835
10960
|
config.errorEventSource
|
|
10836
10961
|
),
|
|
10837
10962
|
connect: () => managedSocket.connect(),
|
|
10838
10963
|
reconnect: () => managedSocket.reconnect(),
|
|
10839
10964
|
disconnect: () => managedSocket.disconnect(),
|
|
10840
10965
|
destroy: () => {
|
|
10966
|
+
pendingFeedsRequests.forEach(
|
|
10967
|
+
(request) => request.reject(new Error("Room destroyed"))
|
|
10968
|
+
);
|
|
10969
|
+
pendingFeedMessagesRequests.forEach(
|
|
10970
|
+
(request) => request.reject(new Error("Room destroyed"))
|
|
10971
|
+
);
|
|
10841
10972
|
const { roomWillDestroy, ...eventsExceptDestroy } = eventHub;
|
|
10842
10973
|
for (const source of Object.values(eventsExceptDestroy)) {
|
|
10843
10974
|
source.dispose();
|
|
@@ -10869,6 +11000,14 @@ function createRoom(options, config) {
|
|
|
10869
11000
|
}
|
|
10870
11001
|
},
|
|
10871
11002
|
fetchYDoc,
|
|
11003
|
+
fetchFeeds,
|
|
11004
|
+
fetchFeedMessages,
|
|
11005
|
+
addFeed,
|
|
11006
|
+
updateFeed,
|
|
11007
|
+
deleteFeed,
|
|
11008
|
+
addFeedMessage,
|
|
11009
|
+
updateFeedMessage,
|
|
11010
|
+
deleteFeedMessage,
|
|
10872
11011
|
getStorage,
|
|
10873
11012
|
getStorageSnapshot,
|
|
10874
11013
|
getStorageStatus,
|
|
@@ -11776,6 +11915,292 @@ function toPlainLson(lson) {
|
|
|
11776
11915
|
}
|
|
11777
11916
|
}
|
|
11778
11917
|
|
|
11918
|
+
// src/immutable.ts
|
|
11919
|
+
function lsonObjectToJson(obj) {
|
|
11920
|
+
const result = {};
|
|
11921
|
+
for (const key in obj) {
|
|
11922
|
+
const val = obj[key];
|
|
11923
|
+
if (val !== void 0) {
|
|
11924
|
+
result[key] = lsonToJson(val);
|
|
11925
|
+
}
|
|
11926
|
+
}
|
|
11927
|
+
return result;
|
|
11928
|
+
}
|
|
11929
|
+
function liveObjectToJson(liveObject) {
|
|
11930
|
+
return lsonObjectToJson(liveObject.toObject());
|
|
11931
|
+
}
|
|
11932
|
+
function liveMapToJson(map) {
|
|
11933
|
+
const result = {};
|
|
11934
|
+
for (const [key, value] of map.entries()) {
|
|
11935
|
+
result[key] = lsonToJson(value);
|
|
11936
|
+
}
|
|
11937
|
+
return result;
|
|
11938
|
+
}
|
|
11939
|
+
function lsonListToJson(value) {
|
|
11940
|
+
return value.map(lsonToJson);
|
|
11941
|
+
}
|
|
11942
|
+
function liveListToJson(value) {
|
|
11943
|
+
return lsonListToJson(value.toArray());
|
|
11944
|
+
}
|
|
11945
|
+
function lsonToJson(value) {
|
|
11946
|
+
if (value instanceof LiveObject) {
|
|
11947
|
+
return liveObjectToJson(value);
|
|
11948
|
+
} else if (value instanceof LiveList) {
|
|
11949
|
+
return liveListToJson(value);
|
|
11950
|
+
} else if (value instanceof LiveMap) {
|
|
11951
|
+
return liveMapToJson(value);
|
|
11952
|
+
} else if (value instanceof LiveRegister) {
|
|
11953
|
+
return value.data;
|
|
11954
|
+
}
|
|
11955
|
+
if (Array.isArray(value)) {
|
|
11956
|
+
return lsonListToJson(value);
|
|
11957
|
+
} else if (isPlainObject(value)) {
|
|
11958
|
+
return lsonObjectToJson(value);
|
|
11959
|
+
}
|
|
11960
|
+
return value;
|
|
11961
|
+
}
|
|
11962
|
+
function legacy_patchLiveList(liveList, prev, next) {
|
|
11963
|
+
let i = 0;
|
|
11964
|
+
let prevEnd = prev.length - 1;
|
|
11965
|
+
let nextEnd = next.length - 1;
|
|
11966
|
+
let prevNode = prev[0];
|
|
11967
|
+
let nextNode = next[0];
|
|
11968
|
+
outer: {
|
|
11969
|
+
while (prevNode === nextNode) {
|
|
11970
|
+
++i;
|
|
11971
|
+
if (i > prevEnd || i > nextEnd) {
|
|
11972
|
+
break outer;
|
|
11973
|
+
}
|
|
11974
|
+
prevNode = prev[i];
|
|
11975
|
+
nextNode = next[i];
|
|
11976
|
+
}
|
|
11977
|
+
prevNode = prev[prevEnd];
|
|
11978
|
+
nextNode = next[nextEnd];
|
|
11979
|
+
while (prevNode === nextNode) {
|
|
11980
|
+
prevEnd--;
|
|
11981
|
+
nextEnd--;
|
|
11982
|
+
if (i > prevEnd || i > nextEnd) {
|
|
11983
|
+
break outer;
|
|
11984
|
+
}
|
|
11985
|
+
prevNode = prev[prevEnd];
|
|
11986
|
+
nextNode = next[nextEnd];
|
|
11987
|
+
}
|
|
11988
|
+
}
|
|
11989
|
+
if (i > prevEnd) {
|
|
11990
|
+
if (i <= nextEnd) {
|
|
11991
|
+
while (i <= nextEnd) {
|
|
11992
|
+
liveList.insert(deepLiveify(next[i]), i);
|
|
11993
|
+
i++;
|
|
11994
|
+
}
|
|
11995
|
+
}
|
|
11996
|
+
} else if (i > nextEnd) {
|
|
11997
|
+
let localI = i;
|
|
11998
|
+
while (localI <= prevEnd) {
|
|
11999
|
+
liveList.delete(i);
|
|
12000
|
+
localI++;
|
|
12001
|
+
}
|
|
12002
|
+
} else {
|
|
12003
|
+
while (i <= prevEnd && i <= nextEnd) {
|
|
12004
|
+
prevNode = prev[i];
|
|
12005
|
+
nextNode = next[i];
|
|
12006
|
+
const liveListNode = liveList.get(i);
|
|
12007
|
+
if (isLiveObject(liveListNode) && isPlainObject(prevNode) && isPlainObject(nextNode)) {
|
|
12008
|
+
legacy_patchLiveObject(liveListNode, prevNode, nextNode);
|
|
12009
|
+
} else {
|
|
12010
|
+
liveList.set(i, deepLiveify(nextNode));
|
|
12011
|
+
}
|
|
12012
|
+
i++;
|
|
12013
|
+
}
|
|
12014
|
+
while (i <= nextEnd) {
|
|
12015
|
+
liveList.insert(deepLiveify(next[i]), i);
|
|
12016
|
+
i++;
|
|
12017
|
+
}
|
|
12018
|
+
let localI = i;
|
|
12019
|
+
while (localI <= prevEnd) {
|
|
12020
|
+
liveList.delete(i);
|
|
12021
|
+
localI++;
|
|
12022
|
+
}
|
|
12023
|
+
}
|
|
12024
|
+
}
|
|
12025
|
+
function legacy_patchLiveObjectKey(liveObject, key, prev, next) {
|
|
12026
|
+
if (process.env.NODE_ENV !== "production") {
|
|
12027
|
+
const nonSerializableValue = findNonSerializableValue(next);
|
|
12028
|
+
if (nonSerializableValue) {
|
|
12029
|
+
error2(
|
|
12030
|
+
`New state path: '${nonSerializableValue.path}' value: '${String(
|
|
12031
|
+
nonSerializableValue.value
|
|
12032
|
+
)}' is not serializable.
|
|
12033
|
+
Only serializable value can be synced with Liveblocks.`
|
|
12034
|
+
);
|
|
12035
|
+
return;
|
|
12036
|
+
}
|
|
12037
|
+
}
|
|
12038
|
+
const value = liveObject.get(key);
|
|
12039
|
+
if (next === void 0) {
|
|
12040
|
+
liveObject.delete(key);
|
|
12041
|
+
} else if (value === void 0) {
|
|
12042
|
+
liveObject.set(key, deepLiveify(next));
|
|
12043
|
+
} else if (prev === next) {
|
|
12044
|
+
return;
|
|
12045
|
+
} else if (isLiveList(value) && Array.isArray(prev) && Array.isArray(next)) {
|
|
12046
|
+
legacy_patchLiveList(value, prev, next);
|
|
12047
|
+
} else if (isLiveObject(value) && isPlainObject(prev) && isPlainObject(next)) {
|
|
12048
|
+
legacy_patchLiveObject(value, prev, next);
|
|
12049
|
+
} else {
|
|
12050
|
+
liveObject.set(key, deepLiveify(next));
|
|
12051
|
+
}
|
|
12052
|
+
}
|
|
12053
|
+
function legacy_patchLiveObject(root, prev, next) {
|
|
12054
|
+
const updates = {};
|
|
12055
|
+
for (const key in next) {
|
|
12056
|
+
legacy_patchLiveObjectKey(root, key, prev[key], next[key]);
|
|
12057
|
+
}
|
|
12058
|
+
for (const key in prev) {
|
|
12059
|
+
if (next[key] === void 0) {
|
|
12060
|
+
root.delete(key);
|
|
12061
|
+
}
|
|
12062
|
+
}
|
|
12063
|
+
if (Object.keys(updates).length > 0) {
|
|
12064
|
+
root.update(updates);
|
|
12065
|
+
}
|
|
12066
|
+
}
|
|
12067
|
+
function getParentsPath(node) {
|
|
12068
|
+
const path = [];
|
|
12069
|
+
while (node.parent.type === "HasParent") {
|
|
12070
|
+
if (isLiveList(node.parent.node)) {
|
|
12071
|
+
path.push(node.parent.node._indexOfPosition(node.parent.key));
|
|
12072
|
+
} else {
|
|
12073
|
+
path.push(node.parent.key);
|
|
12074
|
+
}
|
|
12075
|
+
node = node.parent.node;
|
|
12076
|
+
}
|
|
12077
|
+
return path;
|
|
12078
|
+
}
|
|
12079
|
+
function legacy_patchImmutableObject(state, updates) {
|
|
12080
|
+
return updates.reduce(
|
|
12081
|
+
(state2, update) => legacy_patchImmutableObjectWithUpdate(state2, update),
|
|
12082
|
+
state
|
|
12083
|
+
);
|
|
12084
|
+
}
|
|
12085
|
+
function legacy_patchImmutableObjectWithUpdate(state, update) {
|
|
12086
|
+
const path = getParentsPath(update.node);
|
|
12087
|
+
return legacy_patchImmutableNode(state, path, update);
|
|
12088
|
+
}
|
|
12089
|
+
function legacy_patchImmutableNode(state, path, update) {
|
|
12090
|
+
const pathItem = path.pop();
|
|
12091
|
+
if (pathItem === void 0) {
|
|
12092
|
+
switch (update.type) {
|
|
12093
|
+
case "LiveObject": {
|
|
12094
|
+
if (!isJsonObject(state)) {
|
|
12095
|
+
throw new Error(
|
|
12096
|
+
"Internal: received update on LiveObject but state was not an object"
|
|
12097
|
+
);
|
|
12098
|
+
}
|
|
12099
|
+
const newState = Object.assign({}, state);
|
|
12100
|
+
for (const key in update.updates) {
|
|
12101
|
+
if (update.updates[key]?.type === "update") {
|
|
12102
|
+
const val = update.node.get(key);
|
|
12103
|
+
if (val !== void 0) {
|
|
12104
|
+
newState[key] = lsonToJson(val);
|
|
12105
|
+
}
|
|
12106
|
+
} else if (update.updates[key]?.type === "delete") {
|
|
12107
|
+
delete newState[key];
|
|
12108
|
+
}
|
|
12109
|
+
}
|
|
12110
|
+
return newState;
|
|
12111
|
+
}
|
|
12112
|
+
case "LiveList": {
|
|
12113
|
+
if (!Array.isArray(state)) {
|
|
12114
|
+
throw new Error(
|
|
12115
|
+
"Internal: received update on LiveList but state was not an array"
|
|
12116
|
+
);
|
|
12117
|
+
}
|
|
12118
|
+
let newState = state.map((x) => x);
|
|
12119
|
+
for (const listUpdate of update.updates) {
|
|
12120
|
+
if (listUpdate.type === "set") {
|
|
12121
|
+
newState = newState.map(
|
|
12122
|
+
(item, index) => index === listUpdate.index ? lsonToJson(listUpdate.item) : item
|
|
12123
|
+
);
|
|
12124
|
+
} else if (listUpdate.type === "insert") {
|
|
12125
|
+
if (listUpdate.index === newState.length) {
|
|
12126
|
+
newState.push(lsonToJson(listUpdate.item));
|
|
12127
|
+
} else {
|
|
12128
|
+
newState = [
|
|
12129
|
+
...newState.slice(0, listUpdate.index),
|
|
12130
|
+
lsonToJson(listUpdate.item),
|
|
12131
|
+
...newState.slice(listUpdate.index)
|
|
12132
|
+
];
|
|
12133
|
+
}
|
|
12134
|
+
} else if (listUpdate.type === "delete") {
|
|
12135
|
+
newState.splice(listUpdate.index, 1);
|
|
12136
|
+
} else if (listUpdate.type === "move") {
|
|
12137
|
+
if (listUpdate.previousIndex > listUpdate.index) {
|
|
12138
|
+
newState = [
|
|
12139
|
+
...newState.slice(0, listUpdate.index),
|
|
12140
|
+
lsonToJson(listUpdate.item),
|
|
12141
|
+
...newState.slice(listUpdate.index, listUpdate.previousIndex),
|
|
12142
|
+
...newState.slice(listUpdate.previousIndex + 1)
|
|
12143
|
+
];
|
|
12144
|
+
} else {
|
|
12145
|
+
newState = [
|
|
12146
|
+
...newState.slice(0, listUpdate.previousIndex),
|
|
12147
|
+
...newState.slice(
|
|
12148
|
+
listUpdate.previousIndex + 1,
|
|
12149
|
+
listUpdate.index + 1
|
|
12150
|
+
),
|
|
12151
|
+
lsonToJson(listUpdate.item),
|
|
12152
|
+
...newState.slice(listUpdate.index + 1)
|
|
12153
|
+
];
|
|
12154
|
+
}
|
|
12155
|
+
}
|
|
12156
|
+
}
|
|
12157
|
+
return newState;
|
|
12158
|
+
}
|
|
12159
|
+
case "LiveMap": {
|
|
12160
|
+
if (!isJsonObject(state)) {
|
|
12161
|
+
throw new Error(
|
|
12162
|
+
"Internal: received update on LiveMap but state was not an object"
|
|
12163
|
+
);
|
|
12164
|
+
}
|
|
12165
|
+
const newState = Object.assign({}, state);
|
|
12166
|
+
for (const key in update.updates) {
|
|
12167
|
+
if (update.updates[key]?.type === "update") {
|
|
12168
|
+
const value = update.node.get(key);
|
|
12169
|
+
if (value !== void 0) {
|
|
12170
|
+
newState[key] = lsonToJson(value);
|
|
12171
|
+
}
|
|
12172
|
+
} else if (update.updates[key]?.type === "delete") {
|
|
12173
|
+
delete newState[key];
|
|
12174
|
+
}
|
|
12175
|
+
}
|
|
12176
|
+
return newState;
|
|
12177
|
+
}
|
|
12178
|
+
}
|
|
12179
|
+
}
|
|
12180
|
+
if (Array.isArray(state)) {
|
|
12181
|
+
const newArray = [...state];
|
|
12182
|
+
newArray[pathItem] = legacy_patchImmutableNode(
|
|
12183
|
+
state[pathItem],
|
|
12184
|
+
path,
|
|
12185
|
+
update
|
|
12186
|
+
);
|
|
12187
|
+
return newArray;
|
|
12188
|
+
} else if (isJsonObject(state)) {
|
|
12189
|
+
const node = state[pathItem];
|
|
12190
|
+
if (node === void 0) {
|
|
12191
|
+
return state;
|
|
12192
|
+
} else {
|
|
12193
|
+
const stateAsObj = state;
|
|
12194
|
+
return {
|
|
12195
|
+
...stateAsObj,
|
|
12196
|
+
[pathItem]: legacy_patchImmutableNode(node, path, update)
|
|
12197
|
+
};
|
|
12198
|
+
}
|
|
12199
|
+
} else {
|
|
12200
|
+
return state;
|
|
12201
|
+
}
|
|
12202
|
+
}
|
|
12203
|
+
|
|
11779
12204
|
// src/lib/abortController.ts
|
|
11780
12205
|
function makeAbortController(externalSignal) {
|
|
11781
12206
|
const ctl = new AbortController();
|
|
@@ -11947,6 +12372,7 @@ export {
|
|
|
11947
12372
|
DefaultMap,
|
|
11948
12373
|
Deque,
|
|
11949
12374
|
DerivedSignal,
|
|
12375
|
+
FeedRequestErrorCode,
|
|
11950
12376
|
HttpError,
|
|
11951
12377
|
LiveList,
|
|
11952
12378
|
LiveMap,
|