From 6a34be416b355e197aa2c1efe4b2f110abe47de4 Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Fri, 23 Oct 2026 23:15:46 +0800 Subject: [PATCH] refactor(adapters): remove redundant error and provider facades --- .../ReconstructionCoverageService.ts | 8 +++-- .../ReconstructionObligationLedgerRequest.ts | 8 +++-- .../investigation/EvidenceLedger.ts | 14 ++++++-- .../managed/ManagedMemberComparisonService.ts | 8 +++-- .../managed/ManagedReconstructionService.ts | 8 +++-- src/application/workflowInputError.ts | 12 ------- src/cli/browserAdvancedCommands.ts | 21 ++++++----- src/cli/browserCliError.ts | 10 ++++++ src/cli/browserCommands.ts | 36 +++++++++---------- src/cli/webRuntimeCommands.ts | 2 +- src/cliBrowserContext.ts | 16 --------- src/server/mcpClientMetadata.ts | 8 +---- 12 files changed, 75 insertions(+), 76 deletions(-) delete mode 100644 src/application/workflowInputError.ts create mode 100644 src/cli/browserCliError.ts delete mode 100644 src/cliBrowserContext.ts diff --git a/src/application/ReconstructionCoverageService.ts b/src/application/ReconstructionCoverageService.ts index c391bedb5a..906474b5f5 100644 --- a/src/application/ReconstructionCoverageService.ts +++ b/src/application/ReconstructionCoverageService.ts @@ -8,7 +8,7 @@ import { type ReconstructionClosureResult, } from "../domain/reconstructionCoverage.js"; import { err, type Result } from "../domain/result.js"; -import { requestInputError } from "./workflowInputError.js"; +import { analysisInputErrorFromIssues } from "../domain/inputIssueProjection.js"; const OPERATION = "evaluate_reconstruction_coverage"; const requestEnvelopeSchema = @@ -23,7 +23,11 @@ export const evaluateReconstructionCoverage = ( ): Result => { const parsed = requestEnvelopeSchema.safeParse(rawInput); if (!parsed.success) - return err(requestInputError(OPERATION, parsed.error, rawInput)); + return err( + analysisInputErrorFromIssues(OPERATION, parsed.error.issues, rawInput, { + cause: parsed.error, + }), + ); const coverage = readReconstructionCoverageData(parsed.data.coverage, [ "coverage", ]); diff --git a/src/application/ReconstructionObligationLedgerRequest.ts b/src/application/ReconstructionObligationLedgerRequest.ts index 283df620e0..6a568f70a4 100644 --- a/src/application/ReconstructionObligationLedgerRequest.ts +++ b/src/application/ReconstructionObligationLedgerRequest.ts @@ -13,7 +13,7 @@ import { type ReconstructionObligationManifest, } from "../domain/reconstructionObligationLedgerSchemas.js"; import { err, ok, type Result } from "../domain/result.js"; -import { requestInputError } from "./workflowInputError.js"; +import { analysisInputErrorFromIssues } from "../domain/inputIssueProjection.js"; const OPERATION = "build_reconstruction_obligation_ledger"; const requestSchema = reconstructionObligationLedgerInputSchema.extend({ @@ -38,7 +38,11 @@ export const resolveReconstructionObligationLedgerRequest = ( ): Result => { const frame = requestSchema.safeParse(input); if (!frame.success) - return err(requestInputError(OPERATION, frame.error, input)); + return err( + analysisInputErrorFromIssues(OPERATION, frame.error.issues, input, { + cause: frame.error, + }), + ); const bundle = readEvidenceBundle(frame.data.evidence_bundle); if (!bundle.ok) return bundle; const records = new Map( diff --git a/src/application/investigation/EvidenceLedger.ts b/src/application/investigation/EvidenceLedger.ts index 6691c5ccf2..338aa8a534 100644 --- a/src/application/investigation/EvidenceLedger.ts +++ b/src/application/investigation/EvidenceLedger.ts @@ -25,7 +25,7 @@ import { import { err, ok, type Result } from "../../domain/result.js"; import { compareUnicodeCodePoints } from "../../domain/unicodeCodePointOrder.js"; import type { UnknownPage, UnknownQuery } from "./InvestigationRecordPort.js"; -import { requestInputError } from "../workflowInputError.js"; +import { analysisInputErrorFromIssues } from "../../domain/inputIssueProjection.js"; type EvidenceLedgerFailure = EvidenceIntegrityError; type RecordResult = Result<"added" | "duplicate", EvidenceLedgerFailure>; @@ -224,7 +224,11 @@ export class EvidenceLedger { ); } catch (cause: unknown) { if (!(cause instanceof z.ZodError)) throw cause; - return err(requestInputError("record_unknown", cause, input)); + return err( + analysisInputErrorFromIssues("record_unknown", cause.issues, input, { + cause, + }), + ); } if (this.#unknownHeads.has(unknown.unknown_id)) return err(new UnknownRegistryError("already-exists")); @@ -306,7 +310,11 @@ export class EvidenceLedger { ); } catch (cause: unknown) { if (!(cause instanceof z.ZodError)) throw cause; - return err(requestInputError("update_unknown", cause, input)); + return err( + analysisInputErrorFromIssues("update_unknown", cause.issues, input, { + cause, + }), + ); } const authenticated = readLedgerEvidence( mutationEvidence, diff --git a/src/application/managed/ManagedMemberComparisonService.ts b/src/application/managed/ManagedMemberComparisonService.ts index 7d761d7a24..eae9229858 100644 --- a/src/application/managed/ManagedMemberComparisonService.ts +++ b/src/application/managed/ManagedMemberComparisonService.ts @@ -25,7 +25,7 @@ import { MANAGED_STATIC_PROVIDER, MANAGED_WORKFLOW_PROVIDER, } from "../../domain/investigationProviders.js"; -import { requestInputError } from "../workflowInputError.js"; +import { analysisInputErrorFromIssues } from "../../domain/inputIssueProjection.js"; const managedMemberComparisonRequestSchema = z.strictObject({ left: z.unknown(), @@ -45,7 +45,11 @@ export const executeManagedMemberComparison = ( const operation = "compare_managed_members"; const request = managedMemberComparisonRequestSchema.safeParse(input); if (!request.success) - return err(requestInputError(operation, request.error, input)); + return err( + analysisInputErrorFromIssues(operation, request.error.issues, input, { + cause: request.error, + }), + ); const left = readManagedMemberEvidence(request.data.left, "left"); if (!left.ok) return left; const right = readManagedMemberEvidence(request.data.right, "right"); diff --git a/src/application/managed/ManagedReconstructionService.ts b/src/application/managed/ManagedReconstructionService.ts index 0c1719aa50..03f5786d7a 100644 --- a/src/application/managed/ManagedReconstructionService.ts +++ b/src/application/managed/ManagedReconstructionService.ts @@ -10,7 +10,7 @@ import { } from "../../domain/managed/managedReconstruction.js"; import { err, ok, type Result } from "../../domain/result.js"; import { MANAGED_WORKFLOW_PROVIDER } from "../../domain/investigationProviders.js"; -import { requestInputError } from "../workflowInputError.js"; +import { analysisInputErrorFromIssues } from "../../domain/inputIssueProjection.js"; const OPERATION = "import_managed_reconstruction" as const; @@ -20,7 +20,11 @@ export const resolveManagedReconstructionEvidenceInput = ( ): Result => { const parsed = managedReconstructionImportRequestSchema.safeParse(rawInput); if (!parsed.success) - return err(requestInputError(OPERATION, parsed.error, rawInput)); + return err( + analysisInputErrorFromIssues(OPERATION, parsed.error.issues, rawInput, { + cause: parsed.error, + }), + ); return resolveManagedReconstructionImport(parsed.data); }; diff --git a/src/application/workflowInputError.ts b/src/application/workflowInputError.ts deleted file mode 100644 index cd3cc73ed4..0000000000 --- a/src/application/workflowInputError.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { z } from "zod"; - -import type { AnalysisInputError } from "../domain/analysisErrorCore.js"; -import { analysisInputErrorFromIssues } from "../domain/inputIssueProjection.js"; - -/** Project schema issues of the raw request onto their request paths. */ -export const requestInputError = ( - operation: string, - cause: z.ZodError, - input: unknown, -): AnalysisInputError => - analysisInputErrorFromIssues(operation, cause.issues, input, { cause }); diff --git a/src/cli/browserAdvancedCommands.ts b/src/cli/browserAdvancedCommands.ts index d1b2c61a33..f54fa2e783 100644 --- a/src/cli/browserAdvancedCommands.ts +++ b/src/cli/browserAdvancedCommands.ts @@ -1,6 +1,7 @@ import { Cli, z } from "incur"; -import { browserContext, browserCliError } from "../cliBrowserContext.js"; +import { browserCliError } from "./browserCliError.js"; +import { createBrowserObservationProvider } from "../composition/browserObservation.js"; import { browserScopeOptions, selectedCommandTimeout, @@ -71,7 +72,7 @@ const registerWebMcp = ( run: ({ args, options }) => withCommandCancellation((signal) => logCliCommand(logger, "discover-webmcp-tools", async () => { - const context = browserContext(); + const provider = createBrowserObservationProvider(); const input = { cdp_endpoint: args.endpoint, allowed_origins: options.allowedOrigins, @@ -86,14 +87,13 @@ const registerWebMcp = ( projectInputIssues(parsed.error.issues, input), ); return await finishAnalysisCommand( - () => - discoverWebMcpTools(context.provider, parsed.data, { signal }), + () => discoverWebMcpTools(provider, parsed.data, { signal }), { close: async () => { - await context.provider.close?.(); + await provider.close?.(); }, }, - context.provider.identity().id, + provider.identity().id, "discover_webmcp_tools", signal, ); @@ -184,7 +184,7 @@ const registerScreenshot = ( run: ({ args, options }) => withCommandCancellation((signal) => logCliCommand(logger, "capture-web-screenshot", async () => { - const context = browserContext(); + const provider = createBrowserObservationProvider(); const input = { cdp_endpoint: args.endpoint, allowed_origins: options.allowedOrigins, @@ -198,14 +198,13 @@ const registerScreenshot = ( projectInputIssues(parsed.error.issues, input), ); return await finishAnalysisCommand( - () => - captureWebScreenshot(context.provider, parsed.data, { signal }), + () => captureWebScreenshot(provider, parsed.data, { signal }), { close: async () => { - await context.provider.close?.(); + await provider.close?.(); }, }, - context.provider.identity().id, + provider.identity().id, "capture_web_screenshot", signal, ); diff --git a/src/cli/browserCliError.ts b/src/cli/browserCliError.ts new file mode 100644 index 0000000000..12d5527b34 --- /dev/null +++ b/src/cli/browserCliError.ts @@ -0,0 +1,10 @@ +import { projectAnalysisError } from "../domain/analysisErrorProjection.js"; +import type { JsonValue } from "../domain/jsonValue.js"; + +/** Project a browser operation failure consistently across CLI command groups. */ +export const browserCliError = ( + error: Parameters[0], +): JsonValue => ({ + error: "Browser observation failed", + ...projectAnalysisError(error), +}); diff --git a/src/cli/browserCommands.ts b/src/cli/browserCommands.ts index b0a6d8d2db..21868d3140 100644 --- a/src/cli/browserCommands.ts +++ b/src/cli/browserCommands.ts @@ -6,7 +6,8 @@ import { deliverCliAnalysisEvidence } from "./analysisEvidenceDelivery.js"; import { projectAnalysisError } from "../domain/analysisErrorProjection.js"; import { Cli, z } from "incur"; -import { browserContext, browserCliError } from "../cliBrowserContext.js"; +import { browserCliError } from "./browserCliError.js"; +import { createBrowserObservationProvider } from "../composition/browserObservation.js"; import { analyzeWebBundle, inspectWebPage, @@ -61,7 +62,7 @@ const registerTargetList = ( run: ({ args, options }) => withCommandCancellation((signal) => logCliCommand(logger, "list-browser-targets", async () => { - const context = browserContext(); + const provider = createBrowserObservationProvider(); const input = { cdp_endpoint: args.endpoint, allowed_origins: options.allowedOrigins, @@ -76,13 +77,13 @@ const registerTargetList = ( ), ); return await finishAnalysisCommand( - () => listBrowserTargets(context.provider, parsed.data, { signal }), + () => listBrowserTargets(provider, parsed.data, { signal }), { close: async () => { - await context.provider.close?.(); + await provider.close?.(); }, }, - context.provider.identity().id, + provider.identity().id, "list_browser_targets", signal, ); @@ -108,7 +109,7 @@ const registerPageInspection = ( run: ({ args, options }) => withCommandCancellation((signal) => logCliCommand(logger, "inspect-web-page", async () => { - const context = browserContext(); + const provider = createBrowserObservationProvider(); const input = { cdp_endpoint: args.endpoint, allowed_origins: options.allowedOrigins, @@ -133,13 +134,13 @@ const registerPageInspection = ( ), ); return await finishAnalysisCommand( - () => inspectWebPage(context.provider, parsed.data, { signal }), + () => inspectWebPage(provider, parsed.data, { signal }), { close: async () => { - await context.provider.close?.(); + await provider.close?.(); }, }, - context.provider.identity().id, + provider.identity().id, "inspect_web_page", signal, ); @@ -184,7 +185,7 @@ const registerBundleAnalysis = ( options, ); if (!delivery.ok) return projectAnalysisError(delivery.error); - const context = browserContext(); + const provider = createBrowserObservationProvider(); const input = { cdp_endpoint: args.endpoint, allowed_origins: options.allowedOrigins, @@ -219,14 +220,13 @@ const registerBundleAnalysis = ( ); return deliverCliAnalysisEvidence({ ...delivery.value, - run: () => - analyzeWebBundle(context.provider, parsed.data, { signal }), + run: () => analyzeWebBundle(provider, parsed.data, { signal }), service: { close: async () => { - await context.provider.close?.(); + await provider.close?.(); }, }, - providerId: context.provider.identity().id, + providerId: provider.identity().id, operation: "analyze_web_bundle", signal, }); @@ -254,7 +254,7 @@ const registerObservationSession = ( run: ({ args, options }) => withCommandCancellation((signal) => logCliCommand(logger, "observe-web-session", async () => { - const context = browserContext(); + const provider = createBrowserObservationProvider(); const input = { cdp_endpoint: args.endpoint, allowed_origins: options.allowedOrigins, @@ -272,13 +272,13 @@ const registerObservationSession = ( ), ); return await finishAnalysisCommand( - () => observeWebSession(context.provider, parsed.data, { signal }), + () => observeWebSession(provider, parsed.data, { signal }), { close: async () => { - await context.provider.close?.(); + await provider.close?.(); }, }, - context.provider.identity().id, + provider.identity().id, "observe_web_session", signal, ); diff --git a/src/cli/webRuntimeCommands.ts b/src/cli/webRuntimeCommands.ts index f7be47e950..cb7d3e0b0f 100644 --- a/src/cli/webRuntimeCommands.ts +++ b/src/cli/webRuntimeCommands.ts @@ -1,6 +1,6 @@ import { Cli, z } from "incur"; import { createWebRuntimeService } from "../composition/webRuntime.js"; -import { browserCliError } from "../cliBrowserContext.js"; +import { browserCliError } from "./browserCliError.js"; import { browserScopeOptions, observationDuration, diff --git a/src/cliBrowserContext.ts b/src/cliBrowserContext.ts deleted file mode 100644 index bd5169e6bc..0000000000 --- a/src/cliBrowserContext.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { createBrowserObservationProvider } from "./composition/browserObservation.js"; -import { projectAnalysisError } from "./domain/analysisErrorProjection.js"; -import type { JsonValue } from "./domain/jsonValue.js"; - -/** Build the passive browser provider; scope is supplied on each request. */ -export const browserContext = () => ({ - provider: createBrowserObservationProvider(), -}); - -/** Project a browser operation failure consistently across CLI command groups. */ -export const browserCliError = ( - error: Parameters[0], -): JsonValue => ({ - error: "Browser observation failed", - ...projectAnalysisError(error), -}); diff --git a/src/server/mcpClientMetadata.ts b/src/server/mcpClientMetadata.ts index e14cfdb0c9..a3ac138bf0 100644 --- a/src/server/mcpClientMetadata.ts +++ b/src/server/mcpClientMetadata.ts @@ -28,7 +28,7 @@ export const mcpClientMetadata = ( // The SDK deprecates these accessors only in favor of the envelope, which // 2025-era requests do not carry; they still return initialize values. const value = (key: string, initialized: () => unknown): unknown => - envelope === undefined ? initialized() : mcpEnvelopeValue(envelope, key); + envelope === undefined ? initialized() : Reflect.get(envelope, key); const client = implementation( value(CLIENT_INFO_META_KEY, () => connection.getClientVersion()), ); @@ -46,12 +46,6 @@ export const mcpClientMetadata = ( }; }; -/** Read an SDK-defined metadata key from the SDK's currently opaque envelope type. */ -export const mcpEnvelopeValue = ( - envelope: ServerContext["mcpReq"]["envelope"], - key: string, -): unknown => (envelope === undefined ? undefined : Reflect.get(envelope, key)); - const implementation = (value: unknown): ConnectedClientIdentity | undefined => isRecord(value) && typeof value.name === "string" &&