refactor: finish browser compat untangle

This commit is contained in:
Peter Steinberger
2026-03-26 22:41:46 +00:00
parent 8ee809f3cc
commit 83ca6fbfc6
266 changed files with 424 additions and 179 deletions

View File

@@ -300,7 +300,7 @@ export const GENERATED_BUNDLED_PLUGIN_METADATA = [
},
{
dirName: "browser",
idHint: "browser-plugin",
idHint: "browser",
source: {
source: "./index.ts",
built: "index.js",

View File

@@ -0,0 +1,58 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { startLazyPluginServiceModule } from "./lazy-service-module.js";
describe("startLazyPluginServiceModule", () => {
afterEach(() => {
delete process.env.OPENCLAW_LAZY_SERVICE_SKIP;
delete process.env.OPENCLAW_LAZY_SERVICE_OVERRIDE;
});
it("starts the default module and returns its stop hook", async () => {
const start = vi.fn(async () => {});
const stop = vi.fn(async () => {});
const handle = await startLazyPluginServiceModule({
loadDefaultModule: async () => ({
startDefault: start,
stopDefault: stop,
}),
startExportNames: ["startDefault"],
stopExportNames: ["stopDefault"],
});
expect(start).toHaveBeenCalledTimes(1);
expect(handle).not.toBeNull();
await handle?.stop();
expect(stop).toHaveBeenCalledTimes(1);
});
it("honors skip env before loading the module", async () => {
process.env.OPENCLAW_LAZY_SERVICE_SKIP = "1";
const loadDefaultModule = vi.fn(async () => ({ startDefault: vi.fn(async () => {}) }));
const handle = await startLazyPluginServiceModule({
skipEnvVar: "OPENCLAW_LAZY_SERVICE_SKIP",
loadDefaultModule,
startExportNames: ["startDefault"],
});
expect(handle).toBeNull();
expect(loadDefaultModule).not.toHaveBeenCalled();
});
it("uses the override module when configured", async () => {
process.env.OPENCLAW_LAZY_SERVICE_OVERRIDE = "virtual:service";
const start = vi.fn(async () => {});
const loadOverrideModule = vi.fn(async () => ({ startOverride: start }));
await startLazyPluginServiceModule({
overrideEnvVar: "OPENCLAW_LAZY_SERVICE_OVERRIDE",
loadDefaultModule: async () => ({ startDefault: vi.fn(async () => {}) }),
loadOverrideModule,
startExportNames: ["startOverride", "startDefault"],
});
expect(loadOverrideModule).toHaveBeenCalledWith("virtual:service");
expect(start).toHaveBeenCalledTimes(1);
});
});

View File

@@ -0,0 +1,50 @@
import { isTruthyEnvValue } from "../infra/env.js";
type LazyServiceModule = Record<string, unknown>;
export type LazyPluginServiceHandle = {
stop: () => Promise<void>;
};
function resolveExport<T>(mod: LazyServiceModule, names: string[]): T | null {
for (const name of names) {
const value = mod[name];
if (typeof value === "function") {
return value as T;
}
}
return null;
}
export async function startLazyPluginServiceModule(params: {
skipEnvVar?: string;
overrideEnvVar?: string;
loadDefaultModule: () => Promise<LazyServiceModule>;
loadOverrideModule?: (specifier: string) => Promise<LazyServiceModule>;
startExportNames: string[];
stopExportNames?: string[];
}): Promise<LazyPluginServiceHandle | null> {
const skipEnvVar = params.skipEnvVar?.trim();
if (skipEnvVar && isTruthyEnvValue(process.env[skipEnvVar])) {
return null;
}
const overrideEnvVar = params.overrideEnvVar?.trim();
const override = overrideEnvVar ? process.env[overrideEnvVar]?.trim() : undefined;
const loadOverrideModule =
params.loadOverrideModule ?? (async (specifier: string) => await import(specifier));
const mod = override ? await loadOverrideModule(override) : await params.loadDefaultModule();
const start = resolveExport<() => Promise<unknown>>(mod, params.startExportNames);
if (!start) {
return null;
}
const stop =
params.stopExportNames && params.stopExportNames.length > 0
? resolveExport<() => Promise<void>>(mod, params.stopExportNames)
: null;
await start();
return {
stop: stop ?? (async () => {}),
};
}