@oharness/server 0.7.1 → 0.9.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/browser-pane.d.ts +48 -0
- package/dist/browser-pane.js +185 -0
- package/dist/browser-pane.js.map +1 -0
- package/dist/files.d.ts +40 -1
- package/dist/files.js +94 -3
- package/dist/files.js.map +1 -1
- package/dist/i18n.js +190 -0
- package/dist/i18n.js.map +1 -1
- package/dist/main.js +20 -0
- package/dist/main.js.map +1 -1
- package/dist/page/client/account.d.ts +8 -0
- package/dist/page/client/account.js +1895 -0
- package/dist/page/client/account.js.map +1 -0
- package/dist/page/client/artifacts.d.ts +7 -0
- package/dist/page/client/artifacts.js +767 -0
- package/dist/page/client/artifacts.js.map +1 -0
- package/dist/page/client/base.d.ts +8 -0
- package/dist/page/client/base.js +404 -0
- package/dist/page/client/base.js.map +1 -0
- package/dist/page/client/browser.d.ts +21 -0
- package/dist/page/client/browser.js +906 -0
- package/dist/page/client/browser.js.map +1 -0
- package/dist/page/client/composer.d.ts +8 -0
- package/dist/page/client/composer.js +1714 -0
- package/dist/page/client/composer.js.map +1 -0
- package/dist/page/client/dialogs.d.ts +7 -0
- package/dist/page/client/dialogs.js +724 -0
- package/dist/page/client/dialogs.js.map +1 -0
- package/dist/page/client/events.d.ts +7 -0
- package/dist/page/client/events.js +288 -0
- package/dist/page/client/events.js.map +1 -0
- package/dist/page/client/files.d.ts +7 -0
- package/dist/page/client/files.js +412 -0
- package/dist/page/client/files.js.map +1 -0
- package/dist/page/client/index.d.ts +16 -0
- package/dist/page/client/index.js +50 -0
- package/dist/page/client/index.js.map +1 -0
- package/dist/page/client/panels.d.ts +7 -0
- package/dist/page/client/panels.js +659 -0
- package/dist/page/client/panels.js.map +1 -0
- package/dist/page/client/pickers.d.ts +7 -0
- package/dist/page/client/pickers.js +624 -0
- package/dist/page/client/pickers.js.map +1 -0
- package/dist/page/client/routines.d.ts +6 -0
- package/dist/page/client/routines.js +928 -0
- package/dist/page/client/routines.js.map +1 -0
- package/dist/page/client/shell.d.ts +6 -0
- package/dist/page/client/shell.js +700 -0
- package/dist/page/client/shell.js.map +1 -0
- package/dist/page/client/state.d.ts +7 -0
- package/dist/page/client/state.js +1283 -0
- package/dist/page/client/state.js.map +1 -0
- package/dist/page/client/terminal.d.ts +7 -0
- package/dist/page/client/terminal.js +347 -0
- package/dist/page/client/terminal.js.map +1 -0
- package/dist/page/client/transcript.d.ts +8 -0
- package/dist/page/client/transcript.js +866 -0
- package/dist/page/client/transcript.js.map +1 -0
- package/dist/page/client/usage.d.ts +7 -0
- package/dist/page/client/usage.js +954 -0
- package/dist/page/client/usage.js.map +1 -0
- package/dist/page/style.d.ts +1 -0
- package/dist/page/style.js +3016 -0
- package/dist/page/style.js.map +1 -0
- package/dist/page.js +96 -13871
- package/dist/page.js.map +1 -1
- package/dist/server.d.ts +24 -0
- package/dist/server.js +492 -23
- package/dist/server.js.map +1 -1
- package/dist/terminal.d.ts +34 -0
- package/dist/terminal.js +211 -0
- package/dist/terminal.js.map +1 -0
- package/package.json +9 -8
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ServerResponse } from "node:http";
|
|
2
|
+
import type { BrowserInputEvent, BrowserUseSession } from "@oharness/engine";
|
|
3
|
+
export interface BrowserPaneState {
|
|
4
|
+
/** Whether a browser is actually running. Asking must never start one. */
|
|
5
|
+
running: boolean;
|
|
6
|
+
origin?: string;
|
|
7
|
+
/** Full address for the editable address field. */
|
|
8
|
+
url?: string;
|
|
9
|
+
/** The page's own size, which a frame is a scaled copy of. */
|
|
10
|
+
viewport?: {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
};
|
|
14
|
+
/** Native means the desktop shell embeds the real webContents over the pane. */
|
|
15
|
+
presentation?: "stream" | "native";
|
|
16
|
+
tabs?: Array<{
|
|
17
|
+
id: string;
|
|
18
|
+
url: string;
|
|
19
|
+
title?: string;
|
|
20
|
+
active: boolean;
|
|
21
|
+
}>;
|
|
22
|
+
mode?: "builtin" | "extension";
|
|
23
|
+
policy?: "auto" | "builtin" | "extension";
|
|
24
|
+
/** The built-in browser is on a site the person's own browser has open. */
|
|
25
|
+
importSuggestion?: {
|
|
26
|
+
site: string;
|
|
27
|
+
browser: string;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export declare function browserState(session: BrowserUseSession | undefined): Promise<BrowserPaneState>;
|
|
31
|
+
/**
|
|
32
|
+
* Stream the page as MJPEG until the viewer goes away.
|
|
33
|
+
*
|
|
34
|
+
* A viewer that arrives before any browser has started gets 409 rather than an
|
|
35
|
+
* open stream that never paints: the pane then shows its idle state and asks
|
|
36
|
+
* again later, which is a truer thing to show than a blank frame.
|
|
37
|
+
*/
|
|
38
|
+
export declare function streamFrames(session: BrowserUseSession | undefined, res: ServerResponse, quality?: number): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Translate what the pane saw into what the page should feel.
|
|
41
|
+
*
|
|
42
|
+
* The pane sends coordinates already scaled into the page's own space, because
|
|
43
|
+
* only the pane knows how large it drew the image. Everything else is passed
|
|
44
|
+
* through after being checked — this is model-adjacent input arriving over HTTP,
|
|
45
|
+
* so a malformed body must be a 400 rather than something the browser is asked
|
|
46
|
+
* to interpret.
|
|
47
|
+
*/
|
|
48
|
+
export declare function parseInputEvent(body: unknown): BrowserInputEvent | undefined;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser, as something a person can watch and take over.
|
|
3
|
+
*
|
|
4
|
+
* Frames go out as `multipart/x-mixed-replace` — an MJPEG stream — rather than
|
|
5
|
+
* over the event stream or a socket. Three reasons, in the order they mattered.
|
|
6
|
+
* This server speaks SSE and holds no WebSocket dependency, and adding one for
|
|
7
|
+
* a pane would be the largest change in this feature by far. The page renders
|
|
8
|
+
* the stream by pointing an `<img>` at it, so there is no decode loop to write
|
|
9
|
+
* and nothing to get wrong about dropped frames. And the frames stay binary:
|
|
10
|
+
* base64 through the existing SSE channel would cost a third more bytes and
|
|
11
|
+
* would interleave megabytes of picture with the events that drive the
|
|
12
|
+
* transcript, which is the one stream that must never be held up.
|
|
13
|
+
*
|
|
14
|
+
* Input comes back as ordinary small POSTs, and goes to the same `input` call
|
|
15
|
+
* the tools use. A person and the model therefore reach the page through one
|
|
16
|
+
* path, so there is no second code path to keep in step and no state only one
|
|
17
|
+
* of them can produce.
|
|
18
|
+
*/
|
|
19
|
+
const BOUNDARY = "oharness-frame";
|
|
20
|
+
/** Long enough not to waste bandwidth, short enough to keep an idle image stream alive. */
|
|
21
|
+
const IDLE_PING_MS = 15_000;
|
|
22
|
+
export async function browserState(session) {
|
|
23
|
+
if (!session)
|
|
24
|
+
return { running: false };
|
|
25
|
+
const suggestion = session.loginImportSuggestion?.();
|
|
26
|
+
const state = { ...session.state(), ...(suggestion ? { importSuggestion: suggestion } : {}) };
|
|
27
|
+
if (!state.running)
|
|
28
|
+
return state;
|
|
29
|
+
// The pane is an observer. In particular, polling while two browser_tabs
|
|
30
|
+
// calls are still opening their pages must not create a third blank page.
|
|
31
|
+
// Built-in sessions expose their tabs, so wait until one has actually been
|
|
32
|
+
// adopted before asking helpers whose normal tool-facing contract is to
|
|
33
|
+
// lazily create a page when none exists.
|
|
34
|
+
if (session.paneTabs) {
|
|
35
|
+
const tabs = await session.paneTabs();
|
|
36
|
+
const active = tabs.find((tab) => tab.active);
|
|
37
|
+
if (!active)
|
|
38
|
+
return { ...state, ...(tabs.length ? { tabs } : {}) };
|
|
39
|
+
const viewport = await session.viewport();
|
|
40
|
+
return {
|
|
41
|
+
...state,
|
|
42
|
+
...(active.url ? { url: active.url } : {}),
|
|
43
|
+
...(viewport ? { viewport } : {}),
|
|
44
|
+
...(tabs.length ? { tabs } : {}),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// Third-party Browser Use plugins may not implement paneTabs. Preserve the
|
|
48
|
+
// original fallback for them; their URL/viewport methods define whether a
|
|
49
|
+
// page must be created.
|
|
50
|
+
const [viewport, url] = await Promise.all([session.viewport(), session.url()]);
|
|
51
|
+
return {
|
|
52
|
+
...state,
|
|
53
|
+
...(url ? { url } : {}),
|
|
54
|
+
...(viewport ? { viewport } : {}),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Stream the page as MJPEG until the viewer goes away.
|
|
59
|
+
*
|
|
60
|
+
* A viewer that arrives before any browser has started gets 409 rather than an
|
|
61
|
+
* open stream that never paints: the pane then shows its idle state and asks
|
|
62
|
+
* again later, which is a truer thing to show than a blank frame.
|
|
63
|
+
*/
|
|
64
|
+
export async function streamFrames(session, res, quality = 85) {
|
|
65
|
+
if (!session || !session.state().running) {
|
|
66
|
+
res.writeHead(409, { "content-type": "application/json" });
|
|
67
|
+
res.end(JSON.stringify({ error: "no browser is running" }));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
res.writeHead(200, {
|
|
71
|
+
"content-type": `multipart/x-mixed-replace; boundary=${BOUNDARY}`,
|
|
72
|
+
"cache-control": "no-store, no-transform",
|
|
73
|
+
connection: "keep-alive",
|
|
74
|
+
// Same reason as the event stream: a buffering proxy would hold every
|
|
75
|
+
// frame until the response ended, which for a live stream is never.
|
|
76
|
+
"x-accel-buffering": "no",
|
|
77
|
+
});
|
|
78
|
+
let open = true;
|
|
79
|
+
res.on("close", () => {
|
|
80
|
+
open = false;
|
|
81
|
+
});
|
|
82
|
+
/*
|
|
83
|
+
* Each part is closed by the boundary that opens the next one, so every write
|
|
84
|
+
* emits that boundary too rather than leaving it for the following frame.
|
|
85
|
+
*
|
|
86
|
+
* Without it a still page never appears. The browser reads the part's headers
|
|
87
|
+
* — enough to know the image's size, which is why the element looks correct
|
|
88
|
+
* in the DOM — but will not commit a part it has not seen the end of, so a
|
|
89
|
+
* page that produces one frame and then stops paints nothing at all. That is
|
|
90
|
+
* the common case here, not an edge: an agent opens a page and it sits there.
|
|
91
|
+
*/
|
|
92
|
+
let opened = false;
|
|
93
|
+
const part = (type, body) => {
|
|
94
|
+
if (!open)
|
|
95
|
+
return;
|
|
96
|
+
if (!opened)
|
|
97
|
+
res.write(`--${BOUNDARY}\r\n`);
|
|
98
|
+
res.write(`Content-Type: ${type}\r\nContent-Length: ${body?.length ?? 0}\r\n\r\n`);
|
|
99
|
+
if (body)
|
|
100
|
+
res.write(body);
|
|
101
|
+
res.write(`\r\n--${BOUNDARY}\r\n`);
|
|
102
|
+
opened = true;
|
|
103
|
+
};
|
|
104
|
+
let lastFrame;
|
|
105
|
+
const idle = setInterval(() => {
|
|
106
|
+
// An empty MIME part makes some <img> MJPEG decoders replace the last good
|
|
107
|
+
// frame with a blank image. Repeat the last JPEG instead: it keeps the
|
|
108
|
+
// response alive without changing what the person sees.
|
|
109
|
+
if (lastFrame)
|
|
110
|
+
part("image/jpeg", lastFrame);
|
|
111
|
+
}, IDLE_PING_MS);
|
|
112
|
+
idle.unref?.();
|
|
113
|
+
try {
|
|
114
|
+
for await (const frame of session.frames({ quality })) {
|
|
115
|
+
if (!open)
|
|
116
|
+
break;
|
|
117
|
+
lastFrame = frame;
|
|
118
|
+
part("image/jpeg", frame);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// A browser that closed under the viewer is not an error worth a 500: the
|
|
123
|
+
// stream simply ends and the pane goes back to asking for state.
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
clearInterval(idle);
|
|
127
|
+
if (open)
|
|
128
|
+
res.end();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Translate what the pane saw into what the page should feel.
|
|
133
|
+
*
|
|
134
|
+
* The pane sends coordinates already scaled into the page's own space, because
|
|
135
|
+
* only the pane knows how large it drew the image. Everything else is passed
|
|
136
|
+
* through after being checked — this is model-adjacent input arriving over HTTP,
|
|
137
|
+
* so a malformed body must be a 400 rather than something the browser is asked
|
|
138
|
+
* to interpret.
|
|
139
|
+
*/
|
|
140
|
+
export function parseInputEvent(body) {
|
|
141
|
+
if (typeof body !== "object" || body === null)
|
|
142
|
+
return undefined;
|
|
143
|
+
const record = body;
|
|
144
|
+
const number = (key) => typeof record[key] === "number" && Number.isFinite(record[key]) ? record[key] : undefined;
|
|
145
|
+
const modifiers = number("modifiers") ?? 0;
|
|
146
|
+
if (record["type"] === "text" && typeof record["text"] === "string") {
|
|
147
|
+
return { type: "text", text: record["text"].slice(0, 10_000) };
|
|
148
|
+
}
|
|
149
|
+
if (record["type"] === "key") {
|
|
150
|
+
const action = record["action"];
|
|
151
|
+
if (action !== "down" && action !== "up" && action !== "char")
|
|
152
|
+
return undefined;
|
|
153
|
+
return {
|
|
154
|
+
type: "key",
|
|
155
|
+
action,
|
|
156
|
+
...(typeof record["key"] === "string" ? { key: record["key"] } : {}),
|
|
157
|
+
...(typeof record["code"] === "string" ? { code: record["code"] } : {}),
|
|
158
|
+
...(typeof record["text"] === "string" ? { text: record["text"] } : {}),
|
|
159
|
+
modifiers,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (record["type"] === "mouse") {
|
|
163
|
+
const action = record["action"];
|
|
164
|
+
if (action !== "move" && action !== "down" && action !== "up" && action !== "wheel")
|
|
165
|
+
return undefined;
|
|
166
|
+
const x = number("x");
|
|
167
|
+
const y = number("y");
|
|
168
|
+
if (x === undefined || y === undefined)
|
|
169
|
+
return undefined;
|
|
170
|
+
const button = record["button"];
|
|
171
|
+
return {
|
|
172
|
+
type: "mouse",
|
|
173
|
+
action,
|
|
174
|
+
x,
|
|
175
|
+
y,
|
|
176
|
+
...(button === "left" || button === "right" || button === "middle" ? { button } : {}),
|
|
177
|
+
...(number("clickCount") !== undefined ? { clickCount: number("clickCount") } : {}),
|
|
178
|
+
...(number("deltaX") !== undefined ? { deltaX: number("deltaX") } : {}),
|
|
179
|
+
...(number("deltaY") !== undefined ? { deltaY: number("deltaY") } : {}),
|
|
180
|
+
modifiers,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=browser-pane.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-pane.js","sourceRoot":"","sources":["../src/browser-pane.ts"],"names":[],"mappings":"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"}
|
package/dist/files.d.ts
CHANGED
|
@@ -30,7 +30,9 @@ export declare function within(root: string, target: string): string;
|
|
|
30
30
|
* A directory that cannot be read lists as empty rather than failing: the
|
|
31
31
|
* menu still shows the way back out of it.
|
|
32
32
|
*/
|
|
33
|
-
export declare function browseFiles(root: string, rel?: string
|
|
33
|
+
export declare function browseFiles(root: string, rel?: string, opts?: {
|
|
34
|
+
all?: boolean;
|
|
35
|
+
}): Promise<{
|
|
34
36
|
dir: string;
|
|
35
37
|
parent?: string;
|
|
36
38
|
entries: FileEntry[];
|
|
@@ -46,3 +48,40 @@ export declare function searchFiles(root: string, query: string, limit?: number)
|
|
|
46
48
|
entries: FileEntry[];
|
|
47
49
|
truncated: boolean;
|
|
48
50
|
}>;
|
|
51
|
+
/**
|
|
52
|
+
* What the pane shows by its bytes rather than its text, by extension: the
|
|
53
|
+
* kind of element it goes into, and the type it is served as.
|
|
54
|
+
*
|
|
55
|
+
* Video and audio are the formats Chromium plays without a codec pack; a .mov
|
|
56
|
+
* is usually H.264 inside, which it plays too. A PDF goes to the browser's own
|
|
57
|
+
* viewer.
|
|
58
|
+
*/
|
|
59
|
+
export declare const PREVIEW_MEDIA: Record<string, {
|
|
60
|
+
kind: MediaKind;
|
|
61
|
+
type: string;
|
|
62
|
+
}>;
|
|
63
|
+
export type MediaKind = "image" | "video" | "audio" | "pdf";
|
|
64
|
+
export type FilePreview = {
|
|
65
|
+
path: string;
|
|
66
|
+
size: number;
|
|
67
|
+
kind: "text";
|
|
68
|
+
content: string;
|
|
69
|
+
} | {
|
|
70
|
+
path: string;
|
|
71
|
+
size: number;
|
|
72
|
+
kind: MediaKind | "binary" | "large";
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* One file under `root`, as the files pane shows it.
|
|
76
|
+
*
|
|
77
|
+
* Text comes back whole; an image, a video, a sound or a PDF is only named,
|
|
78
|
+
* so the page fetches its bytes from the raw route into the element that
|
|
79
|
+
* shows it; anything else is described. Unlike
|
|
80
|
+
* the composer's menu this does read contents — it is a viewer the person
|
|
81
|
+
* opened themselves, and it shows them nothing the agent could not.
|
|
82
|
+
*/
|
|
83
|
+
export declare function previewFile(root: string, rel: string): Promise<FilePreview | {
|
|
84
|
+
error: string;
|
|
85
|
+
}>;
|
|
86
|
+
/** A client-supplied path under `root`, or undefined if it climbs out. */
|
|
87
|
+
export declare function resolveFile(root: string, rel: string): string | undefined;
|
package/dist/files.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readdir } from "node:fs/promises";
|
|
1
|
+
import { open, readdir, stat } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
/**
|
|
4
4
|
* Directories that are never what someone is reaching for, and are large
|
|
@@ -16,6 +16,14 @@ const SKIP = new Set([
|
|
|
16
16
|
"__pycache__",
|
|
17
17
|
"venv",
|
|
18
18
|
]);
|
|
19
|
+
/**
|
|
20
|
+
* What the files pane leaves out even when it shows everything.
|
|
21
|
+
*
|
|
22
|
+
* The pane is a tree someone opens one folder at a time, so size is no reason
|
|
23
|
+
* to hide node_modules or a dotfile from it — but git's object store is not a
|
|
24
|
+
* file anybody browses to, and Finder's litter is not the project's.
|
|
25
|
+
*/
|
|
26
|
+
const NEVER_SHOWN = new Set([".git", ".DS_Store"]);
|
|
19
27
|
/** How many directory entries one search may look at before it gives up. */
|
|
20
28
|
const VISIT_BUDGET = 15_000;
|
|
21
29
|
/** How deep a search descends; deeper than this is generated output. */
|
|
@@ -54,7 +62,7 @@ function skip(name) {
|
|
|
54
62
|
* A directory that cannot be read lists as empty rather than failing: the
|
|
55
63
|
* menu still shows the way back out of it.
|
|
56
64
|
*/
|
|
57
|
-
export async function browseFiles(root, rel = "") {
|
|
65
|
+
export async function browseFiles(root, rel = "", opts = {}) {
|
|
58
66
|
const base = path.resolve(root);
|
|
59
67
|
const full = inside(base, rel) ?? base;
|
|
60
68
|
const here = relative(base, full);
|
|
@@ -62,7 +70,7 @@ export async function browseFiles(root, rel = "") {
|
|
|
62
70
|
try {
|
|
63
71
|
const items = await readdir(full, { withFileTypes: true });
|
|
64
72
|
entries = items
|
|
65
|
-
.filter((item) => !skip(item.name))
|
|
73
|
+
.filter((item) => !(opts.all ? NEVER_SHOWN.has(item.name) : skip(item.name)))
|
|
66
74
|
.map((item) => ({
|
|
67
75
|
path: here ? `${here}/${item.name}` : item.name,
|
|
68
76
|
name: item.name,
|
|
@@ -165,4 +173,87 @@ function subsequence(text, needle) {
|
|
|
165
173
|
}
|
|
166
174
|
return score;
|
|
167
175
|
}
|
|
176
|
+
/** Past this a file is described rather than shown: a pane is not an editor. */
|
|
177
|
+
const MAX_PREVIEW_BYTES = 1024 * 1024;
|
|
178
|
+
/** How much of a file is looked at to decide whether it is text. */
|
|
179
|
+
const SNIFF_BYTES = 8000;
|
|
180
|
+
/**
|
|
181
|
+
* What the pane shows by its bytes rather than its text, by extension: the
|
|
182
|
+
* kind of element it goes into, and the type it is served as.
|
|
183
|
+
*
|
|
184
|
+
* Video and audio are the formats Chromium plays without a codec pack; a .mov
|
|
185
|
+
* is usually H.264 inside, which it plays too. A PDF goes to the browser's own
|
|
186
|
+
* viewer.
|
|
187
|
+
*/
|
|
188
|
+
export const PREVIEW_MEDIA = {
|
|
189
|
+
".png": { kind: "image", type: "image/png" },
|
|
190
|
+
".jpg": { kind: "image", type: "image/jpeg" },
|
|
191
|
+
".jpeg": { kind: "image", type: "image/jpeg" },
|
|
192
|
+
".gif": { kind: "image", type: "image/gif" },
|
|
193
|
+
".webp": { kind: "image", type: "image/webp" },
|
|
194
|
+
".avif": { kind: "image", type: "image/avif" },
|
|
195
|
+
".svg": { kind: "image", type: "image/svg+xml" },
|
|
196
|
+
".ico": { kind: "image", type: "image/x-icon" },
|
|
197
|
+
".bmp": { kind: "image", type: "image/bmp" },
|
|
198
|
+
".mp4": { kind: "video", type: "video/mp4" },
|
|
199
|
+
".m4v": { kind: "video", type: "video/mp4" },
|
|
200
|
+
".mov": { kind: "video", type: "video/mp4" },
|
|
201
|
+
".webm": { kind: "video", type: "video/webm" },
|
|
202
|
+
".ogv": { kind: "video", type: "video/ogg" },
|
|
203
|
+
".mp3": { kind: "audio", type: "audio/mpeg" },
|
|
204
|
+
".m4a": { kind: "audio", type: "audio/mp4" },
|
|
205
|
+
".aac": { kind: "audio", type: "audio/aac" },
|
|
206
|
+
".wav": { kind: "audio", type: "audio/wav" },
|
|
207
|
+
".ogg": { kind: "audio", type: "audio/ogg" },
|
|
208
|
+
".oga": { kind: "audio", type: "audio/ogg" },
|
|
209
|
+
".opus": { kind: "audio", type: "audio/ogg" },
|
|
210
|
+
".flac": { kind: "audio", type: "audio/flac" },
|
|
211
|
+
".pdf": { kind: "pdf", type: "application/pdf" },
|
|
212
|
+
};
|
|
213
|
+
/**
|
|
214
|
+
* One file under `root`, as the files pane shows it.
|
|
215
|
+
*
|
|
216
|
+
* Text comes back whole; an image, a video, a sound or a PDF is only named,
|
|
217
|
+
* so the page fetches its bytes from the raw route into the element that
|
|
218
|
+
* shows it; anything else is described. Unlike
|
|
219
|
+
* the composer's menu this does read contents — it is a viewer the person
|
|
220
|
+
* opened themselves, and it shows them nothing the agent could not.
|
|
221
|
+
*/
|
|
222
|
+
export async function previewFile(root, rel) {
|
|
223
|
+
const full = resolveFile(root, rel);
|
|
224
|
+
if (!full)
|
|
225
|
+
return { error: "outside the project" };
|
|
226
|
+
let info;
|
|
227
|
+
try {
|
|
228
|
+
info = await stat(full);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return { error: "no such file" };
|
|
232
|
+
}
|
|
233
|
+
if (!info.isFile())
|
|
234
|
+
return { error: "not a file" };
|
|
235
|
+
const shown = relative(path.resolve(root), full);
|
|
236
|
+
const base = { path: shown, size: info.size };
|
|
237
|
+
const media = PREVIEW_MEDIA[path.extname(full).toLowerCase()];
|
|
238
|
+
if (media)
|
|
239
|
+
return { ...base, kind: media.kind };
|
|
240
|
+
if (info.size > MAX_PREVIEW_BYTES)
|
|
241
|
+
return { ...base, kind: "large" };
|
|
242
|
+
const handle = await open(full, "r");
|
|
243
|
+
try {
|
|
244
|
+
const bytes = await handle.readFile();
|
|
245
|
+
// A NUL near the start is the cheap, reliable tell: no text encoding a
|
|
246
|
+
// source file would use puts one there, and every binary format does.
|
|
247
|
+
if (bytes.subarray(0, SNIFF_BYTES).includes(0))
|
|
248
|
+
return { ...base, kind: "binary" };
|
|
249
|
+
return { ...base, kind: "text", content: bytes.toString("utf8") };
|
|
250
|
+
}
|
|
251
|
+
finally {
|
|
252
|
+
await handle.close();
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/** A client-supplied path under `root`, or undefined if it climbs out. */
|
|
256
|
+
export function resolveFile(root, rel) {
|
|
257
|
+
return inside(path.resolve(root), rel);
|
|
258
|
+
}
|
|
168
259
|
//# sourceMappingURL=files.js.map
|
package/dist/files.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"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"}
|