mirror of
https://github.com/morluto/rea.git
synced 2026-10-31 20:06:14 +00:00
fix(browser): classify export-web-scripts capture selection failures by cause
export_web_scripts reported a missing capture, a directory selected as
the capture, and an unreadable capture as an artifact io failure ("Script
export failed for <capture> -> <output>: ENOENT ..."), unlike its sibling
inspect_web_network_capture, which already reports these as invalid
input or access_denied.
Read the selected capture in its own step: ENOENT, ENOTDIR and EISDIR
become an invalid capture_path issue, and EACCES or EPERM becomes
access_denied. Failures while writing the export keep their existing
classification.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f4c99ab8a5
commit
8c5e34cd37
2 files changed
+99
-7
No files matched your search
@@ -8,6 +8,7 @@ import { ArtifactReaderFailure } from "../artifacts/ArtifactReader.js";
|
||||
import { publishWebScripts } from "../browser/assets/PublishWebScripts.js";
|
||||
import { selectScriptCapture } from "../browser/assets/ScriptCaptureAdapters.js";
|
||||
import {
|
||||
AnalysisAccessDeniedError,
|
||||
AnalysisCancelledError,
|
||||
AnalysisInputError,
|
||||
AnalysisOutputError,
|
||||
@@ -60,9 +61,9 @@ export const exportWebScriptsValidated = async (
|
||||
);
|
||||
try {
|
||||
options.signal?.throwIfAborted();
|
||||
const bytes = await readFile(input.capture_path, {
|
||||
signal: options.signal,
|
||||
});
|
||||
const read = await readCapture(input.capture_path, options.signal);
|
||||
if (!read.ok) return read;
|
||||
const bytes = read.value;
|
||||
const loaded = parseCapture(bytes);
|
||||
if (!loaded.ok) return loaded;
|
||||
options.signal?.throwIfAborted();
|
||||
@@ -142,6 +143,40 @@ export const exportWebScriptsValidated = async (
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Read the caller-selected capture. A missing, non-file or unreadable
|
||||
* selection is a caller or host-permission failure, not an export failure.
|
||||
*/
|
||||
const readCapture = async (
|
||||
path: string,
|
||||
signal: AbortSignal | undefined,
|
||||
): Promise<Result<Buffer, AnalysisError>> => {
|
||||
try {
|
||||
return ok(await readFile(path, { signal }));
|
||||
} catch (cause: unknown) {
|
||||
const code =
|
||||
cause instanceof Error && "code" in cause ? String(cause.code) : "";
|
||||
if (code === "EACCES" || code === "EPERM")
|
||||
return err(
|
||||
new AnalysisAccessDeniedError(OPERATION, path, code, { cause }),
|
||||
);
|
||||
if (code === "ENOENT" || code === "ENOTDIR" || code === "EISDIR")
|
||||
return err(
|
||||
new AnalysisInputError(OPERATION, { cause }, [
|
||||
{
|
||||
path: ["capture_path"],
|
||||
reason: "invalid_value",
|
||||
message:
|
||||
code === "EISDIR"
|
||||
? `Selected capture is a directory, not a file: ${path}`
|
||||
: `Selected capture could not be read (${code}): ${path}`,
|
||||
},
|
||||
]),
|
||||
);
|
||||
throw cause;
|
||||
}
|
||||
};
|
||||
|
||||
const parseCapture = (
|
||||
bytes: Buffer,
|
||||
): Result<ReturnType<typeof selectScriptCapture>, AnalysisError> => {
|
||||
|
||||
Reference in new issue
Block a user