Files

52 lines
3.5 KiB
TypeScript

import path from "node:path";
import { createCloudWorkbenchApplication } from "./cloud-application.ts";
import { createWorkbenchDispatcher } from "./dispatcher.ts";
import { createNativeTestWorkbenchApplication } from "./native-application.ts";
import { createNativeAgentRunWorkbenchApplication } from "./native-agentrun-application.ts";
import { createNativeTestTemporalGateway } from "./native-temporal.ts";
import { createWorkbenchTemporalGateway } from "./temporal.ts";
import { createWorkbenchKafkaEventPublisher } from "./kafka-event-publisher.ts";
import type { WorkbenchEventPublisher } from "./contracts.ts";
export function workbenchRuntime(env: Record<string, string | undefined> = process.env, options: { eventPublisher?: WorkbenchEventPublisher | null } = {}) {
const mode = String(env.WORKBENCH_MODE ?? "").trim();
if (mode !== "native-test" && mode !== "agentrun-native" && mode !== "temporal") throw codedError("workbench_mode_required", "WORKBENCH_MODE must be native-test, agentrun-native, or temporal");
const stateFile = path.resolve(String(env.WORKBENCH_NATIVE_STATE_FILE ?? ".state/workbench-native/state.json"));
const eventPublisher = mode === "native-test"
? null
: Object.hasOwn(options, "eventPublisher")
? options.eventPublisher ?? null
: createWorkbenchKafkaEventPublisher({ env });
const application = mode === "native-test"
? createNativeTestWorkbenchApplication({ stateFile })
: mode === "agentrun-native"
? createNativeAgentRunWorkbenchApplication({ stateFile, env, eventPublisher })
: createCloudWorkbenchApplication({ baseUrl: String(env.WORKBENCH_CLOUD_API_URL ?? ""), authorization: String(env.WORKBENCH_CLOUD_API_AUTHORIZATION ?? ""), eventPublisher });
const temporalAddress = String(env.WORKBENCH_TEMPORAL_ADDRESS ?? env.TEMPORAL_ADDRESS ?? "");
const temporalNamespace = String(env.WORKBENCH_TEMPORAL_NAMESPACE ?? "unidesk");
const taskQueue = String(env.WORKBENCH_TEMPORAL_TASK_QUEUE ?? "hwlab-v03-workbench");
const activity = mode === "native-test" ? null : {
startToCloseTimeoutMs: requiredPositiveInteger(env.WORKBENCH_ACTIVITY_START_TO_CLOSE_TIMEOUT_MS, "WORKBENCH_ACTIVITY_START_TO_CLOSE_TIMEOUT_MS"),
retryInitialIntervalMs: requiredPositiveInteger(env.WORKBENCH_ACTIVITY_RETRY_INITIAL_INTERVAL_MS, "WORKBENCH_ACTIVITY_RETRY_INITIAL_INTERVAL_MS"),
retryMaximumIntervalMs: requiredPositiveInteger(env.WORKBENCH_ACTIVITY_RETRY_MAXIMUM_INTERVAL_MS, "WORKBENCH_ACTIVITY_RETRY_MAXIMUM_INTERVAL_MS"),
retryMaximumAttempts: requiredPositiveInteger(env.WORKBENCH_ACTIVITY_RETRY_MAXIMUM_ATTEMPTS, "WORKBENCH_ACTIVITY_RETRY_MAXIMUM_ATTEMPTS")
};
const temporal = mode === "native-test" ? createNativeTestTemporalGateway(application) : createWorkbenchTemporalGateway({ address: temporalAddress, namespace: temporalNamespace, taskQueue, activity: activity! });
return {
mode,
stateFile,
temporalAddress,
temporalNamespace,
taskQueue, activity,
eventPublisher,
application,
temporal,
dispatch: createWorkbenchDispatcher({ application, temporal, mode }),
async close() { await temporal.close(); await application.close?.(); }
};
}
function codedError(code: string, message: string) { return Object.assign(new Error(message), { code }); }
function requiredPositiveInteger(value: string | undefined, name: string) { const parsed = Number.parseInt(String(value ?? ""), 10); if (!Number.isSafeInteger(parsed) || parsed <= 0) throw codedError("workbench_temporal_config_invalid", `${name} must be a positive integer`); return parsed; }