@liveblocks/server 1.1.1-pnpmtest1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +723 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +450 -51
- package/dist/index.d.ts +450 -51
- package/dist/index.js +714 -70
- package/dist/index.js.map +1 -1
- package/package.json +8 -9
package/dist/index.js
CHANGED
|
@@ -12,16 +12,139 @@ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "
|
|
|
12
12
|
// src/decoders/ClientMsg.ts
|
|
13
13
|
import { ClientMsgCode } from "@liveblocks/core";
|
|
14
14
|
import {
|
|
15
|
-
array,
|
|
15
|
+
array as array2,
|
|
16
16
|
boolean,
|
|
17
17
|
constant as constant2,
|
|
18
|
+
jsonObject,
|
|
19
|
+
nonEmptyString,
|
|
18
20
|
number,
|
|
19
21
|
object as object2,
|
|
20
|
-
optional as
|
|
21
|
-
string as
|
|
22
|
+
optional as optional3,
|
|
23
|
+
string as string3,
|
|
22
24
|
taggedUnion as taggedUnion2
|
|
23
25
|
} from "decoders";
|
|
24
26
|
|
|
27
|
+
// src/protocol/feedMessages.ts
|
|
28
|
+
var FeedMsgCode = {
|
|
29
|
+
// Server → client (50x)
|
|
30
|
+
FEEDS_LIST: 500,
|
|
31
|
+
FEEDS_ADDED: 501,
|
|
32
|
+
FEEDS_UPDATED: 502,
|
|
33
|
+
FEED_DELETED: 503,
|
|
34
|
+
FEED_MESSAGES_LIST: 504,
|
|
35
|
+
FEED_MESSAGES_ADDED: 505,
|
|
36
|
+
FEED_MESSAGES_UPDATED: 506,
|
|
37
|
+
FEED_MESSAGES_DELETED: 507,
|
|
38
|
+
FEED_REQUEST_FAILED: 508,
|
|
39
|
+
// Client → server (51x)
|
|
40
|
+
FETCH_FEEDS: 510,
|
|
41
|
+
FETCH_FEED_MESSAGES: 511,
|
|
42
|
+
ADD_FEED: 512,
|
|
43
|
+
UPDATE_FEED: 513,
|
|
44
|
+
DELETE_FEED: 514,
|
|
45
|
+
ADD_FEED_MESSAGE: 515,
|
|
46
|
+
UPDATE_FEED_MESSAGE: 516,
|
|
47
|
+
DELETE_FEED_MESSAGE: 517
|
|
48
|
+
};
|
|
49
|
+
var FeedRequestErrorCode = {
|
|
50
|
+
INTERNAL: "INTERNAL",
|
|
51
|
+
FEED_ALREADY_EXISTS: "FEED_ALREADY_EXISTS",
|
|
52
|
+
FEED_NOT_FOUND: "FEED_NOT_FOUND",
|
|
53
|
+
FEED_MESSAGE_NOT_FOUND: "FEED_MESSAGE_NOT_FOUND"
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// src/protocol/feedErrors.ts
|
|
57
|
+
function feedRequestFailed(requestId, code, reason) {
|
|
58
|
+
return {
|
|
59
|
+
type: FeedMsgCode.FEED_REQUEST_FAILED,
|
|
60
|
+
requestId: requestId ?? "",
|
|
61
|
+
code,
|
|
62
|
+
reason
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function mapFeedError(err) {
|
|
66
|
+
if (!(err instanceof Error)) {
|
|
67
|
+
return { code: FeedRequestErrorCode.INTERNAL };
|
|
68
|
+
}
|
|
69
|
+
const m = err.message;
|
|
70
|
+
if (m.includes("already exists")) {
|
|
71
|
+
return { code: FeedRequestErrorCode.FEED_ALREADY_EXISTS, reason: m };
|
|
72
|
+
}
|
|
73
|
+
if (m.includes("Feed message") && m.includes("not found")) {
|
|
74
|
+
return { code: FeedRequestErrorCode.FEED_MESSAGE_NOT_FOUND, reason: m };
|
|
75
|
+
}
|
|
76
|
+
if (m.includes("not found")) {
|
|
77
|
+
return { code: FeedRequestErrorCode.FEED_NOT_FOUND, reason: m };
|
|
78
|
+
}
|
|
79
|
+
return { code: FeedRequestErrorCode.INTERNAL, reason: m };
|
|
80
|
+
}
|
|
81
|
+
function feedFailureServerMsg(requestId, err) {
|
|
82
|
+
const mapped = mapFeedError(err);
|
|
83
|
+
return feedRequestFailed(requestId, mapped.code, mapped.reason);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/protocol/ProtocolVersion.ts
|
|
87
|
+
import { enum_ } from "decoders";
|
|
88
|
+
var ProtocolVersion = /* @__PURE__ */ ((ProtocolVersion2) => {
|
|
89
|
+
ProtocolVersion2[ProtocolVersion2["V7"] = 7] = "V7";
|
|
90
|
+
ProtocolVersion2[ProtocolVersion2["V8"] = 8] = "V8";
|
|
91
|
+
return ProtocolVersion2;
|
|
92
|
+
})(ProtocolVersion || {});
|
|
93
|
+
var protocolVersionDecoder = enum_(ProtocolVersion).describe(
|
|
94
|
+
"Unsupported protocol version"
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// src/decoders/feedMetadata.ts
|
|
98
|
+
import {
|
|
99
|
+
array,
|
|
100
|
+
either,
|
|
101
|
+
identifier,
|
|
102
|
+
nullable,
|
|
103
|
+
optional,
|
|
104
|
+
poja,
|
|
105
|
+
record,
|
|
106
|
+
select,
|
|
107
|
+
sized,
|
|
108
|
+
string
|
|
109
|
+
} from "decoders";
|
|
110
|
+
var MAX_METADATA_COUNT = 50;
|
|
111
|
+
var MAX_METADATA_VALUE_LIST_LENGTH = 50;
|
|
112
|
+
var feedMetadataIdDecoder = sized(identifier, { min: 1, max: 40 });
|
|
113
|
+
var metadataStringValue = sized(string, { max: 256 });
|
|
114
|
+
function createRoomMetadataValueDecoder() {
|
|
115
|
+
return select(
|
|
116
|
+
either(string, poja).describe("Must be string or string[]"),
|
|
117
|
+
(x) => typeof x === "string" ? metadataStringValue : array(metadataStringValue).refine(
|
|
118
|
+
(value) => value.length <= MAX_METADATA_VALUE_LIST_LENGTH,
|
|
119
|
+
`Must be at most ${MAX_METADATA_VALUE_LIST_LENGTH} items`
|
|
120
|
+
)
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
var roomMetadataValueDecoder = createRoomMetadataValueDecoder();
|
|
124
|
+
var feedMetadataNullableValueDecoder = nullable(roomMetadataValueDecoder);
|
|
125
|
+
var feedMetadataRecordForCreate = record(
|
|
126
|
+
feedMetadataIdDecoder,
|
|
127
|
+
roomMetadataValueDecoder
|
|
128
|
+
).refine(
|
|
129
|
+
(value) => Object.keys(value).length <= MAX_METADATA_COUNT,
|
|
130
|
+
`Must be at most ${MAX_METADATA_COUNT} items`
|
|
131
|
+
);
|
|
132
|
+
var optionalFeedMetadataDecoder = optional(feedMetadataRecordForCreate);
|
|
133
|
+
var feedMetadataUpdateDecoder = record(
|
|
134
|
+
feedMetadataIdDecoder,
|
|
135
|
+
feedMetadataNullableValueDecoder
|
|
136
|
+
);
|
|
137
|
+
var feedMetadataRecordForFilter = record(
|
|
138
|
+
feedMetadataIdDecoder,
|
|
139
|
+
feedMetadataNullableValueDecoder
|
|
140
|
+
).refine(
|
|
141
|
+
(value) => Object.keys(value).length <= MAX_METADATA_COUNT,
|
|
142
|
+
`Must be at most ${MAX_METADATA_COUNT} items`
|
|
143
|
+
);
|
|
144
|
+
var fetchFeedsMetadataFilterDecoder = optional(
|
|
145
|
+
feedMetadataRecordForFilter
|
|
146
|
+
);
|
|
147
|
+
|
|
25
148
|
// src/decoders/jsonYolo.ts
|
|
26
149
|
import { unknown } from "decoders";
|
|
27
150
|
var jsonYolo = unknown;
|
|
@@ -32,67 +155,67 @@ var jsonObjectYolo = jsonYolo.refine(
|
|
|
32
155
|
|
|
33
156
|
// src/decoders/Op.ts
|
|
34
157
|
import { OpCode } from "@liveblocks/core";
|
|
35
|
-
import { constant, object, optional, string, taggedUnion } from "decoders";
|
|
158
|
+
import { constant, object, optional as optional2, string as string2, taggedUnion } from "decoders";
|
|
36
159
|
var updateObjectOp = object({
|
|
37
160
|
type: constant(OpCode.UPDATE_OBJECT),
|
|
38
|
-
opId:
|
|
39
|
-
id:
|
|
161
|
+
opId: string2,
|
|
162
|
+
id: string2,
|
|
40
163
|
data: jsonObjectYolo
|
|
41
164
|
});
|
|
42
165
|
var createObjectOp = object({
|
|
43
166
|
type: constant(OpCode.CREATE_OBJECT),
|
|
44
|
-
opId:
|
|
45
|
-
id:
|
|
46
|
-
parentId:
|
|
47
|
-
parentKey:
|
|
167
|
+
opId: string2,
|
|
168
|
+
id: string2,
|
|
169
|
+
parentId: string2,
|
|
170
|
+
parentKey: string2,
|
|
48
171
|
data: jsonObjectYolo,
|
|
49
|
-
intent:
|
|
50
|
-
deletedId:
|
|
172
|
+
intent: optional2(constant("set")),
|
|
173
|
+
deletedId: optional2(string2)
|
|
51
174
|
});
|
|
52
175
|
var createListOp = object({
|
|
53
176
|
type: constant(OpCode.CREATE_LIST),
|
|
54
|
-
opId:
|
|
55
|
-
id:
|
|
56
|
-
parentId:
|
|
57
|
-
parentKey:
|
|
58
|
-
intent:
|
|
59
|
-
deletedId:
|
|
177
|
+
opId: string2,
|
|
178
|
+
id: string2,
|
|
179
|
+
parentId: string2,
|
|
180
|
+
parentKey: string2,
|
|
181
|
+
intent: optional2(constant("set")),
|
|
182
|
+
deletedId: optional2(string2)
|
|
60
183
|
});
|
|
61
184
|
var createMapOp = object({
|
|
62
185
|
type: constant(OpCode.CREATE_MAP),
|
|
63
|
-
opId:
|
|
64
|
-
id:
|
|
65
|
-
parentId:
|
|
66
|
-
parentKey:
|
|
67
|
-
intent:
|
|
68
|
-
deletedId:
|
|
186
|
+
opId: string2,
|
|
187
|
+
id: string2,
|
|
188
|
+
parentId: string2,
|
|
189
|
+
parentKey: string2,
|
|
190
|
+
intent: optional2(constant("set")),
|
|
191
|
+
deletedId: optional2(string2)
|
|
69
192
|
});
|
|
70
193
|
var createRegisterOp = object({
|
|
71
194
|
type: constant(OpCode.CREATE_REGISTER),
|
|
72
|
-
opId:
|
|
73
|
-
id:
|
|
74
|
-
parentId:
|
|
75
|
-
parentKey:
|
|
195
|
+
opId: string2,
|
|
196
|
+
id: string2,
|
|
197
|
+
parentId: string2,
|
|
198
|
+
parentKey: string2,
|
|
76
199
|
data: jsonYolo,
|
|
77
|
-
intent:
|
|
78
|
-
deletedId:
|
|
200
|
+
intent: optional2(constant("set")),
|
|
201
|
+
deletedId: optional2(string2)
|
|
79
202
|
});
|
|
80
203
|
var deleteCrdtOp = object({
|
|
81
204
|
type: constant(OpCode.DELETE_CRDT),
|
|
82
|
-
opId:
|
|
83
|
-
id:
|
|
205
|
+
opId: string2,
|
|
206
|
+
id: string2
|
|
84
207
|
});
|
|
85
208
|
var setParentKeyOp = object({
|
|
86
209
|
type: constant(OpCode.SET_PARENT_KEY),
|
|
87
|
-
opId:
|
|
88
|
-
id:
|
|
89
|
-
parentKey:
|
|
210
|
+
opId: string2,
|
|
211
|
+
id: string2,
|
|
212
|
+
parentKey: string2
|
|
90
213
|
});
|
|
91
214
|
var deleteObjectKeyOp = object({
|
|
92
215
|
type: constant(OpCode.DELETE_OBJECT_KEY),
|
|
93
|
-
opId:
|
|
94
|
-
id:
|
|
95
|
-
key:
|
|
216
|
+
opId: string2,
|
|
217
|
+
id: string2,
|
|
218
|
+
key: string2
|
|
96
219
|
});
|
|
97
220
|
var op = taggedUnion("type", {
|
|
98
221
|
[OpCode.UPDATE_OBJECT]: updateObjectOp,
|
|
@@ -114,7 +237,7 @@ var ROOT_YDOC_ID = "root";
|
|
|
114
237
|
var updatePresenceClientMsg = object2({
|
|
115
238
|
type: constant2(ClientMsgCode.UPDATE_PRESENCE),
|
|
116
239
|
data: jsonObjectYolo,
|
|
117
|
-
targetActor:
|
|
240
|
+
targetActor: optional3(number)
|
|
118
241
|
});
|
|
119
242
|
var broadcastEventClientMsg = object2({
|
|
120
243
|
type: constant2(ClientMsgCode.BROADCAST_EVENT),
|
|
@@ -125,21 +248,77 @@ var fetchStorageClientMsg = object2({
|
|
|
125
248
|
});
|
|
126
249
|
var updateStorageClientMsg = object2({
|
|
127
250
|
type: constant2(ClientMsgCode.UPDATE_STORAGE),
|
|
128
|
-
ops:
|
|
251
|
+
ops: array2(op)
|
|
129
252
|
});
|
|
130
253
|
var fetchYDocClientMsg = object2({
|
|
131
254
|
type: constant2(ClientMsgCode.FETCH_YDOC),
|
|
132
|
-
vector:
|
|
133
|
-
guid:
|
|
255
|
+
vector: string3.refineType(),
|
|
256
|
+
guid: optional3(guidDecoder),
|
|
134
257
|
// Don't specify to update the root doc
|
|
135
|
-
v2:
|
|
258
|
+
v2: optional3(boolean)
|
|
136
259
|
});
|
|
137
260
|
var updateYDocClientMsg = object2({
|
|
138
261
|
type: constant2(ClientMsgCode.UPDATE_YDOC),
|
|
139
|
-
update:
|
|
140
|
-
guid:
|
|
262
|
+
update: string3.refineType(),
|
|
263
|
+
guid: optional3(guidDecoder),
|
|
141
264
|
// Don't specify to update the root doc
|
|
142
|
-
v2:
|
|
265
|
+
v2: optional3(boolean)
|
|
266
|
+
});
|
|
267
|
+
var fetchFeedsClientMsg = object2({
|
|
268
|
+
type: constant2(FeedMsgCode.FETCH_FEEDS),
|
|
269
|
+
requestId: string3,
|
|
270
|
+
cursor: optional3(string3),
|
|
271
|
+
since: optional3(number),
|
|
272
|
+
limit: optional3(number),
|
|
273
|
+
metadata: fetchFeedsMetadataFilterDecoder
|
|
274
|
+
});
|
|
275
|
+
var fetchFeedMessagesClientMsg = object2({
|
|
276
|
+
type: constant2(FeedMsgCode.FETCH_FEED_MESSAGES),
|
|
277
|
+
requestId: string3,
|
|
278
|
+
feedId: nonEmptyString,
|
|
279
|
+
cursor: optional3(string3),
|
|
280
|
+
since: optional3(number),
|
|
281
|
+
limit: optional3(number)
|
|
282
|
+
});
|
|
283
|
+
var addFeedClientMsg = object2({
|
|
284
|
+
type: constant2(FeedMsgCode.ADD_FEED),
|
|
285
|
+
feedId: string3,
|
|
286
|
+
metadata: optionalFeedMetadataDecoder,
|
|
287
|
+
timestamp: optional3(number),
|
|
288
|
+
requestId: optional3(string3)
|
|
289
|
+
});
|
|
290
|
+
var updateFeedClientMsg = object2({
|
|
291
|
+
type: constant2(FeedMsgCode.UPDATE_FEED),
|
|
292
|
+
feedId: string3,
|
|
293
|
+
metadata: feedMetadataUpdateDecoder,
|
|
294
|
+
requestId: optional3(string3)
|
|
295
|
+
});
|
|
296
|
+
var deleteFeedClientMsg = object2({
|
|
297
|
+
type: constant2(FeedMsgCode.DELETE_FEED),
|
|
298
|
+
feedId: string3,
|
|
299
|
+
requestId: optional3(string3)
|
|
300
|
+
});
|
|
301
|
+
var addFeedMessageClientMsg = object2({
|
|
302
|
+
type: constant2(FeedMsgCode.ADD_FEED_MESSAGE),
|
|
303
|
+
feedId: string3,
|
|
304
|
+
data: jsonObject,
|
|
305
|
+
id: optional3(string3),
|
|
306
|
+
timestamp: optional3(number),
|
|
307
|
+
requestId: optional3(string3)
|
|
308
|
+
});
|
|
309
|
+
var updateFeedMessageClientMsg = object2({
|
|
310
|
+
type: constant2(FeedMsgCode.UPDATE_FEED_MESSAGE),
|
|
311
|
+
feedId: string3,
|
|
312
|
+
messageId: string3,
|
|
313
|
+
data: jsonObject,
|
|
314
|
+
timestamp: optional3(number),
|
|
315
|
+
requestId: optional3(string3)
|
|
316
|
+
});
|
|
317
|
+
var deleteFeedMessageClientMsg = object2({
|
|
318
|
+
type: constant2(FeedMsgCode.DELETE_FEED_MESSAGE),
|
|
319
|
+
feedId: string3,
|
|
320
|
+
messageId: string3,
|
|
321
|
+
requestId: optional3(string3)
|
|
143
322
|
});
|
|
144
323
|
var clientMsgDecoder = taggedUnion2("type", {
|
|
145
324
|
[ClientMsgCode.UPDATE_PRESENCE]: updatePresenceClientMsg,
|
|
@@ -147,7 +326,15 @@ var clientMsgDecoder = taggedUnion2("type", {
|
|
|
147
326
|
[ClientMsgCode.FETCH_STORAGE]: fetchStorageClientMsg,
|
|
148
327
|
[ClientMsgCode.UPDATE_STORAGE]: updateStorageClientMsg,
|
|
149
328
|
[ClientMsgCode.FETCH_YDOC]: fetchYDocClientMsg,
|
|
150
|
-
[ClientMsgCode.UPDATE_YDOC]: updateYDocClientMsg
|
|
329
|
+
[ClientMsgCode.UPDATE_YDOC]: updateYDocClientMsg,
|
|
330
|
+
[FeedMsgCode.FETCH_FEEDS]: fetchFeedsClientMsg,
|
|
331
|
+
[FeedMsgCode.FETCH_FEED_MESSAGES]: fetchFeedMessagesClientMsg,
|
|
332
|
+
[FeedMsgCode.ADD_FEED]: addFeedClientMsg,
|
|
333
|
+
[FeedMsgCode.UPDATE_FEED]: updateFeedClientMsg,
|
|
334
|
+
[FeedMsgCode.DELETE_FEED]: deleteFeedClientMsg,
|
|
335
|
+
[FeedMsgCode.ADD_FEED_MESSAGE]: addFeedMessageClientMsg,
|
|
336
|
+
[FeedMsgCode.UPDATE_FEED_MESSAGE]: updateFeedMessageClientMsg,
|
|
337
|
+
[FeedMsgCode.DELETE_FEED_MESSAGE]: deleteFeedMessageClientMsg
|
|
151
338
|
}).describe("Must be a valid client message");
|
|
152
339
|
var transientClientMsgDecoder = taggedUnion2("type", {
|
|
153
340
|
// [ClientMsgCode.UPDATE_PRESENCE]: updatePresenceClientMsg,
|
|
@@ -628,17 +815,6 @@ function makeMetadataDB(driver) {
|
|
|
628
815
|
};
|
|
629
816
|
}
|
|
630
817
|
|
|
631
|
-
// src/protocol/ProtocolVersion.ts
|
|
632
|
-
import { enum_ } from "decoders";
|
|
633
|
-
var ProtocolVersion = /* @__PURE__ */ ((ProtocolVersion2) => {
|
|
634
|
-
ProtocolVersion2[ProtocolVersion2["V7"] = 7] = "V7";
|
|
635
|
-
ProtocolVersion2[ProtocolVersion2["V8"] = 8] = "V8";
|
|
636
|
-
return ProtocolVersion2;
|
|
637
|
-
})(ProtocolVersion || {});
|
|
638
|
-
var protocolVersionDecoder = enum_(ProtocolVersion).describe(
|
|
639
|
-
"Unsupported protocol version"
|
|
640
|
-
);
|
|
641
|
-
|
|
642
818
|
// src/Room.ts
|
|
643
819
|
import {
|
|
644
820
|
assertNever as assertNever3,
|
|
@@ -646,12 +822,12 @@ import {
|
|
|
646
822
|
nodeStreamToCompactNodes,
|
|
647
823
|
OpCode as OpCode3,
|
|
648
824
|
raise as raise3,
|
|
649
|
-
ServerMsgCode as
|
|
825
|
+
ServerMsgCode as CoreServerMsgCode,
|
|
650
826
|
tryParseJson,
|
|
651
827
|
WebsocketCloseCodes as CloseCode
|
|
652
828
|
} from "@liveblocks/core";
|
|
653
|
-
import { Mutex } from "async-mutex";
|
|
654
|
-
import { array as
|
|
829
|
+
import { Mutex, tryAcquire } from "async-mutex";
|
|
830
|
+
import { array as array3, formatInline } from "decoders";
|
|
655
831
|
import { chunked } from "itertools";
|
|
656
832
|
import { nanoid as nanoid2 } from "nanoid";
|
|
657
833
|
|
|
@@ -845,16 +1021,21 @@ function hasStaticDataAt(node, key) {
|
|
|
845
1021
|
return node.type === CrdtType4.OBJECT && Object.prototype.hasOwnProperty.call(node.data, key) && node.data[key] !== void 0;
|
|
846
1022
|
}
|
|
847
1023
|
var InMemoryDriver = class {
|
|
1024
|
+
// Key: `${feedId}:${messageId}`
|
|
848
1025
|
constructor(options) {
|
|
849
1026
|
__publicField(this, "_nextActor");
|
|
850
1027
|
__publicField(this, "_nodes");
|
|
851
1028
|
__publicField(this, "_metadb");
|
|
852
1029
|
__publicField(this, "_ydb");
|
|
853
1030
|
__publicField(this, "_leasedSessions");
|
|
1031
|
+
__publicField(this, "_feeds");
|
|
1032
|
+
__publicField(this, "_feedMessages");
|
|
854
1033
|
this._nodes = /* @__PURE__ */ new Map();
|
|
855
1034
|
this._metadb = /* @__PURE__ */ new Map();
|
|
856
1035
|
this._ydb = /* @__PURE__ */ new Map();
|
|
857
1036
|
this._leasedSessions = /* @__PURE__ */ new Map();
|
|
1037
|
+
this._feeds = /* @__PURE__ */ new Map();
|
|
1038
|
+
this._feedMessages = /* @__PURE__ */ new Map();
|
|
858
1039
|
this._nextActor = options?.initialActor ?? -1;
|
|
859
1040
|
for (const [key, value] of options?.initialNodes ?? []) {
|
|
860
1041
|
this._nodes.set(key, value);
|
|
@@ -894,6 +1075,180 @@ var InMemoryDriver = class {
|
|
|
894
1075
|
takeRowsWritten() {
|
|
895
1076
|
return 0;
|
|
896
1077
|
}
|
|
1078
|
+
// ---------------------------------------------------------------------------
|
|
1079
|
+
// Feed APIs
|
|
1080
|
+
// ---------------------------------------------------------------------------
|
|
1081
|
+
async list_feeds(options) {
|
|
1082
|
+
const limit = Math.min(options?.limit ?? 20, 100);
|
|
1083
|
+
const since = options?.since;
|
|
1084
|
+
const cursor = options?.cursor;
|
|
1085
|
+
const metadata = options?.metadata;
|
|
1086
|
+
let feeds = [];
|
|
1087
|
+
for (const [_, feed] of this._feeds.entries()) {
|
|
1088
|
+
if (metadata !== void 0) {
|
|
1089
|
+
const feedMetadata = feed.metadata;
|
|
1090
|
+
let matches = true;
|
|
1091
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
1092
|
+
if (feedMetadata[key] !== value) {
|
|
1093
|
+
matches = false;
|
|
1094
|
+
break;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
if (!matches) continue;
|
|
1098
|
+
}
|
|
1099
|
+
if (since !== void 0 && feed.createdAt < since) {
|
|
1100
|
+
continue;
|
|
1101
|
+
}
|
|
1102
|
+
feeds.push(feed);
|
|
1103
|
+
}
|
|
1104
|
+
feeds.sort((a, b) => {
|
|
1105
|
+
if (b.createdAt !== a.createdAt) {
|
|
1106
|
+
return b.createdAt - a.createdAt;
|
|
1107
|
+
}
|
|
1108
|
+
return b.feedId.localeCompare(a.feedId);
|
|
1109
|
+
});
|
|
1110
|
+
if (cursor !== void 0) {
|
|
1111
|
+
try {
|
|
1112
|
+
const decoded = JSON.parse(
|
|
1113
|
+
decodeURIComponent(
|
|
1114
|
+
escape(atob(cursor.replace(/-/g, "+").replace(/_/g, "/")))
|
|
1115
|
+
)
|
|
1116
|
+
);
|
|
1117
|
+
const [cursorFeedId, cursorCreatedAt] = decoded;
|
|
1118
|
+
feeds = feeds.filter((s) => {
|
|
1119
|
+
return s.createdAt < cursorCreatedAt || s.createdAt === cursorCreatedAt && s.feedId < cursorFeedId;
|
|
1120
|
+
});
|
|
1121
|
+
} catch {
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
let nextCursor;
|
|
1125
|
+
if (feeds.length > limit) {
|
|
1126
|
+
feeds = feeds.slice(0, limit);
|
|
1127
|
+
const last = feeds[feeds.length - 1];
|
|
1128
|
+
if (last) {
|
|
1129
|
+
const cursorData = [last.feedId, last.createdAt];
|
|
1130
|
+
nextCursor = btoa(
|
|
1131
|
+
unescape(encodeURIComponent(JSON.stringify(cursorData)))
|
|
1132
|
+
).replace("/", "_").replace("+", "-").replace(/=+$/, "");
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
return { feeds, nextCursor };
|
|
1136
|
+
}
|
|
1137
|
+
async get_feed(feedId) {
|
|
1138
|
+
const feed = this._feeds.get(feedId);
|
|
1139
|
+
if (feed === void 0) {
|
|
1140
|
+
return void 0;
|
|
1141
|
+
}
|
|
1142
|
+
return feed;
|
|
1143
|
+
}
|
|
1144
|
+
async create_feed(feed) {
|
|
1145
|
+
if (this._feeds.has(feed.feedId)) {
|
|
1146
|
+
throw new Error(`Feed ${feed.feedId} already exists`);
|
|
1147
|
+
}
|
|
1148
|
+
this._feeds.set(feed.feedId, {
|
|
1149
|
+
feedId: feed.feedId,
|
|
1150
|
+
metadata: feed.metadata,
|
|
1151
|
+
createdAt: feed.createdAt,
|
|
1152
|
+
updatedAt: feed.updatedAt
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
async update_feed_metadata(feedId, metadata) {
|
|
1156
|
+
const existing = this._feeds.get(feedId);
|
|
1157
|
+
if (existing === void 0) {
|
|
1158
|
+
throw new Error(`Feed ${feedId} not found`);
|
|
1159
|
+
}
|
|
1160
|
+
this._feeds.set(feedId, {
|
|
1161
|
+
...existing,
|
|
1162
|
+
metadata
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
async delete_feed(feedId) {
|
|
1166
|
+
const messageKeys = [];
|
|
1167
|
+
for (const [key] of this._feedMessages.entries()) {
|
|
1168
|
+
if (key.startsWith(`${feedId}:`)) {
|
|
1169
|
+
messageKeys.push(key);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
for (const key of messageKeys) {
|
|
1173
|
+
this._feedMessages.delete(key);
|
|
1174
|
+
}
|
|
1175
|
+
this._feeds.delete(feedId);
|
|
1176
|
+
}
|
|
1177
|
+
async list_feed_messages(feedId, options) {
|
|
1178
|
+
const limit = Math.min(options?.limit ?? 20, 100);
|
|
1179
|
+
const since = options?.since;
|
|
1180
|
+
const cursor = options?.cursor;
|
|
1181
|
+
let messages = [];
|
|
1182
|
+
const prefix = `${feedId}:`;
|
|
1183
|
+
for (const [key, message] of this._feedMessages.entries()) {
|
|
1184
|
+
if (key.startsWith(prefix)) {
|
|
1185
|
+
if (since !== void 0 && message.createdAt < since) {
|
|
1186
|
+
continue;
|
|
1187
|
+
}
|
|
1188
|
+
messages.push(message);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
messages.sort((a, b) => {
|
|
1192
|
+
if (b.createdAt !== a.createdAt) {
|
|
1193
|
+
return b.createdAt - a.createdAt;
|
|
1194
|
+
}
|
|
1195
|
+
return b.id.localeCompare(a.id);
|
|
1196
|
+
});
|
|
1197
|
+
if (cursor !== void 0) {
|
|
1198
|
+
try {
|
|
1199
|
+
const decoded = JSON.parse(
|
|
1200
|
+
decodeURIComponent(
|
|
1201
|
+
escape(atob(cursor.replace(/-/g, "+").replace(/_/g, "/")))
|
|
1202
|
+
)
|
|
1203
|
+
);
|
|
1204
|
+
const [cursorMessageId, cursorCreatedAt] = decoded;
|
|
1205
|
+
messages = messages.filter((m) => {
|
|
1206
|
+
return m.createdAt < cursorCreatedAt || m.createdAt === cursorCreatedAt && m.id < cursorMessageId;
|
|
1207
|
+
});
|
|
1208
|
+
} catch {
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
let nextCursor;
|
|
1212
|
+
if (messages.length > limit) {
|
|
1213
|
+
messages = messages.slice(0, limit);
|
|
1214
|
+
const last = messages[messages.length - 1];
|
|
1215
|
+
if (last) {
|
|
1216
|
+
const cursorData = [last.id, last.createdAt];
|
|
1217
|
+
nextCursor = btoa(
|
|
1218
|
+
unescape(encodeURIComponent(JSON.stringify(cursorData)))
|
|
1219
|
+
).replace("/", "_").replace("+", "-").replace(/=+$/, "");
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
return { messages, nextCursor };
|
|
1223
|
+
}
|
|
1224
|
+
async add_feed_message(feedId, message) {
|
|
1225
|
+
const feed = this._feeds.get(feedId);
|
|
1226
|
+
if (feed === void 0) {
|
|
1227
|
+
throw new Error(`Feed ${feedId} not found`);
|
|
1228
|
+
}
|
|
1229
|
+
this._feedMessages.set(`${feedId}:${message.id}`, message);
|
|
1230
|
+
}
|
|
1231
|
+
async update_feed_message(feedId, messageId, data, timestamp) {
|
|
1232
|
+
const key = `${feedId}:${messageId}`;
|
|
1233
|
+
const message = this._feedMessages.get(key);
|
|
1234
|
+
if (message === void 0) {
|
|
1235
|
+
throw new Error(`Feed message ${messageId} not found in feed ${feedId}`);
|
|
1236
|
+
}
|
|
1237
|
+
const effectiveTimestamp = timestamp ?? Date.now();
|
|
1238
|
+
if (effectiveTimestamp < message.updatedAt) {
|
|
1239
|
+
return message;
|
|
1240
|
+
}
|
|
1241
|
+
const updatedMessage = {
|
|
1242
|
+
...message,
|
|
1243
|
+
updatedAt: effectiveTimestamp,
|
|
1244
|
+
data
|
|
1245
|
+
};
|
|
1246
|
+
this._feedMessages.set(key, updatedMessage);
|
|
1247
|
+
return updatedMessage;
|
|
1248
|
+
}
|
|
1249
|
+
async delete_feed_message(feedId, messageId) {
|
|
1250
|
+
this._feedMessages.delete(`${feedId}:${messageId}`);
|
|
1251
|
+
}
|
|
897
1252
|
next_actor() {
|
|
898
1253
|
return ++this._nextActor;
|
|
899
1254
|
}
|
|
@@ -1448,7 +1803,7 @@ var YjsStorage = class {
|
|
|
1448
1803
|
let encodedTargetVector;
|
|
1449
1804
|
try {
|
|
1450
1805
|
encodedTargetVector = stateVector.length > 0 ? Base64.toUint8Array(stateVector) : void 0;
|
|
1451
|
-
} catch
|
|
1806
|
+
} catch {
|
|
1452
1807
|
logger.warn(
|
|
1453
1808
|
"Could not get update from passed vector, returning all updates"
|
|
1454
1809
|
);
|
|
@@ -1672,7 +2027,8 @@ function isLeasedSessionExpired(leasedSession) {
|
|
|
1672
2027
|
}
|
|
1673
2028
|
|
|
1674
2029
|
// src/Room.ts
|
|
1675
|
-
var messagesDecoder =
|
|
2030
|
+
var messagesDecoder = array3(clientMsgDecoder);
|
|
2031
|
+
var ServerMsgCode2 = { ...CoreServerMsgCode, ...FeedMsgCode };
|
|
1676
2032
|
var HIGHEST_PROTOCOL_VERSION = Math.max(
|
|
1677
2033
|
...Object.values(ProtocolVersion).filter(
|
|
1678
2034
|
(v) => typeof v === "number"
|
|
@@ -1722,6 +2078,7 @@ var BrowserSession = class {
|
|
|
1722
2078
|
// Metadata sent to client in ROOM_STATE message's "meta" field
|
|
1723
2079
|
__privateAdd(this, __socket);
|
|
1724
2080
|
__privateAdd(this, __debug);
|
|
2081
|
+
/** Updated on every incoming message (including pings) via handleData(). Used for idle timeout detection. */
|
|
1725
2082
|
__privateAdd(this, __lastActiveAt);
|
|
1726
2083
|
// We keep a status in-memory in the session of whether we already sent a rejected ops message to the client.
|
|
1727
2084
|
__privateAdd(this, __hasNotifiedClientStorageUpdateError);
|
|
@@ -1733,15 +2090,15 @@ var BrowserSession = class {
|
|
|
1733
2090
|
this.publicMeta = ticket.publicMeta;
|
|
1734
2091
|
__privateSet(this, __socket, socket);
|
|
1735
2092
|
__privateSet(this, __debug, debug);
|
|
1736
|
-
const now = createdAt ??
|
|
2093
|
+
const now = createdAt?.getTime() ?? Date.now();
|
|
1737
2094
|
this.createdAt = now;
|
|
1738
2095
|
__privateSet(this, __lastActiveAt, now);
|
|
1739
2096
|
__privateSet(this, __hasNotifiedClientStorageUpdateError, false);
|
|
1740
2097
|
}
|
|
1741
2098
|
get lastActiveAt() {
|
|
1742
2099
|
const lastPing = __privateGet(this, __socket).getLastPongTimestamp?.();
|
|
1743
|
-
if (lastPing && lastPing > __privateGet(this, __lastActiveAt)) {
|
|
1744
|
-
return lastPing;
|
|
2100
|
+
if (lastPing && lastPing.getTime() > __privateGet(this, __lastActiveAt)) {
|
|
2101
|
+
return lastPing.getTime();
|
|
1745
2102
|
} else {
|
|
1746
2103
|
return __privateGet(this, __lastActiveAt);
|
|
1747
2104
|
}
|
|
@@ -1749,10 +2106,9 @@ var BrowserSession = class {
|
|
|
1749
2106
|
get hasNotifiedClientStorageUpdateError() {
|
|
1750
2107
|
return __privateGet(this, __hasNotifiedClientStorageUpdateError);
|
|
1751
2108
|
}
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
}
|
|
2109
|
+
/** @internal - This should have to be called only from Room, never externally */
|
|
2110
|
+
markActive(now) {
|
|
2111
|
+
__privateSet(this, __lastActiveAt, now ? now.getTime() : Date.now());
|
|
1756
2112
|
}
|
|
1757
2113
|
setHasNotifiedClientStorageUpdateError() {
|
|
1758
2114
|
__privateSet(this, __hasNotifiedClientStorageUpdateError, true);
|
|
@@ -1824,6 +2180,15 @@ var Room = class {
|
|
|
1824
2180
|
__publicField(this, "meta");
|
|
1825
2181
|
__publicField(this, "driver");
|
|
1826
2182
|
__publicField(this, "logger");
|
|
2183
|
+
/**
|
|
2184
|
+
* While a room is in "maintenance mode", all WebSocket connections to the
|
|
2185
|
+
* room should be rejected until it's pulled out of maintenance mode again.
|
|
2186
|
+
* Maintenance mode should only last a couple of milliseconds, typically.
|
|
2187
|
+
*
|
|
2188
|
+
* This mutex ensures that concurrent destructive operations (like
|
|
2189
|
+
* init-storage, storage-reset, etc.) cannot interfere with one another.
|
|
2190
|
+
*/
|
|
2191
|
+
__publicField(this, "_maintenanceMode", new Mutex());
|
|
1827
2192
|
__publicField(this, "_loadData$", null);
|
|
1828
2193
|
__publicField(this, "_data", null);
|
|
1829
2194
|
__publicField(this, "_qsize", 0);
|
|
@@ -1884,6 +2249,24 @@ var Room = class {
|
|
|
1884
2249
|
}
|
|
1885
2250
|
// prettier-ignore
|
|
1886
2251
|
// ------------------------------------------------------------------------------------
|
|
2252
|
+
// Maintenance mode
|
|
2253
|
+
// ------------------------------------------------------------------------------------
|
|
2254
|
+
/**
|
|
2255
|
+
* Returns true if the room is currently in maintenance mode.
|
|
2256
|
+
* When in maintenance mode, callers should refuse new WebSocket connections.
|
|
2257
|
+
*/
|
|
2258
|
+
get isInMaintenance() {
|
|
2259
|
+
return this._maintenanceMode.isLocked();
|
|
2260
|
+
}
|
|
2261
|
+
/**
|
|
2262
|
+
* Tries to enter maintenance mode and run the given callback exclusively.
|
|
2263
|
+
* If the room is already in maintenance mode, throws E_ALREADY_LOCKED
|
|
2264
|
+
* immediately instead of queuing the request.
|
|
2265
|
+
*/
|
|
2266
|
+
async runInMaintenanceMode(callback) {
|
|
2267
|
+
return tryAcquire(this._maintenanceMode).runExclusive(callback);
|
|
2268
|
+
}
|
|
2269
|
+
// ------------------------------------------------------------------------------------
|
|
1887
2270
|
// Public API
|
|
1888
2271
|
// ------------------------------------------------------------------------------------
|
|
1889
2272
|
/**
|
|
@@ -2127,6 +2510,7 @@ var Room = class {
|
|
|
2127
2510
|
);
|
|
2128
2511
|
}) {
|
|
2129
2512
|
const text = typeof data === "string" ? data : raise3("Unsupported message format");
|
|
2513
|
+
this.sessions.get(key)?.markActive();
|
|
2130
2514
|
if (text === "ping") {
|
|
2131
2515
|
await this.handlePing(key, ctx);
|
|
2132
2516
|
} else {
|
|
@@ -2340,6 +2724,87 @@ var Room = class {
|
|
|
2340
2724
|
await this.deleteLeasedSession(session, ctx, defer);
|
|
2341
2725
|
}
|
|
2342
2726
|
}
|
|
2727
|
+
// ---------------------------------------------------------------------------
|
|
2728
|
+
// Feed APIs
|
|
2729
|
+
// ---------------------------------------------------------------------------
|
|
2730
|
+
/**
|
|
2731
|
+
* List feeds with pagination and filtering.
|
|
2732
|
+
*/
|
|
2733
|
+
async listFeeds(options) {
|
|
2734
|
+
return await this.driver.list_feeds(options);
|
|
2735
|
+
}
|
|
2736
|
+
/**
|
|
2737
|
+
* Get a specific feed by feed ID.
|
|
2738
|
+
*/
|
|
2739
|
+
async getFeed(feedId) {
|
|
2740
|
+
return await this.driver.get_feed(feedId);
|
|
2741
|
+
}
|
|
2742
|
+
/**
|
|
2743
|
+
* Create a new feed.
|
|
2744
|
+
* If timestamp is not provided, current server time is used.
|
|
2745
|
+
*/
|
|
2746
|
+
async createFeed(feed) {
|
|
2747
|
+
const now = feed.timestamp ?? Date.now();
|
|
2748
|
+
const fullFeed = {
|
|
2749
|
+
...feed,
|
|
2750
|
+
createdAt: now,
|
|
2751
|
+
updatedAt: now
|
|
2752
|
+
};
|
|
2753
|
+
await this.driver.create_feed(fullFeed);
|
|
2754
|
+
return fullFeed;
|
|
2755
|
+
}
|
|
2756
|
+
/**
|
|
2757
|
+
* Update a feed's metadata.
|
|
2758
|
+
*/
|
|
2759
|
+
async updateFeedMetadata(feedId, metadata) {
|
|
2760
|
+
await this.driver.update_feed_metadata(feedId, metadata);
|
|
2761
|
+
}
|
|
2762
|
+
/**
|
|
2763
|
+
* Delete a feed.
|
|
2764
|
+
*/
|
|
2765
|
+
async deleteFeed(feedId) {
|
|
2766
|
+
await this.driver.delete_feed(feedId);
|
|
2767
|
+
}
|
|
2768
|
+
/**
|
|
2769
|
+
* List feed messages for a feed with pagination.
|
|
2770
|
+
*/
|
|
2771
|
+
async listFeedMessages(feedId, options) {
|
|
2772
|
+
return await this.driver.list_feed_messages(feedId, options);
|
|
2773
|
+
}
|
|
2774
|
+
/**
|
|
2775
|
+
* Add a message to a feed.
|
|
2776
|
+
* If message id is not provided, a unique ID is automatically generated.
|
|
2777
|
+
* If timestamp is not provided, current server time is used.
|
|
2778
|
+
*/
|
|
2779
|
+
async addFeedMessage(feedId, message) {
|
|
2780
|
+
const now = message.timestamp ?? Date.now();
|
|
2781
|
+
const fullMessage = {
|
|
2782
|
+
id: message.id ?? nanoid2(),
|
|
2783
|
+
createdAt: now,
|
|
2784
|
+
updatedAt: now,
|
|
2785
|
+
data: message.data
|
|
2786
|
+
};
|
|
2787
|
+
await this.driver.add_feed_message(feedId, fullMessage);
|
|
2788
|
+
return fullMessage;
|
|
2789
|
+
}
|
|
2790
|
+
/**
|
|
2791
|
+
* Update a feed message's data.
|
|
2792
|
+
* Returns the updated message.
|
|
2793
|
+
*/
|
|
2794
|
+
async updateFeedMessage(feedId, messageId, data, timestamp) {
|
|
2795
|
+
return await this.driver.update_feed_message(
|
|
2796
|
+
feedId,
|
|
2797
|
+
messageId,
|
|
2798
|
+
data,
|
|
2799
|
+
timestamp ?? Date.now()
|
|
2800
|
+
);
|
|
2801
|
+
}
|
|
2802
|
+
/**
|
|
2803
|
+
* Delete a feed message.
|
|
2804
|
+
*/
|
|
2805
|
+
async deleteFeedMessage(feedId, messageId) {
|
|
2806
|
+
await this.driver.delete_feed_message(feedId, messageId);
|
|
2807
|
+
}
|
|
2343
2808
|
/**
|
|
2344
2809
|
* Will send the given ServerMsg through all Session, except the Session
|
|
2345
2810
|
* where the message originates from.
|
|
@@ -2676,6 +3141,176 @@ var Room = class {
|
|
|
2676
3141
|
}
|
|
2677
3142
|
break;
|
|
2678
3143
|
}
|
|
3144
|
+
case FeedMsgCode.FETCH_FEEDS: {
|
|
3145
|
+
const fetchMsg = msg;
|
|
3146
|
+
const [result, err] = await tryCatch(
|
|
3147
|
+
this.listFeeds({
|
|
3148
|
+
cursor: fetchMsg.cursor,
|
|
3149
|
+
since: fetchMsg.since,
|
|
3150
|
+
limit: fetchMsg.limit,
|
|
3151
|
+
metadata: fetchMsg.metadata
|
|
3152
|
+
})
|
|
3153
|
+
);
|
|
3154
|
+
if (err) {
|
|
3155
|
+
replyImmediately(feedFailureServerMsg(fetchMsg.requestId, err));
|
|
3156
|
+
break;
|
|
3157
|
+
}
|
|
3158
|
+
replyImmediately({
|
|
3159
|
+
type: FeedMsgCode.FEEDS_LIST,
|
|
3160
|
+
requestId: fetchMsg.requestId,
|
|
3161
|
+
feeds: result.feeds,
|
|
3162
|
+
nextCursor: result.nextCursor
|
|
3163
|
+
});
|
|
3164
|
+
break;
|
|
3165
|
+
}
|
|
3166
|
+
case FeedMsgCode.FETCH_FEED_MESSAGES: {
|
|
3167
|
+
const fetchMsg = msg;
|
|
3168
|
+
const [result, err] = await tryCatch(
|
|
3169
|
+
this.listFeedMessages(fetchMsg.feedId, {
|
|
3170
|
+
cursor: fetchMsg.cursor,
|
|
3171
|
+
since: fetchMsg.since,
|
|
3172
|
+
limit: fetchMsg.limit
|
|
3173
|
+
})
|
|
3174
|
+
);
|
|
3175
|
+
if (err) {
|
|
3176
|
+
replyImmediately(feedFailureServerMsg(fetchMsg.requestId, err));
|
|
3177
|
+
break;
|
|
3178
|
+
}
|
|
3179
|
+
replyImmediately({
|
|
3180
|
+
type: FeedMsgCode.FEED_MESSAGES_LIST,
|
|
3181
|
+
requestId: fetchMsg.requestId,
|
|
3182
|
+
feedId: fetchMsg.feedId,
|
|
3183
|
+
messages: result.messages,
|
|
3184
|
+
nextCursor: result.nextCursor
|
|
3185
|
+
});
|
|
3186
|
+
break;
|
|
3187
|
+
}
|
|
3188
|
+
case FeedMsgCode.ADD_FEED: {
|
|
3189
|
+
const addMsg = msg;
|
|
3190
|
+
const [feed, err] = await tryCatch(
|
|
3191
|
+
this.createFeed({
|
|
3192
|
+
feedId: addMsg.feedId,
|
|
3193
|
+
metadata: addMsg.metadata ?? {},
|
|
3194
|
+
timestamp: addMsg.timestamp
|
|
3195
|
+
})
|
|
3196
|
+
);
|
|
3197
|
+
if (err) {
|
|
3198
|
+
replyImmediately(feedFailureServerMsg(addMsg.requestId, err));
|
|
3199
|
+
break;
|
|
3200
|
+
}
|
|
3201
|
+
const feedsMsg = {
|
|
3202
|
+
type: FeedMsgCode.FEEDS_ADDED,
|
|
3203
|
+
feeds: [feed]
|
|
3204
|
+
};
|
|
3205
|
+
replyImmediately(feedsMsg);
|
|
3206
|
+
scheduleFanOut(feedsMsg);
|
|
3207
|
+
break;
|
|
3208
|
+
}
|
|
3209
|
+
case FeedMsgCode.UPDATE_FEED: {
|
|
3210
|
+
const updateMsg = msg;
|
|
3211
|
+
const [, metaErr] = await tryCatch(
|
|
3212
|
+
this.updateFeedMetadata(updateMsg.feedId, updateMsg.metadata)
|
|
3213
|
+
);
|
|
3214
|
+
if (metaErr) {
|
|
3215
|
+
replyImmediately(feedFailureServerMsg(updateMsg.requestId, metaErr));
|
|
3216
|
+
break;
|
|
3217
|
+
}
|
|
3218
|
+
const feed = await this.getFeed(updateMsg.feedId);
|
|
3219
|
+
if (!feed) {
|
|
3220
|
+
replyImmediately(
|
|
3221
|
+
feedRequestFailed(
|
|
3222
|
+
updateMsg.requestId,
|
|
3223
|
+
FeedRequestErrorCode.FEED_NOT_FOUND
|
|
3224
|
+
)
|
|
3225
|
+
);
|
|
3226
|
+
break;
|
|
3227
|
+
}
|
|
3228
|
+
const feedsMsg = {
|
|
3229
|
+
type: FeedMsgCode.FEEDS_UPDATED,
|
|
3230
|
+
feeds: [feed]
|
|
3231
|
+
};
|
|
3232
|
+
replyImmediately(feedsMsg);
|
|
3233
|
+
scheduleFanOut(feedsMsg);
|
|
3234
|
+
break;
|
|
3235
|
+
}
|
|
3236
|
+
case FeedMsgCode.DELETE_FEED: {
|
|
3237
|
+
const deleteMsg = msg;
|
|
3238
|
+
const [, err] = await tryCatch(this.deleteFeed(deleteMsg.feedId));
|
|
3239
|
+
if (err) {
|
|
3240
|
+
replyImmediately(feedFailureServerMsg(deleteMsg.requestId, err));
|
|
3241
|
+
break;
|
|
3242
|
+
}
|
|
3243
|
+
const feedDeletedMsg = {
|
|
3244
|
+
type: FeedMsgCode.FEED_DELETED,
|
|
3245
|
+
feedId: deleteMsg.feedId
|
|
3246
|
+
};
|
|
3247
|
+
replyImmediately(feedDeletedMsg);
|
|
3248
|
+
scheduleFanOut(feedDeletedMsg);
|
|
3249
|
+
break;
|
|
3250
|
+
}
|
|
3251
|
+
case FeedMsgCode.ADD_FEED_MESSAGE: {
|
|
3252
|
+
const addMsg = msg;
|
|
3253
|
+
const [message, err] = await tryCatch(
|
|
3254
|
+
this.addFeedMessage(addMsg.feedId, {
|
|
3255
|
+
data: addMsg.data,
|
|
3256
|
+
id: addMsg.id,
|
|
3257
|
+
timestamp: addMsg.timestamp
|
|
3258
|
+
})
|
|
3259
|
+
);
|
|
3260
|
+
if (err) {
|
|
3261
|
+
replyImmediately(feedFailureServerMsg(addMsg.requestId, err));
|
|
3262
|
+
break;
|
|
3263
|
+
}
|
|
3264
|
+
const feedMessagesMsg = {
|
|
3265
|
+
type: FeedMsgCode.FEED_MESSAGES_ADDED,
|
|
3266
|
+
feedId: addMsg.feedId,
|
|
3267
|
+
messages: [message]
|
|
3268
|
+
};
|
|
3269
|
+
replyImmediately(feedMessagesMsg);
|
|
3270
|
+
scheduleFanOut(feedMessagesMsg);
|
|
3271
|
+
break;
|
|
3272
|
+
}
|
|
3273
|
+
case FeedMsgCode.UPDATE_FEED_MESSAGE: {
|
|
3274
|
+
const updateMsg = msg;
|
|
3275
|
+
const [message, err] = await tryCatch(
|
|
3276
|
+
this.updateFeedMessage(
|
|
3277
|
+
updateMsg.feedId,
|
|
3278
|
+
updateMsg.messageId,
|
|
3279
|
+
updateMsg.data,
|
|
3280
|
+
updateMsg.timestamp
|
|
3281
|
+
)
|
|
3282
|
+
);
|
|
3283
|
+
if (err) {
|
|
3284
|
+
replyImmediately(feedFailureServerMsg(updateMsg.requestId, err));
|
|
3285
|
+
break;
|
|
3286
|
+
}
|
|
3287
|
+
const feedMessagesMsg = {
|
|
3288
|
+
type: FeedMsgCode.FEED_MESSAGES_UPDATED,
|
|
3289
|
+
feedId: updateMsg.feedId,
|
|
3290
|
+
messages: [message]
|
|
3291
|
+
};
|
|
3292
|
+
replyImmediately(feedMessagesMsg);
|
|
3293
|
+
scheduleFanOut(feedMessagesMsg);
|
|
3294
|
+
break;
|
|
3295
|
+
}
|
|
3296
|
+
case FeedMsgCode.DELETE_FEED_MESSAGE: {
|
|
3297
|
+
const deleteMsg = msg;
|
|
3298
|
+
const [, err] = await tryCatch(
|
|
3299
|
+
this.deleteFeedMessage(deleteMsg.feedId, deleteMsg.messageId)
|
|
3300
|
+
);
|
|
3301
|
+
if (err) {
|
|
3302
|
+
replyImmediately(feedFailureServerMsg(deleteMsg.requestId, err));
|
|
3303
|
+
break;
|
|
3304
|
+
}
|
|
3305
|
+
const feedMessagesMsg = {
|
|
3306
|
+
type: FeedMsgCode.FEED_MESSAGES_DELETED,
|
|
3307
|
+
feedId: deleteMsg.feedId,
|
|
3308
|
+
messageIds: [deleteMsg.messageId]
|
|
3309
|
+
};
|
|
3310
|
+
replyImmediately(feedMessagesMsg);
|
|
3311
|
+
scheduleFanOut(feedMessagesMsg);
|
|
3312
|
+
break;
|
|
3313
|
+
}
|
|
2679
3314
|
default: {
|
|
2680
3315
|
try {
|
|
2681
3316
|
return assertNever3(msg, "Unrecognized client msg");
|
|
@@ -2692,6 +3327,8 @@ export {
|
|
|
2692
3327
|
BrowserSession,
|
|
2693
3328
|
ConsoleTarget,
|
|
2694
3329
|
DefaultMap,
|
|
3330
|
+
FeedMsgCode,
|
|
3331
|
+
FeedRequestErrorCode,
|
|
2695
3332
|
InMemoryDriver,
|
|
2696
3333
|
LogLevel,
|
|
2697
3334
|
LogTarget,
|
|
@@ -2704,12 +3341,19 @@ export {
|
|
|
2704
3341
|
ackIgnoredOp,
|
|
2705
3342
|
clientMsgDecoder,
|
|
2706
3343
|
concatUint8Arrays,
|
|
3344
|
+
feedFailureServerMsg,
|
|
3345
|
+
feedMetadataIdDecoder,
|
|
3346
|
+
feedMetadataUpdateDecoder,
|
|
3347
|
+
feedRequestFailed,
|
|
3348
|
+
fetchFeedsMetadataFilterDecoder,
|
|
2707
3349
|
guidDecoder,
|
|
2708
3350
|
isLeasedSessionExpired,
|
|
2709
3351
|
jsonObjectYolo,
|
|
2710
3352
|
jsonYolo,
|
|
2711
3353
|
makeInMemorySnapshot,
|
|
2712
3354
|
makeMetadataDB,
|
|
3355
|
+
mapFeedError,
|
|
3356
|
+
optionalFeedMetadataDecoder,
|
|
2713
3357
|
plainLsonToNodeStream,
|
|
2714
3358
|
protocolVersionDecoder,
|
|
2715
3359
|
quote,
|