Files
rea/src/application/ElectronActiveObservationService.ts
T
morluto 735c10059c refactor(domain): split error taxonomy into thematic modules (#636)
Move each error family out of domain/errors.ts into its own module
(base, core, provider selection/adapter, browser observation,
artifact, evidence, unknown registry, hopper, configuration) and
relocate AnalysisErrorProjection to analysisErrorProjection.
Migrate all 162 importers to the owning modules and delete
errors.ts. No re-export shims; behavior is unchanged.
2026-10-06 05:57:38 +08:00

86 lines
2.8 KiB
TypeScript

import { dirname } from "node:path";
import { realpath } from "node:fs/promises";
import type { ExecutionOptions } from "./AnalysisProvider.js";
import type { ElectronActiveObservationPort } from "./ElectronActiveObservationPort.js";
import {
AnalysisCapabilityUnavailableError,
AnalysisInputError,
} from "../domain/analysisErrorCore.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { Evidence } from "../domain/evidence.js";
import type { ElectronActiveObservationInput } from "../domain/electronActiveObservation.js";
import { err, type Result } from "../domain/result.js";
import { createElectronActiveEvidence } from "./ElectronActiveEvidence.js";
const OPERATION = "capture_electron_scenario" as const;
const PROVIDER_ID = "rea-playwright-electron-active";
type CanonicalElectronActiveObservationInput =
ElectronActiveObservationInput & {
readonly application_root: string;
};
const canonicalizeInput = async (
input: ElectronActiveObservationInput,
): Promise<Result<CanonicalElectronActiveObservationInput, AnalysisError>> => {
try {
const [executablePath, applicationPath] = await Promise.all([
realpath(input.executable_path),
realpath(input.application_path),
]);
const applicationRoot =
input.application_root === undefined
? dirname(applicationPath)
: await realpath(input.application_root);
return {
ok: true,
value: {
...input,
executable_path: executablePath,
application_path: applicationPath,
application_root: applicationRoot,
},
};
} catch (cause: unknown) {
return err(
new AnalysisInputError(OPERATION, { cause }, [
{
path: ["application_path"],
reason: "invalid_format",
message:
"Electron executable, application, and root must resolve to existing paths",
},
]),
);
}
};
/** Canonicalize request paths and execute one provider-owned Electron run. */
export const captureElectronScenario = async (
provider: ElectronActiveObservationPort | undefined,
input: ElectronActiveObservationInput,
options: ExecutionOptions = {},
): Promise<Result<Evidence, AnalysisError>> => {
const canonical = await canonicalizeInput(input);
if (!canonical.ok) return canonical;
if (provider === undefined)
return err(
new AnalysisCapabilityUnavailableError(
PROVIDER_ID,
OPERATION,
"active Electron observation provider is not configured",
),
);
const captured = await provider.capture(canonical.value, options);
return captured.ok
? {
ok: true,
value: createElectronActiveEvidence(
canonical.value,
captured.value,
provider.identity(),
),
}
: captured;
};