@neta-art/cohub 1.8.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -105
- package/dist/chunks/environment.js +33 -0
- package/dist/chunks/http.d.ts +1615 -0
- package/dist/chunks/http.js +1919 -0
- package/dist/chunks/websocket.d.ts +266 -0
- package/dist/chunks/websocket.js +655 -0
- package/dist/http.d.ts +3 -30
- package/dist/http.js +2 -45
- package/dist/index.d.ts +35 -14
- package/dist/index.js +105 -8
- package/dist/websocket.d.ts +2 -141
- package/dist/websocket.js +2 -628
- package/package.json +7 -7
- package/dist/apis/channels.d.ts +0 -13
- package/dist/apis/channels.js +0 -24
- package/dist/apis/cron-jobs.d.ts +0 -18
- package/dist/apis/cron-jobs.js +0 -25
- package/dist/apis/explore.d.ts +0 -9
- package/dist/apis/explore.js +0 -9
- package/dist/apis/generations.d.ts +0 -8
- package/dist/apis/generations.js +0 -16
- package/dist/apis/invitations.d.ts +0 -20
- package/dist/apis/invitations.js +0 -36
- package/dist/apis/models.d.ts +0 -7
- package/dist/apis/models.js +0 -9
- package/dist/apis/prompts.d.ts +0 -9
- package/dist/apis/prompts.js +0 -16
- package/dist/apis/search.d.ts +0 -10
- package/dist/apis/search.js +0 -14
- package/dist/apis/session-access.d.ts +0 -13
- package/dist/apis/session-access.js +0 -19
- package/dist/apis/spaces.d.ts +0 -371
- package/dist/apis/spaces.js +0 -766
- package/dist/apis/tasks.d.ts +0 -13
- package/dist/apis/tasks.js +0 -18
- package/dist/apis/user.d.ts +0 -27
- package/dist/apis/user.js +0 -71
- package/dist/client.d.ts +0 -33
- package/dist/client.js +0 -103
- package/dist/environment.d.ts +0 -22
- package/dist/environment.js +0 -37
- package/dist/realtime.d.ts +0 -2
- package/dist/realtime.js +0 -8
- package/dist/session-generation-stream.d.ts +0 -114
- package/dist/session-generation-stream.js +0 -514
- package/dist/session-patch-reducer.d.ts +0 -61
- package/dist/session-patch-reducer.js +0 -432
- package/dist/transport.d.ts +0 -40
- package/dist/transport.js +0 -78
- package/dist/types.d.ts +0 -535
- package/dist/types.js +0 -1
|
@@ -1,432 +0,0 @@
|
|
|
1
|
-
const blockSubPathPattern = /^\/message\/content\/blocks\/(\d+)\/(.+)$/;
|
|
2
|
-
const blockPathPattern = /^\/message\/content\/blocks\/(\d+)$/;
|
|
3
|
-
const blockMetaPathPattern = /^\/message\/content\/blocks\/(\d+)\/_meta$/;
|
|
4
|
-
const TERMINAL_PATCH_STATUSES = new Set(["completed", "failed", "interrupted"]);
|
|
5
|
-
const isTerminalPatchStatus = (status) => TERMINAL_PATCH_STATUSES.has(status);
|
|
6
|
-
const createIdleState = (input) => ({
|
|
7
|
-
spaceId: input.spaceId ?? null,
|
|
8
|
-
sessionId: input.sessionId,
|
|
9
|
-
status: "idle",
|
|
10
|
-
contentBlocks: [],
|
|
11
|
-
anchorUserMessageId: null,
|
|
12
|
-
patchSeq: 0,
|
|
13
|
-
turnId: null,
|
|
14
|
-
appendPath: null,
|
|
15
|
-
});
|
|
16
|
-
function cloneBlock(block) {
|
|
17
|
-
return structuredClone(block);
|
|
18
|
-
}
|
|
19
|
-
function getStreamIndex(block) {
|
|
20
|
-
const value = block._meta?.streamIndex;
|
|
21
|
-
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
22
|
-
}
|
|
23
|
-
function blockIdentityCompatible(prev, next) {
|
|
24
|
-
if (prev.type !== next.type)
|
|
25
|
-
return false;
|
|
26
|
-
if (prev.type === "tool_use" && next.type === "tool_use")
|
|
27
|
-
return prev.id === next.id && prev.name === next.name;
|
|
28
|
-
if (prev.type === "tool_result" && next.type === "tool_result")
|
|
29
|
-
return prev.tool_use_id === next.tool_use_id;
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
function findBlockByStreamIndex(blocks, streamIndex) {
|
|
33
|
-
return blocks.findIndex((block) => getStreamIndex(block) === streamIndex);
|
|
34
|
-
}
|
|
35
|
-
function findBlockForReplacement(blocks, streamIndex, nextBlock) {
|
|
36
|
-
const compatibleIndex = blocks.findIndex((block) => getStreamIndex(block) === streamIndex && blockIdentityCompatible(block, nextBlock));
|
|
37
|
-
if (compatibleIndex >= 0)
|
|
38
|
-
return compatibleIndex;
|
|
39
|
-
const sameStreamIndex = blocks.findIndex((block) => getStreamIndex(block) === streamIndex);
|
|
40
|
-
if (sameStreamIndex >= 0 && nextBlock.type !== "tool_use" && nextBlock.type !== "tool_result")
|
|
41
|
-
return sameStreamIndex;
|
|
42
|
-
return -1;
|
|
43
|
-
}
|
|
44
|
-
function sortBlocksByStreamIndex(blocks) {
|
|
45
|
-
return [...blocks].sort((a, b) => {
|
|
46
|
-
const aIndex = getStreamIndex(a);
|
|
47
|
-
const bIndex = getStreamIndex(b);
|
|
48
|
-
if (aIndex == null && bIndex == null)
|
|
49
|
-
return 0;
|
|
50
|
-
if (aIndex == null)
|
|
51
|
-
return 1;
|
|
52
|
-
if (bIndex == null)
|
|
53
|
-
return -1;
|
|
54
|
-
return aIndex - bIndex;
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
function isContentBlock(value) {
|
|
58
|
-
return Boolean(value && typeof value === "object" && "type" in value);
|
|
59
|
-
}
|
|
60
|
-
function isPlainObject(value) {
|
|
61
|
-
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
62
|
-
}
|
|
63
|
-
function decodePointerSegments(encoded) {
|
|
64
|
-
if (!encoded)
|
|
65
|
-
return [];
|
|
66
|
-
return encoded.split("/").map((s) => s.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
67
|
-
}
|
|
68
|
-
function ensureTextLikeBlock(blocks, streamIndex, field) {
|
|
69
|
-
const existingIndex = findBlockByStreamIndex(blocks, streamIndex);
|
|
70
|
-
const existing = existingIndex >= 0 ? blocks[existingIndex] : undefined;
|
|
71
|
-
if (field === "text") {
|
|
72
|
-
if (existing?.type === "text")
|
|
73
|
-
return existing;
|
|
74
|
-
const block = {
|
|
75
|
-
type: "text",
|
|
76
|
-
text: "",
|
|
77
|
-
_meta: { streamIndex },
|
|
78
|
-
};
|
|
79
|
-
blocks.push(block);
|
|
80
|
-
return block;
|
|
81
|
-
}
|
|
82
|
-
if (existing?.type === "thinking")
|
|
83
|
-
return existing;
|
|
84
|
-
const block = {
|
|
85
|
-
type: "thinking",
|
|
86
|
-
thinking: "",
|
|
87
|
-
_meta: { streamIndex },
|
|
88
|
-
};
|
|
89
|
-
blocks.push(block);
|
|
90
|
-
return block;
|
|
91
|
-
}
|
|
92
|
-
function getOrCreateBlockForSubpath(blocks, streamIndex, firstSegment) {
|
|
93
|
-
const idx = findBlockByStreamIndex(blocks, streamIndex);
|
|
94
|
-
if (idx >= 0)
|
|
95
|
-
return blocks[idx] ?? null;
|
|
96
|
-
if (firstSegment === "text") {
|
|
97
|
-
return ensureTextLikeBlock(blocks, streamIndex, "text");
|
|
98
|
-
}
|
|
99
|
-
if (firstSegment === "thinking") {
|
|
100
|
-
return ensureTextLikeBlock(blocks, streamIndex, "thinking");
|
|
101
|
-
}
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
function setDeepOnContentBlock(root, segments, value) {
|
|
105
|
-
if (segments.length === 0)
|
|
106
|
-
return false;
|
|
107
|
-
let cur = root;
|
|
108
|
-
for (let i = 0; i < segments.length - 1; i++) {
|
|
109
|
-
const k = segments[i];
|
|
110
|
-
if (k === undefined)
|
|
111
|
-
return false;
|
|
112
|
-
if (!isPlainObject(cur))
|
|
113
|
-
return false;
|
|
114
|
-
const next = cur[k];
|
|
115
|
-
if (next === undefined)
|
|
116
|
-
return false;
|
|
117
|
-
cur = next;
|
|
118
|
-
}
|
|
119
|
-
const last = segments[segments.length - 1];
|
|
120
|
-
if (last === undefined)
|
|
121
|
-
return false;
|
|
122
|
-
if (!isPlainObject(cur))
|
|
123
|
-
return false;
|
|
124
|
-
const toAssign = value !== null && typeof value === "object"
|
|
125
|
-
? structuredClone(value)
|
|
126
|
-
: value;
|
|
127
|
-
cur[last] = toAssign;
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
function appendDeepOnContentBlock(root, segments, suffix) {
|
|
131
|
-
if (segments.length === 0)
|
|
132
|
-
return false;
|
|
133
|
-
let cur = root;
|
|
134
|
-
for (let i = 0; i < segments.length - 1; i++) {
|
|
135
|
-
const k = segments[i];
|
|
136
|
-
if (k === undefined)
|
|
137
|
-
return false;
|
|
138
|
-
if (!isPlainObject(cur))
|
|
139
|
-
return false;
|
|
140
|
-
const next = cur[k];
|
|
141
|
-
if (next === undefined)
|
|
142
|
-
return false;
|
|
143
|
-
cur = next;
|
|
144
|
-
}
|
|
145
|
-
const last = segments[segments.length - 1];
|
|
146
|
-
if (last === undefined)
|
|
147
|
-
return false;
|
|
148
|
-
if (!isPlainObject(cur))
|
|
149
|
-
return false;
|
|
150
|
-
const parent = cur;
|
|
151
|
-
const leaf = parent[last];
|
|
152
|
-
if (typeof leaf !== "string")
|
|
153
|
-
return false;
|
|
154
|
-
parent[last] = leaf + suffix;
|
|
155
|
-
return true;
|
|
156
|
-
}
|
|
157
|
-
function resolveBlockForSubpath(blocks, streamIndex, firstSegment) {
|
|
158
|
-
const idx = findBlockByStreamIndex(blocks, streamIndex);
|
|
159
|
-
if (idx >= 0)
|
|
160
|
-
return blocks[idx] ?? null;
|
|
161
|
-
return getOrCreateBlockForSubpath(blocks, streamIndex, firstSegment);
|
|
162
|
-
}
|
|
163
|
-
function applyReplaceAtBlockSubpath(blocks, streamIndex, encodedTail, value) {
|
|
164
|
-
const segs = decodePointerSegments(encodedTail);
|
|
165
|
-
if (segs.length === 0)
|
|
166
|
-
return false;
|
|
167
|
-
const block = resolveBlockForSubpath(blocks, streamIndex, segs[0] ?? "");
|
|
168
|
-
if (!block)
|
|
169
|
-
return false;
|
|
170
|
-
return setDeepOnContentBlock(block, segs, value);
|
|
171
|
-
}
|
|
172
|
-
function applyAppendAtBlockSubpath(blocks, streamIndex, encodedTail, suffix) {
|
|
173
|
-
if (typeof suffix !== "string")
|
|
174
|
-
return false;
|
|
175
|
-
const segs = decodePointerSegments(encodedTail);
|
|
176
|
-
if (segs.length === 0)
|
|
177
|
-
return false;
|
|
178
|
-
const block = resolveBlockForSubpath(blocks, streamIndex, segs[0] ?? "");
|
|
179
|
-
if (!block)
|
|
180
|
-
return false;
|
|
181
|
-
return appendDeepOnContentBlock(block, segs, suffix);
|
|
182
|
-
}
|
|
183
|
-
function appendPatchStreamValue(blocks, path, value) {
|
|
184
|
-
const m = path.match(blockSubPathPattern);
|
|
185
|
-
if (!m)
|
|
186
|
-
return false;
|
|
187
|
-
return applyAppendAtBlockSubpath(blocks, Number(m[1]), m[2] ?? "", value);
|
|
188
|
-
}
|
|
189
|
-
function applyPatchOpsToBlocks(current, ops, initialAppendPath) {
|
|
190
|
-
const next = current.map(cloneBlock);
|
|
191
|
-
let anchorUserMessageId;
|
|
192
|
-
let appendPath = initialAppendPath;
|
|
193
|
-
let failed = false;
|
|
194
|
-
for (const op of ops) {
|
|
195
|
-
if (!op.o && !op.p) {
|
|
196
|
-
if (!appendPath || !appendPatchStreamValue(next, appendPath, op.v)) {
|
|
197
|
-
failed = true;
|
|
198
|
-
break;
|
|
199
|
-
}
|
|
200
|
-
continue;
|
|
201
|
-
}
|
|
202
|
-
if (op.o === "merge" && op.p === "/message/metadata") {
|
|
203
|
-
const anchor = op.v.anchorUserMessageId;
|
|
204
|
-
if (typeof anchor === "string" && anchor.trim()) {
|
|
205
|
-
anchorUserMessageId = anchor;
|
|
206
|
-
}
|
|
207
|
-
continue;
|
|
208
|
-
}
|
|
209
|
-
if (op.o === "append") {
|
|
210
|
-
if (typeof op.p !== "string" || !appendPatchStreamValue(next, op.p, op.v)) {
|
|
211
|
-
failed = true;
|
|
212
|
-
break;
|
|
213
|
-
}
|
|
214
|
-
appendPath = op.p;
|
|
215
|
-
continue;
|
|
216
|
-
}
|
|
217
|
-
if (op.o === "merge") {
|
|
218
|
-
const match = op.p.match(blockMetaPathPattern);
|
|
219
|
-
if (!match)
|
|
220
|
-
continue;
|
|
221
|
-
const streamIndex = Number(match[1]);
|
|
222
|
-
const blockIndex = findBlockByStreamIndex(next, streamIndex);
|
|
223
|
-
const block = blockIndex >= 0 ? next[blockIndex] : undefined;
|
|
224
|
-
if (!block)
|
|
225
|
-
continue;
|
|
226
|
-
block._meta = { ...(block._meta ?? {}), ...op.v };
|
|
227
|
-
continue;
|
|
228
|
-
}
|
|
229
|
-
if (op.o === "replace") {
|
|
230
|
-
const sub = op.p.match(blockSubPathPattern);
|
|
231
|
-
if (sub?.[2] && typeof op.p === "string") {
|
|
232
|
-
const streamIndex = Number(sub[1]);
|
|
233
|
-
const encodedTail = sub[2];
|
|
234
|
-
if (applyReplaceAtBlockSubpath(next, streamIndex, encodedTail, op.v)) {
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
failed = true;
|
|
238
|
-
break;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
if (op.o === "replace" || op.o === "add") {
|
|
242
|
-
const match = op.p.match(blockPathPattern);
|
|
243
|
-
if (!match || !isContentBlock(op.v))
|
|
244
|
-
continue;
|
|
245
|
-
const streamIndex = Number(match[1]);
|
|
246
|
-
const block = cloneBlock(op.v);
|
|
247
|
-
block._meta = { ...(block._meta ?? {}), streamIndex };
|
|
248
|
-
const blockIndex = findBlockForReplacement(next, streamIndex, block);
|
|
249
|
-
if (blockIndex >= 0) {
|
|
250
|
-
next[blockIndex] = block;
|
|
251
|
-
}
|
|
252
|
-
else {
|
|
253
|
-
next.push(block);
|
|
254
|
-
}
|
|
255
|
-
continue;
|
|
256
|
-
}
|
|
257
|
-
if (op.o === "remove") {
|
|
258
|
-
const match = op.p.match(blockPathPattern);
|
|
259
|
-
if (!match)
|
|
260
|
-
continue;
|
|
261
|
-
const blockIndex = findBlockByStreamIndex(next, Number(match[1]));
|
|
262
|
-
if (blockIndex >= 0)
|
|
263
|
-
next.splice(blockIndex, 1);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
return {
|
|
267
|
-
failed,
|
|
268
|
-
contentBlocks: sortBlocksByStreamIndex(next),
|
|
269
|
-
anchorUserMessageId,
|
|
270
|
-
appendPath,
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
export class SessionPatchReducer {
|
|
274
|
-
states = new Map();
|
|
275
|
-
key(input) {
|
|
276
|
-
return `${input.spaceId ?? ""}:${input.sessionId}`;
|
|
277
|
-
}
|
|
278
|
-
get(input) {
|
|
279
|
-
const key = this.key(input);
|
|
280
|
-
return this.states.get(key) ?? createIdleState(input);
|
|
281
|
-
}
|
|
282
|
-
start(input) {
|
|
283
|
-
const state = {
|
|
284
|
-
...this.get(input),
|
|
285
|
-
status: "pending",
|
|
286
|
-
contentBlocks: [],
|
|
287
|
-
anchorUserMessageId: null,
|
|
288
|
-
patchSeq: 0,
|
|
289
|
-
turnId: input.turnId ?? null,
|
|
290
|
-
appendPath: null,
|
|
291
|
-
};
|
|
292
|
-
this.states.set(this.key(input), state);
|
|
293
|
-
return state;
|
|
294
|
-
}
|
|
295
|
-
replaceTurnId(input) {
|
|
296
|
-
const current = this.get(input);
|
|
297
|
-
const state = {
|
|
298
|
-
...current,
|
|
299
|
-
turnId: input.nextTurnId,
|
|
300
|
-
};
|
|
301
|
-
this.states.set(this.key(input), state);
|
|
302
|
-
return state;
|
|
303
|
-
}
|
|
304
|
-
complete(input) {
|
|
305
|
-
const current = this.get(input);
|
|
306
|
-
const state = {
|
|
307
|
-
...current,
|
|
308
|
-
turnId: input.turnId ?? current.turnId,
|
|
309
|
-
status: "completed",
|
|
310
|
-
contentBlocks: [],
|
|
311
|
-
anchorUserMessageId: null,
|
|
312
|
-
};
|
|
313
|
-
this.states.set(this.key(input), state);
|
|
314
|
-
return state;
|
|
315
|
-
}
|
|
316
|
-
fail(input) {
|
|
317
|
-
const current = this.get(input);
|
|
318
|
-
const state = {
|
|
319
|
-
...current,
|
|
320
|
-
turnId: input.turnId ?? current.turnId,
|
|
321
|
-
status: "failed",
|
|
322
|
-
contentBlocks: [],
|
|
323
|
-
anchorUserMessageId: null,
|
|
324
|
-
};
|
|
325
|
-
this.states.set(this.key(input), state);
|
|
326
|
-
return state;
|
|
327
|
-
}
|
|
328
|
-
interrupt(input) {
|
|
329
|
-
const current = this.get(input);
|
|
330
|
-
const state = {
|
|
331
|
-
...current,
|
|
332
|
-
turnId: input.turnId ?? current.turnId,
|
|
333
|
-
status: "interrupted",
|
|
334
|
-
contentBlocks: [],
|
|
335
|
-
anchorUserMessageId: null,
|
|
336
|
-
appendPath: null,
|
|
337
|
-
};
|
|
338
|
-
this.states.set(this.key(input), state);
|
|
339
|
-
return state;
|
|
340
|
-
}
|
|
341
|
-
reset(input) {
|
|
342
|
-
this.states.delete(this.key(input));
|
|
343
|
-
}
|
|
344
|
-
applySnapshot(input) {
|
|
345
|
-
const current = this.get(input);
|
|
346
|
-
const inputTurnId = input.turnId ?? null;
|
|
347
|
-
const currentTurnId = current.turnId;
|
|
348
|
-
const isDifferentKnownTurn = Boolean(currentTurnId && inputTurnId && currentTurnId !== inputTurnId);
|
|
349
|
-
const isTerminalSameTurn = isTerminalPatchStatus(current.status) && Boolean(currentTurnId) && currentTurnId === inputTurnId;
|
|
350
|
-
if (isTerminalSameTurn || (!isDifferentKnownTurn && input.seq < current.patchSeq)) {
|
|
351
|
-
return { applied: false, reason: "duplicate", state: current };
|
|
352
|
-
}
|
|
353
|
-
const state = {
|
|
354
|
-
...current,
|
|
355
|
-
spaceId: input.spaceId ?? current.spaceId ?? null,
|
|
356
|
-
sessionId: input.sessionId,
|
|
357
|
-
status: "streaming",
|
|
358
|
-
contentBlocks: sortBlocksByStreamIndex(input.contentBlocks.map(cloneBlock)),
|
|
359
|
-
anchorUserMessageId: input.anchorUserMessageId ?? current.anchorUserMessageId ?? null,
|
|
360
|
-
patchSeq: input.seq,
|
|
361
|
-
turnId: inputTurnId ?? current.turnId ?? null,
|
|
362
|
-
appendPath: input.appendPath ?? null,
|
|
363
|
-
};
|
|
364
|
-
this.states.set(this.key(input), state);
|
|
365
|
-
return { applied: true, state };
|
|
366
|
-
}
|
|
367
|
-
resetAll() {
|
|
368
|
-
this.states.clear();
|
|
369
|
-
}
|
|
370
|
-
applyEvent(event) {
|
|
371
|
-
return this.applyPatch({
|
|
372
|
-
spaceId: event.spaceId,
|
|
373
|
-
sessionId: event.sessionId,
|
|
374
|
-
turnId: event.payload.turnId,
|
|
375
|
-
seq: event.payload.seq,
|
|
376
|
-
baseSeq: event.payload.baseSeq,
|
|
377
|
-
ops: event.payload.ops,
|
|
378
|
-
anchorUserMessageId: event.payload.anchorUserMessageId,
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
applyPatch(input) {
|
|
382
|
-
const current = this.get(input);
|
|
383
|
-
const currentTurnId = current.turnId;
|
|
384
|
-
const inputTurnId = input.turnId ?? null;
|
|
385
|
-
const isDifferentKnownTurn = Boolean(currentTurnId && inputTurnId && currentTurnId !== inputTurnId);
|
|
386
|
-
const isFreshKnownTurn = isDifferentKnownTurn && input.baseSeq === 0;
|
|
387
|
-
const currentSeq = isFreshKnownTurn ? 0 : current.patchSeq;
|
|
388
|
-
const isSameTurnKeyframe = Boolean(currentTurnId &&
|
|
389
|
-
inputTurnId &&
|
|
390
|
-
currentTurnId === inputTurnId &&
|
|
391
|
-
input.baseSeq === 0 &&
|
|
392
|
-
input.seq >= currentSeq);
|
|
393
|
-
const isTerminalSameTurn = isTerminalPatchStatus(current.status) &&
|
|
394
|
-
Boolean(currentTurnId) &&
|
|
395
|
-
currentTurnId === inputTurnId;
|
|
396
|
-
if (isTerminalSameTurn) {
|
|
397
|
-
return { applied: false, reason: "duplicate", state: current };
|
|
398
|
-
}
|
|
399
|
-
if (isDifferentKnownTurn && !isFreshKnownTurn) {
|
|
400
|
-
return { applied: false, reason: "version_mismatch", state: current };
|
|
401
|
-
}
|
|
402
|
-
if (!isSameTurnKeyframe && input.seq <= currentSeq) {
|
|
403
|
-
return { applied: false, reason: "duplicate", state: current };
|
|
404
|
-
}
|
|
405
|
-
if (!isSameTurnKeyframe && input.baseSeq !== currentSeq) {
|
|
406
|
-
return { applied: false, reason: "version_mismatch", state: current };
|
|
407
|
-
}
|
|
408
|
-
const startingFresh = input.baseSeq === 0 || isFreshKnownTurn || isSameTurnKeyframe;
|
|
409
|
-
const baseBlocks = startingFresh ? [] : current.contentBlocks;
|
|
410
|
-
const patched = applyPatchOpsToBlocks(baseBlocks, input.ops, startingFresh ? null : current.appendPath);
|
|
411
|
-
if (patched.failed) {
|
|
412
|
-
return { applied: false, reason: "version_mismatch", state: current };
|
|
413
|
-
}
|
|
414
|
-
const next = {
|
|
415
|
-
...current,
|
|
416
|
-
spaceId: input.spaceId ?? current.spaceId ?? null,
|
|
417
|
-
sessionId: input.sessionId,
|
|
418
|
-
status: "streaming",
|
|
419
|
-
contentBlocks: patched.contentBlocks,
|
|
420
|
-
anchorUserMessageId: patched.anchorUserMessageId ??
|
|
421
|
-
input.anchorUserMessageId ??
|
|
422
|
-
current.anchorUserMessageId ??
|
|
423
|
-
null,
|
|
424
|
-
patchSeq: input.seq,
|
|
425
|
-
turnId: input.turnId ?? current.turnId ?? null,
|
|
426
|
-
appendPath: patched.appendPath,
|
|
427
|
-
};
|
|
428
|
-
this.states.set(this.key(next), next);
|
|
429
|
-
return { applied: true, state: next };
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
export const createSessionPatchReducer = () => new SessionPatchReducer();
|
package/dist/transport.d.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { CohubEnvironment } from "./environment.js";
|
|
2
|
-
import type { WebsocketClientOptions } from "./websocket.js";
|
|
3
|
-
export type Fetch = typeof globalThis.fetch;
|
|
4
|
-
type RequestInitWithFetch = RequestInit & {
|
|
5
|
-
fetch?: Fetch;
|
|
6
|
-
};
|
|
7
|
-
export type RawHttpResponse = {
|
|
8
|
-
response: Response;
|
|
9
|
-
blob(): Promise<Blob>;
|
|
10
|
-
arrayBuffer(): Promise<ArrayBuffer>;
|
|
11
|
-
text(): Promise<string>;
|
|
12
|
-
};
|
|
13
|
-
export type CohubClientOptions = {
|
|
14
|
-
env?: CohubEnvironment;
|
|
15
|
-
baseUrl?: string;
|
|
16
|
-
getAccessToken?: () => Promise<string | null> | string | null;
|
|
17
|
-
onUnauthorized?: () => Promise<void> | void;
|
|
18
|
-
setStoredAuthToken?: (token: string) => void;
|
|
19
|
-
clearStoredAuthToken?: () => void;
|
|
20
|
-
fetch?: Fetch;
|
|
21
|
-
websocket?: WebsocketClientOptions;
|
|
22
|
-
};
|
|
23
|
-
export declare class HttpError extends Error {
|
|
24
|
-
readonly status: number;
|
|
25
|
-
readonly body: unknown;
|
|
26
|
-
constructor(message: string, status: number, body: unknown);
|
|
27
|
-
}
|
|
28
|
-
export declare class HttpTransport {
|
|
29
|
-
private readonly baseUrl;
|
|
30
|
-
private readonly fetcher;
|
|
31
|
-
private readonly getAccessToken?;
|
|
32
|
-
private readonly onUnauthorized?;
|
|
33
|
-
constructor(options?: CohubClientOptions);
|
|
34
|
-
private withAuthorization;
|
|
35
|
-
private send;
|
|
36
|
-
request<T>(path: string, init?: RequestInitWithFetch): Promise<T>;
|
|
37
|
-
raw(path: string, init?: RequestInitWithFetch): Promise<RawHttpResponse>;
|
|
38
|
-
blob(path: string, init?: RequestInitWithFetch): Promise<Blob>;
|
|
39
|
-
}
|
|
40
|
-
export {};
|
package/dist/transport.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { resolveApiBaseUrl } from "./environment.js";
|
|
2
|
-
const responseBodyForError = async (response) => {
|
|
3
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
4
|
-
return contentType.includes("application/json")
|
|
5
|
-
? await response.json().catch(() => null)
|
|
6
|
-
: await response.text().catch(() => response.statusText);
|
|
7
|
-
};
|
|
8
|
-
const messageFromErrorBody = (body, fallback) => typeof body === "string" ? body : JSON.stringify(body ?? null) || fallback;
|
|
9
|
-
export class HttpError extends Error {
|
|
10
|
-
status;
|
|
11
|
-
body;
|
|
12
|
-
constructor(message, status, body) {
|
|
13
|
-
super(message);
|
|
14
|
-
this.name = "HttpError";
|
|
15
|
-
this.status = status;
|
|
16
|
-
this.body = body;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
export class HttpTransport {
|
|
20
|
-
baseUrl;
|
|
21
|
-
fetcher;
|
|
22
|
-
getAccessToken;
|
|
23
|
-
onUnauthorized;
|
|
24
|
-
constructor(options = {}) {
|
|
25
|
-
this.baseUrl = resolveApiBaseUrl(options);
|
|
26
|
-
this.fetcher = options.fetch ?? fetch;
|
|
27
|
-
this.getAccessToken = options.getAccessToken;
|
|
28
|
-
this.onUnauthorized = options.onUnauthorized;
|
|
29
|
-
}
|
|
30
|
-
async withAuthorization(init) {
|
|
31
|
-
const headers = new Headers(init?.headers);
|
|
32
|
-
const token = this.getAccessToken ? await this.getAccessToken() : null;
|
|
33
|
-
if (token) {
|
|
34
|
-
headers.set("Authorization", `Bearer ${token}`);
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
headers.delete("Authorization");
|
|
38
|
-
}
|
|
39
|
-
return {
|
|
40
|
-
...init,
|
|
41
|
-
headers,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
async send(path, init) {
|
|
45
|
-
const fetcher = init?.fetch ?? this.fetcher;
|
|
46
|
-
const url = this.baseUrl ? `${this.baseUrl}${path}` : path;
|
|
47
|
-
const response = await fetcher(url, await this.withAuthorization(init));
|
|
48
|
-
if (response.status === 401) {
|
|
49
|
-
await this.onUnauthorized?.();
|
|
50
|
-
throw new HttpError("unauthorized", 401, null);
|
|
51
|
-
}
|
|
52
|
-
if (!response.ok) {
|
|
53
|
-
const body = await responseBodyForError(response);
|
|
54
|
-
throw new HttpError(messageFromErrorBody(body, response.statusText), response.status, body);
|
|
55
|
-
}
|
|
56
|
-
return response;
|
|
57
|
-
}
|
|
58
|
-
async request(path, init) {
|
|
59
|
-
const response = await this.send(path, init);
|
|
60
|
-
if (response.status === 204) {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
return response.json();
|
|
64
|
-
}
|
|
65
|
-
async raw(path, init) {
|
|
66
|
-
const response = await this.send(path, init);
|
|
67
|
-
return {
|
|
68
|
-
response,
|
|
69
|
-
blob: () => response.blob(),
|
|
70
|
-
arrayBuffer: () => response.arrayBuffer(),
|
|
71
|
-
text: () => response.text(),
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
async blob(path, init) {
|
|
75
|
-
const raw = await this.raw(path, init);
|
|
76
|
-
return raw.blob();
|
|
77
|
-
}
|
|
78
|
-
}
|