fix(mcp): isolate optional observation adapter failures (#838)

This commit is contained in:
N0zoM1z0 authored and GitHub committed 2026-10-07 11:45:17 +08:00
1 parent 78f4848d70
commit be3cfbffdf
31 files changed
+741 -102

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
import type { BrowserObservationPort } from "../application/BrowserObservationPort.js";
import { CdpBrowserProvider } from "../browser/CdpBrowserProvider.js";
/** Construct a fresh provider without opening a target or acquiring an engine. */
export const createBrowserObservationProvider = (): BrowserObservationPort =>
new CdpBrowserProvider();
+6
View File
@@ -0,0 +1,6 @@
import type { BrowserScenarioCapturePort } from "../application/BrowserScenarioCapturePort.js";
import { PlaywrightBrowserScenarioProvider } from "../browser/PlaywrightBrowserScenarioProvider.js";
/** Construct a fresh provider without opening a target or acquiring an engine. */
export const createBrowserScenarioProvider = (): BrowserScenarioCapturePort =>
new PlaywrightBrowserScenarioProvider();
+6
View File
@@ -0,0 +1,6 @@
import type { ElectronObservationPort } from "../application/ElectronObservationPort.js";
import { CdpElectronProvider } from "../browser/CdpElectronProvider.js";
/** Construct a fresh provider without opening a target or acquiring an engine. */
export const createElectronObservationProvider = (): ElectronObservationPort =>
new CdpElectronProvider();
+6
View File
@@ -0,0 +1,6 @@
import type { ElectronActiveObservationPort } from "../application/ElectronActiveObservationPort.js";
import { PlaywrightElectronActiveProvider } from "../browser/PlaywrightElectronActiveProvider.js";
/** Construct a fresh provider without opening a target or acquiring an engine. */
export const createElectronScenarioProvider =
(): ElectronActiveObservationPort => new PlaywrightElectronActiveProvider();
@@ -0,0 +1,6 @@
import type { JavaScriptRuntimeObservationPort } from "../application/JavaScriptRuntimeObservationPort.js";
import { V8InspectorProvider } from "../browser/V8InspectorProvider.js";
/** Construct a fresh provider without opening a target or acquiring an engine. */
export const createJavaScriptRuntimeObservationProvider =
(): JavaScriptRuntimeObservationPort => new V8InspectorProvider();
@@ -0,0 +1,97 @@
import type {
OptionalObservationProviders,
OptionalProviderLoadFailure,
OptionalProviderLoadResult,
} from "../application/OptionalObservationProviders.js";
import {
CDP_BROWSER_PROVIDER_IDENTITY,
PLAYWRIGHT_BROWSER_SCENARIO_PROVIDER_IDENTITY,
CDP_ELECTRON_PROVIDER_IDENTITY,
PLAYWRIGHT_ELECTRON_ACTIVE_PROVIDER_IDENTITY,
V8_INSPECTOR_PROVIDER_IDENTITY,
} from "../browser/providerIdentities.js";
import { err, ok, type Result } from "../domain/result.js";
/** Precisely typed startup factories for the five existing observation ports. */
export type OptionalObservationFactories = {
readonly [Port in keyof OptionalObservationProviders]-?: () => Promise<
NonNullable<OptionalObservationProviders[Port]>
>;
};
const productionFactories: OptionalObservationFactories = {
browserObservation: async () =>
(
await import("./browserObservation.js")
).createBrowserObservationProvider(),
browserScenarioCapture: async () =>
(await import("./browserScenario.js")).createBrowserScenarioProvider(),
electronObservation: async () =>
(
await import("./electronObservation.js")
).createElectronObservationProvider(),
electronActiveObservation: async () =>
(await import("./electronScenario.js")).createElectronScenarioProvider(),
javascriptRuntimeObservation: async () =>
(
await import("./javascriptRuntimeObservation.js")
).createJavaScriptRuntimeObservationProvider(),
};
const loadPort = async <Port>(
factory: () => Promise<Port>,
providerId: string,
): Promise<Result<Port, OptionalProviderLoadFailure>> => {
try {
return ok(await factory());
} catch (cause: unknown) {
return err({
providerId,
reason: cause instanceof Error ? cause.message : String(cause),
});
}
};
/** Load each adapter independently, retaining healthy peers and exact failures. */
export const loadOptionalObservationProviders = async (
factories: OptionalObservationFactories = productionFactories,
): Promise<OptionalProviderLoadResult> => {
const [browser, scenario, electron, electronActive, runtime] =
await Promise.all([
loadPort(factories.browserObservation, CDP_BROWSER_PROVIDER_IDENTITY.id),
loadPort(
factories.browserScenarioCapture,
PLAYWRIGHT_BROWSER_SCENARIO_PROVIDER_IDENTITY.id,
),
loadPort(
factories.electronObservation,
CDP_ELECTRON_PROVIDER_IDENTITY.id,
),
loadPort(
factories.electronActiveObservation,
PLAYWRIGHT_ELECTRON_ACTIVE_PROVIDER_IDENTITY.id,
),
loadPort(
factories.javascriptRuntimeObservation,
V8_INSPECTOR_PROVIDER_IDENTITY.id,
),
]);
return {
...(browser.ok ? { browserObservation: browser.value } : {}),
...(scenario.ok ? { browserScenarioCapture: scenario.value } : {}),
...(electron.ok ? { electronObservation: electron.value } : {}),
...(electronActive.ok
? { electronActiveObservation: electronActive.value }
: {}),
...(runtime.ok ? { javascriptRuntimeObservation: runtime.value } : {}),
optionalProviderLoadFailures: {
...(browser.ok ? {} : { browserObservation: browser.error }),
...(scenario.ok ? {} : { browserScenarioCapture: scenario.error }),
...(electron.ok ? {} : { electronObservation: electron.error }),
...(electronActive.ok
? {}
: { electronActiveObservation: electronActive.error }),
...(runtime.ok ? {} : { javascriptRuntimeObservation: runtime.error }),
},
};
};