import { Client, Connection } from "@temporalio/client"; import type { WorkbenchActivityConfig, WorkbenchTemporalGateway, WorkbenchTurnInput } from "./contracts.ts"; export function createWorkbenchTemporalGateway(options: { address: string; namespace: string; taskQueue: string; activity: WorkbenchActivityConfig }): WorkbenchTemporalGateway { if (!options.address) throw codedError("workbench_temporal_address_required", "WORKBENCH_TEMPORAL_ADDRESS is required"); let connection: Connection | undefined; let client: Client | undefined; const getClient = async () => { connection ??= await Connection.connect({ address: options.address }); client ??= new Client({ connection, namespace: options.namespace }); return client; }; const start = async (workflowType: string, workflowId: string, input: unknown) => { const temporal = await getClient(); try { const handle = await temporal.workflow.start(workflowType, { taskQueue: options.taskQueue, workflowId, args: [input] }); return { workflowId, workflowRunId: handle.firstExecutionRunId, reused: false }; } catch (error: any) { if (error?.name !== "WorkflowExecutionAlreadyStartedError") throw error; const description = await temporal.workflow.getHandle(workflowId).describe(); return { workflowId, workflowRunId: description.runId, reused: true }; } }; return { submit(input: WorkbenchTurnInput) { return start("workbenchTurnWorkflow", `workbench-turn-${input.traceId}`, { ...input, activity: options.activity }); }, cancel(input) { return start("workbenchCancelWorkflow", `workbench-cancel-${input.traceId}`, { ...input, activity: options.activity }); }, async close() { await connection?.close(); connection = undefined; client = undefined; } }; } function codedError(code: string, message: string) { return Object.assign(new Error(message), { code }); }