{"version":3,"file":"engine-BjI50-XZ.mjs","names":[],"sources":["../src/tako/app-root.ts","../src/workflows/discovery.ts","../src/tako/socket.ts","../src/workflows/rpc-client.ts","../src/workflows/backoff.ts","../src/workflows/step.ts","../src/workflows/worker.ts","../src/workflows/engine.ts"],"sourcesContent":["import { join } from \"node:path\";\n\nexport const APP_ROOT_ENV = \"TAKO_APP_ROOT\";\nexport const DEFAULT_APP_ROOT = \"src\";\n\nexport function resolveAppRootDir(appDir: string, appRoot?: string): string {\n  const root = (appRoot ?? process.env[APP_ROOT_ENV] ?? DEFAULT_APP_ROOT).trim();\n  if (!root || root === \".\") return appDir;\n  return join(appDir, root);\n}\n","/**\n * Filesystem discovery for the configured workflows directory.\n *\n * Each `<name>.(ts|tsx|js|mjs|mts)` file becomes a workflow named `<name>`.\n * The default export must be either:\n *   - A `WorkflowDefinition` produced by `defineWorkflow(name, opts)` —\n *     handler and opts are read directly from the object.\n *   - A plain function — registered with empty opts.\n *\n * Nested directories are not scanned in v1 — flat structure only.\n */\n\nimport { readdir, stat } from \"node:fs/promises\";\nimport { pathToFileURL } from \"node:url\";\nimport { join, parse } from \"node:path\";\nimport { isWorkflowDefinition, isWorkflowExport } from \"./define\";\nimport type { WorkflowRuntimeOpts } from \"./types\";\nimport type { WorkflowHandler } from \"./worker\";\n\nconst VALID_EXTS = new Set([\".ts\", \".tsx\", \".js\", \".mjs\", \".mts\"]);\n\nexport interface DiscoveredWorkflow {\n  name: string;\n  handler: WorkflowHandler;\n  opts: WorkflowRuntimeOpts;\n}\n\nexport interface WorkflowDiscoveryOptions {\n  /**\n   * Only return workflows assigned to this worker group. Workflows without\n   * `opts.worker` belong to the default group. Omit to return all workflows.\n   */\n  worker?: string;\n}\n\nconst DEFAULT_WORKER_GROUP = \"default\";\n\nexport async function discoverWorkflows(\n  dir: string,\n  opts: WorkflowDiscoveryOptions = {},\n): Promise<DiscoveredWorkflow[]> {\n  const exists = await dirExists(dir);\n  if (!exists) return [];\n\n  const entries = await readdir(dir);\n  const found: DiscoveredWorkflow[] = [];\n  for (const entry of entries) {\n    const parsed = parse(entry);\n    if (!VALID_EXTS.has(parsed.ext)) continue;\n    if (parsed.name.startsWith(\".\") || parsed.name.startsWith(\"_\")) continue;\n\n    const url = pathToFileURL(join(dir, entry)).href;\n    const mod = (await import(/* @vite-ignore */ url)) as Record<string, unknown>;\n    const defaultExport = mod[\"default\"];\n\n    if (isWorkflowExport(defaultExport)) {\n      const def = defaultExport.definition;\n      if (def.name !== parsed.name) {\n        throw new Error(\n          `workflow file '${parsed.name}' exports defineWorkflow('${def.name}', ...); the name must match the file basename`,\n        );\n      }\n      pushIfWorkerMatches(found, { name: def.name, handler: def.handler, opts: def.opts }, opts);\n    } else if (isWorkflowDefinition(defaultExport)) {\n      pushIfWorkerMatches(\n        found,\n        {\n          name: defaultExport.name,\n          handler: defaultExport.handler,\n          opts: defaultExport.opts,\n        },\n        opts,\n      );\n    } else if (typeof defaultExport === \"function\") {\n      pushIfWorkerMatches(\n        found,\n        {\n          name: parsed.name,\n          handler: defaultExport as WorkflowHandler,\n          opts: {},\n        },\n        opts,\n      );\n    } else {\n      throw new Error(\n        `workflow '${parsed.name}' (${entry}) must default-export a defineWorkflow() result or a plain function`,\n      );\n    }\n  }\n  return found;\n}\n\nfunction pushIfWorkerMatches(\n  found: DiscoveredWorkflow[],\n  workflow: DiscoveredWorkflow,\n  opts: WorkflowDiscoveryOptions,\n): void {\n  if (opts.worker === undefined || workflowWorkerGroup(workflow.opts) === opts.worker) {\n    found.push(workflow);\n  }\n}\n\nfunction workflowWorkerGroup(opts: WorkflowRuntimeOpts): string {\n  return opts.worker ?? DEFAULT_WORKER_GROUP;\n}\n\nasync function dirExists(dir: string): Promise<boolean> {\n  try {\n    const s = await stat(dir);\n    return s.isDirectory();\n  } catch {\n    return false;\n  }\n}\n","/**\n * Shared Tako internal unix-socket RPC client.\n *\n * Server-side SDK code (app fetch handlers, workflow bodies, cron ticks)\n * reaches `tako-server` via a single unix socket. Workflow RPCs and\n * server-side channel `.publish()` both land here — no HTTPS, no auth, same\n * trust boundary as the hosting process.\n *\n * Env vars set by the server when spawning an instance or worker:\n *   TAKO_INTERNAL_SOCKET — path to the shared unix socket\n *   TAKO_APP_NAME        — app name used on every command payload\n */\n\nimport { createConnection } from \"node:net\";\nimport type { Socket } from \"node:net\";\nimport { setChannelSocketPublisher } from \"../channels\";\nimport { createLogger } from \"../logger\";\nimport type { ChannelMessage, ChannelPublishInput } from \"../types\";\n\nexport const INTERNAL_SOCKET_ENV = \"TAKO_INTERNAL_SOCKET\";\nexport const APP_NAME_ENV = \"TAKO_APP_NAME\";\n\nexport { TakoError, type TakoErrorCode } from \"./error\";\nimport { TakoError, type TakoErrorCode } from \"./error\";\n\ninterface RpcResponse {\n  status: \"ok\" | \"error\";\n  data?: unknown;\n  message?: string;\n}\n\nconst logger = createLogger(\"sdk.rpc\");\nconst DEFAULT_INTERNAL_SOCKET_POOL_SIZE = 64;\nconst RPC_TIMEOUT_MS = 30_000;\n\ntype ResolveResponse = (value: RpcResponse) => void;\ntype RejectResponse = (reason: unknown) => void;\n\ninterface PendingRpc {\n  cmd: unknown;\n  resolve: ResolveResponse;\n  reject: RejectResponse;\n}\n\nconst internalSocketPools = new Map<string, InternalSocketPool>();\n\n/**\n * Log the raw failure and return a sanitized `TakoError`. Callers throw the\n * returned value; the original error stays on `.cause` for local debugging\n * but never flows to an end user via `.message`. The stable `code` field\n * lets app code branch by failure class.\n */\nfunction wrapSocketError(code: TakoErrorCode, cause: unknown): TakoError {\n  logger.error(\"rpc failed\", { code, error: cause });\n  return new TakoError(code, \"Internal Server Error\", { cause });\n}\n\n/**\n * Look up the `(socketPath, appName)` pair from env. Returns `null` when\n * either var is missing — callers decide whether to fall back (HTTPS for\n * channels) or throw (workflow RPC).\n */\nexport function internalSocketFromEnv(): { socketPath: string; app: string } | null {\n  const envObj = typeof process !== \"undefined\" ? process.env : undefined;\n  if (!envObj) return null;\n  const socketPath = envObj[INTERNAL_SOCKET_ENV];\n  const app = envObj[APP_NAME_ENV];\n  if (!socketPath || !app) return null;\n  return { socketPath, app };\n}\n\n/**\n * Validate the Tako runtime env contract: `TAKO_INTERNAL_SOCKET` and\n * `TAKO_APP_NAME` must be set together or not at all.\n *\n * Called once at SDK init so a misconfigured spawn (one var set, the other\n * missing) crashes the process on boot instead of hiding until the first\n * workflow `.enqueue()` or channel `.publish()`. Both spawners\n * (`tako-server`, `tako-dev-server`) always set the pair, so a half-set\n * state is a platform bug worth failing loud.\n */\nexport function assertInternalSocketEnvConsistency(): void {\n  const envObj = typeof process !== \"undefined\" ? process.env : undefined;\n  if (!envObj) return;\n  const hasSocket = Boolean(envObj[INTERNAL_SOCKET_ENV]);\n  const hasApp = Boolean(envObj[APP_NAME_ENV]);\n  if (hasSocket === hasApp) return;\n  const missing = hasSocket ? APP_NAME_ENV : INTERNAL_SOCKET_ENV;\n  const present = hasSocket ? INTERNAL_SOCKET_ENV : APP_NAME_ENV;\n  throw new Error(\n    `Tako SDK: ${present} is set but ${missing} is missing. ` +\n      `Both env vars must be set together (or neither — when running ` +\n      `outside a Tako-managed process). This usually means the spawner ` +\n      `forgot to inject the full Tako runtime contract.`,\n  );\n}\n\n/**\n * Install a channel publisher that routes `Channel.publish()` calls through\n * the Tako internal socket when `TAKO_INTERNAL_SOCKET` + `TAKO_APP_NAME` are\n * set. Called from the server and worker bootstraps so app/workflow code can\n * publish without an HTTPS round-trip back through the proxy.\n *\n * Returns `true` when a publisher was installed, `false` when the env is\n * missing (e.g. running outside a Tako-managed process).\n */\nexport function installChannelSocketPublisherFromEnv(): boolean {\n  const env = internalSocketFromEnv();\n  if (!env) return false;\n  const { socketPath, app } = env;\n  setChannelSocketPublisher(async <T>(channel: string, message: ChannelPublishInput<T>) => {\n    const result = await callInternal(socketPath, {\n      command: \"channel_publish\",\n      app,\n      channel,\n      payload: message,\n    });\n    return result as ChannelMessage<T>;\n  });\n  return true;\n}\n\n/** Send a single JSONL command and resolve to `data` (or throw on error). */\nexport async function callInternal(socketPath: string, cmd: unknown): Promise<unknown> {\n  const resp = await internalSocketPool(socketPath).call(cmd);\n  if (resp.status === \"error\") {\n    logger.error(\"rpc rejected\", { code: \"TAKO_RPC_ERROR\", message: resp.message });\n    throw new TakoError(\"TAKO_RPC_ERROR\", \"Internal Server Error\", {\n      cause: resp.message ? new Error(resp.message) : undefined,\n    });\n  }\n  return resp.data ?? null;\n}\n\nfunction internalSocketPool(socketPath: string): InternalSocketPool {\n  const existing = internalSocketPools.get(socketPath);\n  if (existing) return existing;\n  const created = new InternalSocketPool(socketPath, DEFAULT_INTERNAL_SOCKET_POOL_SIZE);\n  internalSocketPools.set(socketPath, created);\n  return created;\n}\n\nexport function closeInternalSocketPoolsForTests(): void {\n  for (const pool of internalSocketPools.values()) {\n    pool.close();\n  }\n  internalSocketPools.clear();\n}\n\nclass InternalSocketPool {\n  private readonly idle: RpcConnection[] = [];\n  private readonly active = new Set<RpcConnection>();\n  private readonly pending: PendingRpc[] = [];\n\n  // JSONL responses do not carry request ids, so each socket lane keeps at\n  // most one in-flight RPC. Parallelism comes from bounded lanes; sequential\n  // calls reuse idle sockets instead of reconnecting for every publish/enqueue.\n  constructor(\n    private readonly socketPath: string,\n    private readonly maxConnections: number,\n  ) {}\n\n  call(cmd: unknown): Promise<RpcResponse> {\n    return new Promise<RpcResponse>((resolve, reject) => {\n      this.pending.push({ cmd, resolve, reject });\n      this.drain();\n    });\n  }\n\n  close(): void {\n    while (this.pending.length > 0) {\n      const pending = this.pending.shift();\n      pending?.reject(wrapSocketError(\"TAKO_UNAVAILABLE\", new Error(\"rpc pool closed\")));\n    }\n    for (const conn of this.active) {\n      conn.close();\n    }\n    this.active.clear();\n    this.idle.length = 0;\n  }\n\n  private drain(): void {\n    while (this.pending.length > 0) {\n      const conn = this.nextConnection();\n      if (!conn) return;\n\n      const request = this.pending.shift();\n      if (!request) {\n        this.returnConnection(conn);\n        return;\n      }\n\n      conn\n        .send(request.cmd)\n        .then(request.resolve, request.reject)\n        .finally(() => {\n          this.returnConnection(conn);\n          this.drain();\n        });\n    }\n  }\n\n  private nextConnection(): RpcConnection | null {\n    const idle = this.idle.pop();\n    if (idle) return idle;\n\n    if (this.active.size >= this.maxConnections) {\n      return null;\n    }\n\n    const conn = new RpcConnection(this.socketPath, () => {\n      this.active.delete(conn);\n      const idx = this.idle.indexOf(conn);\n      if (idx !== -1) {\n        this.idle.splice(idx, 1);\n      }\n    });\n    this.active.add(conn);\n    return conn;\n  }\n\n  private returnConnection(conn: RpcConnection): void {\n    if (!conn.closed && this.active.has(conn)) {\n      this.idle.push(conn);\n    }\n  }\n}\n\nclass RpcConnection {\n  private readonly socket: Socket;\n  private readonly connected: Promise<void>;\n  private buf = \"\";\n  private current: PendingRpc | null = null;\n  private timeout: ReturnType<typeof setTimeout> | null = null;\n  closed = false;\n\n  constructor(\n    socketPath: string,\n    private readonly onClose: () => void,\n  ) {\n    this.socket = createConnection(socketPath);\n    this.connected = new Promise<void>((resolve, reject) => {\n      this.socket.once(\"connect\", resolve);\n      this.socket.once(\"error\", reject);\n    });\n\n    this.socket.on(\"data\", (chunk) => this.onData(chunk));\n    this.socket.on(\"error\", (err) => {\n      this.failCurrent(\"TAKO_UNAVAILABLE\", err);\n      this.markClosed();\n    });\n    this.socket.on(\"end\", () => {\n      this.failCurrent(\"TAKO_PROTOCOL\", new Error(\"socket closed without response\"));\n      this.markClosed();\n    });\n    this.socket.on(\"close\", () => this.markClosed());\n  }\n\n  async send(cmd: unknown): Promise<RpcResponse> {\n    if (this.closed) {\n      throw wrapSocketError(\"TAKO_UNAVAILABLE\", new Error(\"socket is closed\"));\n    }\n    if (this.current) {\n      throw wrapSocketError(\"TAKO_PROTOCOL\", new Error(\"socket lane is busy\"));\n    }\n\n    await this.connected.catch((err) => {\n      this.markClosed();\n      throw wrapSocketError(\"TAKO_UNAVAILABLE\", err);\n    });\n\n    if (this.closed) {\n      throw wrapSocketError(\"TAKO_UNAVAILABLE\", new Error(\"socket is closed\"));\n    }\n\n    return new Promise<RpcResponse>((resolve, reject) => {\n      this.current = { cmd, resolve, reject };\n      this.timeout = setTimeout(() => {\n        this.failCurrent(\"TAKO_TIMEOUT\", new Error(\"rpc timed out\"));\n        this.close();\n      }, RPC_TIMEOUT_MS);\n\n      this.socket.write(`${JSON.stringify(cmd)}\\n`, (err) => {\n        if (!err) return;\n        this.failCurrent(\"TAKO_UNAVAILABLE\", err);\n        this.close();\n      });\n    });\n  }\n\n  close(): void {\n    this.markClosed();\n    this.socket.destroy();\n  }\n\n  private onData(chunk: Buffer | string): void {\n    this.buf += typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\");\n    const nl = this.buf.indexOf(\"\\n\");\n    if (nl === -1) return;\n\n    const line = this.buf.slice(0, nl);\n    this.buf = this.buf.slice(nl + 1);\n    const current = this.takeCurrent();\n    if (!current) {\n      this.close();\n      return;\n    }\n\n    try {\n      current.resolve(JSON.parse(line) as RpcResponse);\n    } catch (err) {\n      current.reject(wrapSocketError(\"TAKO_PROTOCOL\", err));\n      this.close();\n    }\n  }\n\n  private failCurrent(code: TakoErrorCode, cause: unknown): void {\n    const current = this.takeCurrent();\n    if (!current) return;\n    current.reject(wrapSocketError(code, cause));\n  }\n\n  private takeCurrent(): PendingRpc | null {\n    const current = this.current;\n    this.current = null;\n    if (this.timeout) {\n      clearTimeout(this.timeout);\n      this.timeout = null;\n    }\n    return current;\n  }\n\n  private markClosed(): void {\n    if (this.closed) return;\n    this.closed = true;\n    this.onClose();\n  }\n}\n","/**\n * WorkflowsClient — single client for all workflow RPCs.\n *\n * Runs in the HTTP app process (for workflow `.enqueue()` and\n * `workflowsEngine.signal()`) and in the worker process (for claim, heartbeat,\n * saveStep, complete, cancel, fail, defer, waitForEvent). The SDK never\n * touches SQLite — tako-server owns the queue file; everything reaches it\n * via the shared internal unix socket at `TAKO_INTERNAL_SOCKET`.\n *\n * Every command carries the app name (from `TAKO_APP_NAME`), so one\n * tako-server socket can route for every deployed app.\n */\n\nimport { APP_NAME_ENV, INTERNAL_SOCKET_ENV, TakoError, callInternal } from \"../tako/socket\";\nimport type { EnqueueOptions } from \"./engine\";\nimport type { Run, RunId, RunStatus, StepState } from \"./types\";\n\n/** Result returned after enqueueing a workflow run. */\nexport interface EnqueueResult {\n  /** Workflow run id. */\n  id: RunId;\n  /** True when `uniqueKey` matched an existing non-terminal run. */\n  deduplicated: boolean;\n}\n\n/**\n * RPC client for workflow operations against the Tako internal socket.\n *\n * Intended for Tako runtime internals; app code should use workflow handles\n * returned by {@link import(\"./define\").defineWorkflow}.\n */\nexport class WorkflowsClient {\n  private readonly socketPath: string;\n  private readonly app: string;\n\n  constructor(socketPath: string, app: string) {\n    this.socketPath = socketPath;\n    this.app = app;\n  }\n\n  /**\n   * Build a client from env vars set by tako-server when spawning the\n   * app/worker process. Returns null when the env vars are absent (outside\n   * of a Tako-managed process) — callers should fall back or error.\n   */\n  static fromEnv(): WorkflowsClient | null {\n    const path = process.env[INTERNAL_SOCKET_ENV];\n    const app = process.env[APP_NAME_ENV];\n    if (!path || !app) return null;\n    return new WorkflowsClient(path, app);\n  }\n\n  /** The app name this client sends on every RPC. */\n  get appName(): string {\n    return this.app;\n  }\n\n  // --- Enqueue / signal: usable from any process ---\n\n  /**\n   * Enqueue a workflow run.\n   *\n   * @param name - Workflow name.\n   * @param payload - JSON-serializable workflow payload.\n   * @param opts - Enqueue options.\n   * @defaultValue opts = {}\n   */\n  async enqueue(name: string, payload: unknown, opts: EnqueueOptions = {}): Promise<EnqueueResult> {\n    const wire: Record<string, unknown> = {};\n    if (opts.runAt !== undefined) wire[\"run_at_ms\"] = opts.runAt.getTime();\n    if (opts.retries !== undefined) wire[\"max_attempts\"] = opts.retries + 1;\n    if (opts.uniqueKey !== undefined && opts.uniqueKey !== null) {\n      wire[\"unique_key\"] = opts.uniqueKey;\n    }\n    const data = await this.call({\n      command: \"enqueue_run\",\n      app: this.app,\n      name,\n      payload: payload ?? null,\n      opts: wire,\n    });\n    const d = data as { id: string; deduplicated: boolean } | null;\n    if (!d || typeof d.id !== \"string\") {\n      throw new TakoError(\"TAKO_PROTOCOL\", \"Internal Server Error\");\n    }\n    return { id: d.id, deduplicated: Boolean(d.deduplicated) };\n  }\n\n  /** Wake workflow runs parked on `ctx.waitFor(eventName)`. */\n  async signal(eventName: string, payload: unknown): Promise<number> {\n    const data = await this.call({\n      command: \"signal\",\n      app: this.app,\n      event_name: eventName,\n      payload: payload ?? null,\n    });\n    const d = data as { woken?: number } | null;\n    return d?.woken ?? 0;\n  }\n\n  // --- Worker-only: registration + run lifecycle ---\n\n  /** Register cron schedules for discovered workflows. */\n  async registerSchedules(schedules: Array<{ name: string; cron: string }>): Promise<void> {\n    await this.call({ command: \"register_schedules\", app: this.app, schedules });\n  }\n\n  /** Claim one pending workflow run for a worker. */\n  async claim(workerId: string, names: string[], leaseMs: number): Promise<Run | null> {\n    const data = await this.call({\n      command: \"claim_run\",\n      app: this.app,\n      worker_id: workerId,\n      names,\n      lease_ms: leaseMs,\n    });\n    if (data === null || data === undefined) return null;\n    return rawToRun(data as RawRun);\n  }\n\n  /** Extend the lease for a running workflow run. */\n  async heartbeat(id: RunId, workerId: string, leaseMs: number): Promise<void> {\n    await this.call({\n      command: \"heartbeat_run\",\n      app: this.app,\n      id,\n      worker_id: workerId,\n      lease_ms: leaseMs,\n    });\n  }\n\n  /** Persist the memoized result for one durable step. */\n  async saveStep(id: RunId, workerId: string, stepName: string, result: unknown): Promise<void> {\n    await this.call({\n      command: \"save_step\",\n      app: this.app,\n      id,\n      worker_id: workerId,\n      step_name: stepName,\n      result: result ?? null,\n    });\n  }\n\n  /** Mark a workflow run as succeeded. */\n  async complete(id: RunId, workerId: string): Promise<void> {\n    await this.call({ command: \"complete_run\", app: this.app, id, worker_id: workerId });\n  }\n\n  /** Mark a workflow run as cancelled. */\n  async cancel(id: RunId, workerId: string, reason?: string | null): Promise<void> {\n    await this.call({\n      command: \"cancel_run\",\n      app: this.app,\n      id,\n      worker_id: workerId,\n      reason: reason ?? null,\n    });\n  }\n\n  /** Mark a workflow run attempt as failed or dead. */\n  async fail(\n    id: RunId,\n    workerId: string,\n    error: string,\n    nextRunAt: Date | null,\n    finalize: boolean,\n  ): Promise<void> {\n    await this.call({\n      command: \"fail_run\",\n      app: this.app,\n      id,\n      worker_id: workerId,\n      error,\n      next_run_at_ms: nextRunAt ? nextRunAt.getTime() : null,\n      finalize,\n    });\n  }\n\n  /** Defer a workflow run until a time, or indefinitely when `wakeAt` is null. */\n  async defer(id: RunId, workerId: string, wakeAt: Date | null): Promise<void> {\n    await this.call({\n      command: \"defer_run\",\n      app: this.app,\n      id,\n      worker_id: workerId,\n      wake_at_ms: wakeAt ? wakeAt.getTime() : null,\n    });\n  }\n\n  /** Park a workflow run until an event or optional timeout. */\n  async waitForEvent(\n    id: RunId,\n    workerId: string,\n    stepName: string,\n    eventName: string,\n    timeoutAt: Date | null,\n  ): Promise<void> {\n    await this.call({\n      command: \"wait_for_event\",\n      app: this.app,\n      id,\n      worker_id: workerId,\n      step_name: stepName,\n      event_name: eventName,\n      timeout_at_ms: timeoutAt ? timeoutAt.getTime() : null,\n    });\n  }\n\n  // --- Internal ---\n\n  private call(cmd: unknown): Promise<unknown> {\n    return callInternal(this.socketPath, cmd);\n  }\n}\n\ninterface RawRun {\n  id: string;\n  name: string;\n  payload: unknown;\n  status: string;\n  attempts: number;\n  max_attempts: number;\n  run_at_ms: number;\n  step_state: StepState;\n}\n\nfunction rawToRun(raw: RawRun): Run {\n  return {\n    id: raw.id,\n    name: raw.name,\n    payload: raw.payload,\n    status: raw.status as RunStatus,\n    attempts: raw.attempts,\n    retries: raw.max_attempts - 1,\n    runAt: raw.run_at_ms,\n    leaseUntil: null,\n    workerId: null,\n    lastError: null,\n    stepState: raw.step_state ?? {},\n    createdAt: 0,\n    uniqueKey: null,\n  };\n}\n","/**\n * Exponential backoff with +/- 20% jitter.\n *\n * `attempts` is the number of attempts that have already completed (>= 1).\n * The first retry (after attempt 1) waits ~base, the next ~2*base, etc.,\n * capped at `max`.\n */\nexport function expBackoffMs(\n  attempts: number,\n  base = 1_000,\n  max = 3_600_000,\n  jitterPct = 0.2,\n): number {\n  const safeAttempts = Math.max(1, attempts);\n  const exp = Math.min(base * 2 ** (safeAttempts - 1), max);\n  const jitter = exp * jitterPct * (Math.random() * 2 - 1);\n  return Math.max(0, Math.round(exp + jitter));\n}\n","/**\n * Step API + workflow control signals.\n *\n * `ctx.run(name, fn, opts?)` memoizes fn's result in the run's steps\n * table. On retry, completed steps return their stored value instead of\n * re-executing. Per-step `retries`/`backoff`/`retry: false` options control\n * in-step retry behavior independent of the run-level retry budget.\n *\n * `ctx.sleep(name, durationMs)` waits durably. Short sleeps are\n * inline; long sleeps (≥INLINE_SLEEP_THRESHOLD_MS) defer the run via\n * `client.defer` so the worker can release.\n *\n * `ctx.waitFor(name, opts?)` parks the run until a matching\n * `workflowsEngine.signal(eventName, payload)` (from `tako.sh/internal`) arrives or the timeout fires.\n * Resumption hydrates the event payload as the step's result.\n *\n * **At-least-once contract**: if the worker dies between fn() returning and\n * saveStep persisting, fn re-runs on next claim. Make step bodies\n * idempotent (Stripe idempotency keys, upsert not insert, etc.).\n */\n\nimport type { Logger } from \"../logger\";\nimport { expBackoffMs } from \"./backoff\";\nimport type { WorkflowsClient } from \"./rpc-client\";\nimport type { RunId, StepState } from \"./types\";\n\nconst INLINE_SLEEP_THRESHOLD_MS = 30_000;\n\n/** Options for `ctx.run(name, fn, options)`. */\nexport interface StepRunOptions {\n  /**\n   * In-step retry attempts before propagating.\n   * @defaultValue 0\n   */\n  retries?: number;\n  /** Backoff between in-step retries. */\n  backoff?: {\n    /**\n     * Initial backoff delay in ms.\n     * @defaultValue 1_000\n     */\n    base?: number;\n    /**\n     * Maximum backoff delay in ms.\n     * @defaultValue 30_000\n     */\n    max?: number;\n  };\n  /** When set to `false`, any throw inside fn fails the run immediately (skips in-step retries). */\n  retry?: false;\n}\n\n/** Options for `ctx.waitFor(name, options)`. */\nexport interface StepWaitOptions {\n  /**\n   * Timeout in ms. After this elapses without a matching signal, the step\n   * resolves to `null`.\n   * @defaultValue Infinity (parked indefinitely)\n   */\n  timeout?: number;\n}\n\ninterface StepAPI {\n  run<T>(\n    name: string,\n    fn: (step: WorkflowStepContext) => Promise<T> | T,\n    opts?: StepRunOptions,\n  ): Promise<T>;\n  sleep(name: string, durationMs: number): Promise<void>;\n  waitFor<T = unknown>(name: string, opts?: StepWaitOptions): Promise<T | null>;\n}\n\n/** Context passed to one durable workflow step. */\nexport interface WorkflowStepContext {\n  /** Unique id for the current workflow run. */\n  readonly runId: RunId;\n  /** Name of the current workflow. */\n  readonly workflowName: string;\n  /** Name of the current durable step. */\n  readonly stepName: string;\n  /** Current run attempt, starting at 1. */\n  readonly attempt: number;\n  /** Logger scoped to this step. */\n  readonly logger: Logger;\n}\n\n/** Sentinel: end the run cleanly as `cancelled`. */\nexport class BailSignal {\n  constructor(public reason?: string) {}\n}\n\n/** Sentinel: end the run as `dead` immediately (skip retries). */\nexport class FailSignal {\n  constructor(public error: Error) {}\n}\n\n/** Sentinel: defer the run to `wakeAt` (or indefinitely if null). */\nexport class DeferSignal {\n  constructor(public wakeAt: Date | null) {}\n}\n\n/** Sentinel: park the run waiting for an event. */\nexport class WaitSignal {\n  constructor(\n    public stepName: string,\n    public eventName: string,\n    public timeoutAt: Date | null,\n  ) {}\n}\n\n/** True for any control-flow sentinel — these must propagate untouched. */\nexport function isControlSignal(err: unknown): boolean {\n  return (\n    err instanceof BailSignal ||\n    err instanceof FailSignal ||\n    err instanceof DeferSignal ||\n    err instanceof WaitSignal\n  );\n}\n\n/**\n * Create the durable step API for one claimed workflow run.\n *\n * @internal\n */\nexport function createStepAPI(\n  client: WorkflowsClient,\n  runId: RunId,\n  workerId: string,\n  stepState: StepState,\n  log: Logger,\n  createContext: (stepName: string) => WorkflowStepContext,\n): StepAPI {\n  return {\n    async run<T>(\n      name: string,\n      fn: (step: WorkflowStepContext) => Promise<T> | T,\n      opts?: StepRunOptions,\n    ): Promise<T> {\n      if (Object.prototype.hasOwnProperty.call(stepState, name)) {\n        log.debug(\"Step cached\", { step: name });\n        return stepState[name] as T;\n      }\n\n      const attempts = (opts?.retries ?? 0) + 1;\n      const base = opts?.backoff?.base ?? 1_000;\n      const max = opts?.backoff?.max ?? 30_000;\n\n      let lastErr: unknown;\n      const startedAt = Date.now();\n      const context = createContext(name);\n      for (let attempt = 1; attempt <= attempts; attempt++) {\n        try {\n          const result = await fn(context);\n          stepState[name] = result as unknown;\n          await client.saveStep(runId, workerId, name, result ?? null);\n          log.info(\"Step completed\", { step: name, ms: Date.now() - startedAt });\n          return result;\n        } catch (err) {\n          // Control signals (success/bail/fail/defer/wait) are how the\n          // handler talks to the worker — never retry, never wrap, just\n          // propagate.\n          if (isControlSignal(err)) throw err;\n          lastErr = err;\n          if (opts?.retry === false) {\n            const e = err instanceof Error ? err : new Error(String(err));\n            throw new FailSignal(e);\n          }\n          if (attempt < attempts) {\n            await new Promise((r) => setTimeout(r, expBackoffMs(attempt, base, max)));\n          }\n        }\n      }\n      throw lastErr;\n    },\n\n    async sleep(name: string, durationMs: number): Promise<void> {\n      const key = `__sleep:${name}`;\n      const stored = stepState[key] as { wakeAt: number } | undefined;\n      if (stored) {\n        if (Date.now() >= stored.wakeAt) {\n          if (!Object.prototype.hasOwnProperty.call(stepState, name)) {\n            stepState[name] = true;\n            await client.saveStep(runId, workerId, name, true);\n            log.info(\"Sleep completed\", { step: name, ms: durationMs });\n          } else {\n            log.debug(\"Sleep cached\", { step: name });\n          }\n          return;\n        }\n        throw new DeferSignal(new Date(stored.wakeAt));\n      }\n\n      const wakeAt = Date.now() + durationMs;\n      stepState[key] = { wakeAt };\n      await client.saveStep(runId, workerId, key, { wakeAt });\n\n      if (durationMs < INLINE_SLEEP_THRESHOLD_MS) {\n        await new Promise((r) => setTimeout(r, durationMs));\n        stepState[name] = true;\n        await client.saveStep(runId, workerId, name, true);\n        log.info(\"Sleep completed\", { step: name, ms: durationMs });\n        return;\n      }\n      throw new DeferSignal(new Date(wakeAt));\n    },\n\n    async waitFor<T = unknown>(name: string, opts?: StepWaitOptions): Promise<T | null> {\n      if (Object.prototype.hasOwnProperty.call(stepState, name)) {\n        log.debug(\"Step cached\", { step: name });\n        return stepState[name] as T | null;\n      }\n      const timeoutAt = opts?.timeout != null ? new Date(Date.now() + opts.timeout) : null;\n      throw new WaitSignal(name, name, timeoutAt);\n    },\n  };\n}\n","/**\n * Worker loop — claims one run at a time, executes its handler with a\n * checkpointed step API, heartbeats the lease, and finalizes the run via\n * `complete` / `cancel` / `fail` / `defer` / `wait_for_event` based on the\n * outcome.\n *\n * Sentinel exceptions (BailSignal/FailSignal/DeferSignal/WaitSignal) drive\n * the non-retry termination paths cleanly.\n *\n * Start one Worker per app instance. `drain()` stops claiming and awaits\n * any in-flight run for the platform drain hook.\n */\n\nimport { createLogger, type Logger } from \"../logger\";\nimport { expBackoffMs } from \"./backoff\";\nimport type { WorkflowsClient } from \"./rpc-client\";\nimport {\n  BailSignal,\n  createStepAPI,\n  DeferSignal,\n  FailSignal,\n  WaitSignal,\n  type StepRunOptions,\n  type StepWaitOptions,\n  type WorkflowStepContext,\n} from \"./step\";\nimport type { Run, StepState } from \"./types\";\n\n/**\n * Function that executes one workflow run.\n *\n * The payload type `P` is inferred from `defineWorkflow<P>(...)` and flows into\n * `.enqueue(payload)`.\n */\nexport type WorkflowHandler<P = unknown> = (\n  payload: P,\n  ctx: WorkflowContext,\n) => Promise<void> | void;\n\n/**\n * Runtime context passed to each workflow handler.\n */\nexport interface WorkflowContext {\n  /** Unique id for the current workflow run. */\n  readonly runId: string;\n  /** Name used when the workflow was registered with `defineWorkflow`. */\n  readonly workflowName: string;\n  /** Current run attempt, starting at 1. */\n  readonly attempt: number;\n  /** Logger scoped to this workflow run. */\n  readonly logger: Logger;\n  /**\n   * Execute and memoize a durable step.\n   *\n   * On retry, completed steps return their stored result without calling `fn`.\n   */\n  run<T>(\n    name: string,\n    fn: (step: WorkflowStepContext) => Promise<T> | T,\n    opts?: StepRunOptions,\n  ): Promise<T>;\n  /**\n   * Durably sleep for `durationMs`.\n   */\n  sleep(name: string, durationMs: number): Promise<void>;\n  /**\n   * Park the run until `signal(name, payload)` wakes it or the optional timeout\n   * elapses.\n   */\n  waitFor<T = unknown>(name: string, opts?: StepWaitOptions): Promise<T | null>;\n  /**\n   * End the run cleanly as `cancelled` with no retries.\n   *\n   * Use this for work that is no longer needed. To exit successfully early,\n   * just `return` from the handler.\n   */\n  bail(reason?: string): never;\n  /**\n   * End the run as `dead` immediately with no retries.\n   *\n   * Use this for permanent errors that will not improve with retry.\n   */\n  fail(error: Error | string): never;\n}\n\ninterface WorkflowRetryConfig {\n  /** Run-level retry budget (default 3). */\n  maxAttempts?: number;\n  /** Run-level backoff between failed attempts. */\n  backoff?: {\n    /**\n     * Initial backoff delay in ms.\n     * @defaultValue 1_000\n     */\n    base?: number;\n    /**\n     * Maximum backoff delay in ms.\n     * @defaultValue 3_600_000\n     */\n    max?: number;\n  };\n}\n\n/** Options for constructing a workflow worker. */\nexport interface WorkerOptions {\n  /** RPC client used for queue operations. */\n  client: WorkflowsClient;\n  /** Registered workflow handlers by workflow name. */\n  registry: Map<string, RegisteredWorkflow>;\n  /** Stable worker id used for leases. */\n  workerId: string;\n  /** @defaultValue 60_000 */\n  leaseMs?: number;\n  /** @defaultValue leaseMs / 3 */\n  heartbeatIntervalMs?: number;\n  /** @defaultValue 1_000 */\n  pollIntervalMs?: number;\n  /** @defaultValue 1_000 */\n  baseBackoffMs?: number;\n  /** @defaultValue 3_600_000 */\n  maxBackoffMs?: number;\n  /**\n   * Scale-to-zero: exit poll loop after this many ms with no claim.\n   * @defaultValue 0\n   */\n  idleTimeoutMs?: number;\n  /**\n   * Max concurrent in-flight runs.\n   * @defaultValue 500\n   */\n  concurrency?: number;\n  /** Base logger. Per-run children are tagged `worker:<workflowName>`. */\n  logger?: Logger;\n}\n\n/** Workflow handler registered with the worker runtime. */\nexport interface RegisteredWorkflow {\n  /** Function that executes one workflow run. */\n  handler: WorkflowHandler;\n  /** Optional run-level retry configuration. */\n  retry?: WorkflowRetryConfig;\n}\n\nconst DEFAULTS = {\n  leaseMs: 60_000,\n  pollIntervalMs: 1_000,\n  baseBackoffMs: 1_000,\n  maxBackoffMs: 3_600_000,\n  idleTimeoutMs: 0,\n  concurrency: 500,\n} as const;\n\n/**\n * Workflow worker loop.\n *\n * Claims runs from the workflow RPC client, executes handlers with durable\n * step APIs, heartbeats leases, and finalizes run state.\n */\nexport class Worker {\n  private readonly client: WorkflowsClient;\n  private readonly registry: Map<string, RegisteredWorkflow>;\n  private readonly workerId: string;\n  private readonly leaseMs: number;\n  private readonly heartbeatIntervalMs: number;\n  private readonly pollIntervalMs: number;\n  private readonly baseBackoffMs: number;\n  private readonly maxBackoffMs: number;\n  private readonly idleTimeoutMs: number;\n  private readonly concurrency: number;\n  private readonly log: Logger;\n\n  private draining = false;\n  private idledOut = false;\n  private lastClaimAt = 0;\n  private readonly inFlight = new Set<Promise<void>>();\n  private loopPromise: Promise<void> | null = null;\n\n  constructor(opts: WorkerOptions) {\n    this.client = opts.client;\n    this.registry = opts.registry;\n    this.workerId = opts.workerId;\n    this.leaseMs = opts.leaseMs ?? DEFAULTS.leaseMs;\n    this.heartbeatIntervalMs = opts.heartbeatIntervalMs ?? Math.floor(this.leaseMs / 3);\n    this.pollIntervalMs = opts.pollIntervalMs ?? DEFAULTS.pollIntervalMs;\n    this.baseBackoffMs = opts.baseBackoffMs ?? DEFAULTS.baseBackoffMs;\n    this.maxBackoffMs = opts.maxBackoffMs ?? DEFAULTS.maxBackoffMs;\n    this.idleTimeoutMs = opts.idleTimeoutMs ?? DEFAULTS.idleTimeoutMs;\n    this.concurrency = Math.max(1, opts.concurrency ?? DEFAULTS.concurrency);\n    this.log = opts.logger ?? createLogger(\"worker\");\n    this.lastClaimAt = Date.now();\n  }\n\n  /** True when this worker exited because `idleTimeoutMs` elapsed. */\n  get idled(): boolean {\n    return this.idledOut;\n  }\n\n  /** Claim and process one run if available. */\n  async processOnce(): Promise<boolean> {\n    if (this.draining) return false;\n    const names = Array.from(this.registry.keys());\n    const run = await this.client.claim(this.workerId, names, this.leaseMs);\n    if (!run) return false;\n    this.lastClaimAt = Date.now();\n\n    const work = this.execute(run);\n    this.inFlight.add(work);\n    try {\n      await work;\n    } finally {\n      this.inFlight.delete(work);\n    }\n    return true;\n  }\n\n  /**\n   * Claim one run and kick off its execution without awaiting. Returns\n   * `true` if a run was claimed and dispatched, `false` if the queue was\n   * empty. Used by the internal run loop to keep up to `concurrency`\n   * runs in flight simultaneously; tests use the awaiting `processOnce`.\n   */\n  private async dispatchOne(): Promise<boolean> {\n    if (this.draining) return false;\n    const names = Array.from(this.registry.keys());\n    const run = await this.client.claim(this.workerId, names, this.leaseMs);\n    if (!run) return false;\n    this.lastClaimAt = Date.now();\n\n    const work: Promise<void> = this.execute(run)\n      .catch((err) => {\n        // Nothing awaits this promise; without a catch, a failed finalize\n        // RPC (complete/fail/cancel) becomes an unhandled rejection.\n        this.log.error(\"run finalization failed\", {\n          runId: run.id,\n          workflow: run.name,\n          error: err instanceof Error ? err.message : String(err),\n        });\n      })\n      .finally(() => {\n        this.inFlight.delete(work);\n      });\n    this.inFlight.add(work);\n    return true;\n  }\n\n  /** Start the polling loop. */\n  start(): void {\n    if (this.loopPromise) return;\n    this.loopPromise = this.runLoop();\n  }\n\n  /** Stop claiming new runs and wait for active runs to finish. */\n  async drain(): Promise<void> {\n    this.draining = true;\n    if (this.loopPromise) {\n      await this.loopPromise;\n      this.loopPromise = null;\n    }\n    await Promise.allSettled(Array.from(this.inFlight));\n  }\n\n  /** Number of currently running workflow handlers. */\n  get runningCount(): number {\n    return this.inFlight.size;\n  }\n\n  private async runLoop(): Promise<void> {\n    while (!this.draining) {\n      if (this.inFlight.size >= this.concurrency) {\n        await Promise.race(Array.from(this.inFlight)).catch(() => {});\n        continue;\n      }\n      const did = await this.dispatchOne().catch(() => false);\n      if (!did && !this.draining) {\n        if (\n          this.idleTimeoutMs > 0 &&\n          this.inFlight.size === 0 &&\n          Date.now() - this.lastClaimAt >= this.idleTimeoutMs\n        ) {\n          this.idledOut = true;\n          this.draining = true;\n          break;\n        }\n        await new Promise((r) => setTimeout(r, this.pollIntervalMs));\n      }\n    }\n  }\n\n  private async execute(run: Run): Promise<void> {\n    const runLog = this.log.child(`worker:${run.name}`, { runId: run.id });\n    const contextLog = this.log.child(run.name, { runId: run.id, workflow: run.name });\n    const reg = this.registry.get(run.name);\n    if (!reg) {\n      runLog.error(\"Workflow failed\", { error: `no handler registered for '${run.name}'` });\n      await this.client.fail(\n        run.id,\n        this.workerId,\n        `no handler registered for '${run.name}'`,\n        null,\n        true,\n      );\n      return;\n    }\n\n    const stepState: StepState = { ...run.stepState };\n    const createStepContext = (stepName: string): WorkflowStepContext => ({\n      runId: run.id,\n      workflowName: run.name,\n      stepName,\n      attempt: run.attempts,\n      logger: contextLog.child(`${run.name}:${stepName}`, { step: stepName }),\n    });\n    const context: WorkflowContext = {\n      runId: run.id,\n      workflowName: run.name,\n      attempt: run.attempts,\n      logger: contextLog,\n      ...createStepAPI(this.client, run.id, this.workerId, stepState, runLog, createStepContext),\n      bail: (reason?: string): never => {\n        throw new BailSignal(reason);\n      },\n      fail: (error: Error | string): never => {\n        const e = error instanceof Error ? error : new Error(error);\n        throw new FailSignal(e);\n      },\n    };\n\n    let heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n    if (this.heartbeatIntervalMs > 0) {\n      heartbeatTimer = setInterval(() => {\n        this.client.heartbeat(run.id, this.workerId, this.leaseMs).catch(() => {});\n      }, this.heartbeatIntervalMs);\n    }\n\n    runLog.info(\"Workflow started\", { attempt: run.attempts, payload: run.payload });\n    try {\n      await reg.handler(run.payload, context);\n      await this.client.complete(run.id, this.workerId);\n      runLog.info(\"Workflow completed\");\n    } catch (err) {\n      if (err instanceof BailSignal) {\n        await this.client.cancel(run.id, this.workerId, err.reason ?? null);\n        runLog.info(\"Workflow cancelled\", { reason: err.reason ?? null });\n        return;\n      }\n      if (err instanceof FailSignal) {\n        await this.client.fail(run.id, this.workerId, err.error.message, null, true);\n        runLog.error(\"Workflow failed\", { error: err.error });\n        return;\n      }\n      if (err instanceof DeferSignal) {\n        await this.client.defer(run.id, this.workerId, err.wakeAt);\n        runLog.debug(\"Workflow deferred\", { wakeAt: err.wakeAt });\n        return;\n      }\n      if (err instanceof WaitSignal) {\n        await this.client.waitForEvent(\n          run.id,\n          this.workerId,\n          err.stepName,\n          err.eventName,\n          err.timeoutAt,\n        );\n        runLog.debug(\"Workflow waiting\", { event: err.eventName, timeoutAt: err.timeoutAt });\n        return;\n      }\n\n      // Regular error → run-level retry path.\n      const message = err instanceof Error ? err.message : String(err);\n      const maxAttempts = reg.retry?.maxAttempts ?? run.retries + 1;\n      const finalize = run.attempts >= maxAttempts;\n      const base = reg.retry?.backoff?.base ?? this.baseBackoffMs;\n      const max = reg.retry?.backoff?.max ?? this.maxBackoffMs;\n      const nextRunAt = finalize\n        ? null\n        : new Date(Date.now() + expBackoffMs(run.attempts, base, max));\n      await this.client.fail(run.id, this.workerId, message, nextRunAt, finalize);\n      const errField = err instanceof Error ? err : message;\n      if (finalize) {\n        runLog.error(\"Workflow failed\", { attempt: run.attempts, error: errField });\n      } else {\n        runLog.warn(\"Workflow failed, retrying\", {\n          attempt: run.attempts,\n          nextRunAt,\n          error: errField,\n        });\n      }\n    } finally {\n      if (heartbeatTimer) clearInterval(heartbeatTimer);\n    }\n  }\n}\n","/**\n * WorkflowEngine — SDK-facing surface for durable tasks.\n *\n * This module is imported by **two processes**:\n *\n * 1. **Worker process** (`bunx tako-worker`, etc.) — uses\n *    `discover/register/startWorker/drain`. All DB ops go over RPC to\n *    tako-server via `WorkflowsClient`.\n *\n * 2. **HTTP app process** — `enqueue` delegates to the same RPC client.\n *    The SDK never opens SQLite; tako-server owns the queue file.\n *\n * The same singleton supports both — callers just invoke the relevant\n * subset.\n */\n\nimport { discoverWorkflows, type WorkflowDiscoveryOptions } from \"./discovery\";\nimport { WorkflowsClient } from \"./rpc-client\";\nimport type { WorkflowRuntimeOpts } from \"./types\";\nimport type { RunId } from \"./types\";\nimport { Worker, type RegisteredWorkflow, type WorkflowHandler } from \"./worker\";\n\ninterface Registration {\n  handler: WorkflowHandler;\n  opts: WorkflowRuntimeOpts;\n}\n\n/** Options for `workflow.enqueue(payload, options)`. */\nexport interface EnqueueOptions {\n  /**\n   * When to run.\n   * @defaultValue now\n   */\n  runAt?: Date;\n  /**\n   * Number of retries after the first attempt. Overrides the workflow-level default.\n   * @defaultValue workflow's configured retries\n   */\n  retries?: number;\n  /**\n   * Uniqueness key. If a non-terminal run with this key already exists,\n   * enqueue is a no-op and the existing run id is returned.\n   */\n  uniqueKey?: string | null;\n}\n\n/**\n * Runtime coordinator for workflow discovery, enqueue, signal, and worker execution.\n *\n * Application code normally uses `defineWorkflow(...).enqueue(...)` and\n * `signal(...)`; this class is exported for Tako runtime internals.\n */\nexport class WorkflowEngine {\n  private client: WorkflowsClient | null = null;\n  private worker: Worker | null = null;\n  private workerId = \"\";\n  private configuredFlag = false;\n  private readonly registrations = new Map<string, Registration>();\n\n  /** True once configure() has succeeded (worker process only). */\n  get configured(): boolean {\n    return this.configuredFlag;\n  }\n\n  /** The workflow names that have been registered (worker process only). */\n  get registeredNames(): string[] {\n    return Array.from(this.registrations.keys());\n  }\n\n  /** Worker-process setup. Attaches the RPC client + worker identity. */\n  configure(opts: { client: WorkflowsClient; workerId: string }): void {\n    if (this.configuredFlag) throw new Error(\"WorkflowEngine already configured\");\n    this.client = opts.client;\n    this.workerId = opts.workerId;\n    this.configuredFlag = true;\n  }\n\n  /**\n   * HTTP-process setup. Explicitly attach a client (tests inject a mock).\n   * If not called, the engine lazily tries `WorkflowsClient.fromEnv()` on\n   * first enqueue.\n   */\n  setClient(client: WorkflowsClient | null): void {\n    this.client = client;\n  }\n\n  /**\n   * Register one workflow handler.\n   *\n   * @param name - Workflow name.\n   * @param handler - Workflow function.\n   * @param opts - Runtime workflow options.\n   * @defaultValue opts = {}\n   */\n  register(name: string, handler: WorkflowHandler, opts: WorkflowRuntimeOpts = {}): void {\n    if (this.registrations.has(name)) {\n      throw new Error(`workflow '${name}' is already registered`);\n    }\n    this.registrations.set(name, { handler, opts });\n  }\n\n  /**\n   * Scan `dir` for workflow files and register each one by filename (without\n   * extension). `opts.worker` can narrow discovery to workflows assigned to a\n   * specific worker group.\n   */\n  async discover(dir: string, opts: WorkflowDiscoveryOptions = {}): Promise<number> {\n    const found = await discoverWorkflows(dir, opts);\n    for (const entry of found) {\n      this.register(entry.name, entry.handler, entry.opts);\n    }\n    return found.length;\n  }\n\n  /**\n   * Enqueue a task. In the HTTP process this goes through the per-app\n   * enqueue socket (tako-server writes to SQLite). In the worker process\n   * (where a backend is configured) it still goes through the RPC path —\n   * the worker doesn't self-enqueue via its own DB handle, which keeps\n   * server ownership of cron-dedup idempotent.\n   */\n  async enqueue(name: string, payload: unknown, opts: EnqueueOptions = {}): Promise<RunId> {\n    const client = this.resolveClient();\n    const effectiveOpts: EnqueueOptions = { ...opts };\n    if (effectiveOpts.retries === undefined) {\n      const reg = this.registrations.get(name);\n      if (reg?.opts.retries !== undefined) {\n        effectiveOpts.retries = reg.opts.retries;\n      }\n    }\n    const result = await client.enqueue(name, payload, effectiveOpts);\n    return result.id;\n  }\n\n  /** Deliver an event payload to every parked waitFor matching `eventName`. */\n  async signal(eventName: string, payload?: unknown): Promise<number> {\n    return this.resolveClient().signal(eventName, payload ?? null);\n  }\n\n  private resolveClient(): WorkflowsClient {\n    if (!this.client) {\n      this.client = WorkflowsClient.fromEnv();\n    }\n    if (!this.client) {\n      throw new Error(\n        \"Workflow engine has no RPC client. Set TAKO_INTERNAL_SOCKET + TAKO_APP_NAME or call setClient().\",\n      );\n    }\n    return this.client;\n  }\n\n  /** Start the worker with default runtime options. */\n  start(): void {\n    this.startWorker({});\n  }\n\n  /**\n   * Worker-process start with runtime-provided concurrency / idle timeout.\n   * Called by the worker entrypoint bootstrap; user code normally uses\n   * `start()` which accepts no arguments.\n   */\n  startWorker(opts: { concurrency?: number; idleTimeoutMs?: number }): void {\n    if (this.worker) return;\n    const client = this.resolveClient();\n    const registry = new Map<string, RegisteredWorkflow>();\n    for (const [name, reg] of this.registrations) {\n      const entry: RegisteredWorkflow = { handler: reg.handler };\n      if (reg.opts.retries !== undefined || reg.opts.backoff !== undefined) {\n        entry.retry = {};\n        if (reg.opts.retries !== undefined) entry.retry.maxAttempts = reg.opts.retries + 1;\n        if (reg.opts.backoff !== undefined) entry.retry.backoff = reg.opts.backoff;\n      }\n      registry.set(name, entry);\n    }\n    this.worker = new Worker({\n      client,\n      registry,\n      workerId: this.workerId,\n      ...(opts.concurrency !== undefined && { concurrency: opts.concurrency }),\n      ...(opts.idleTimeoutMs !== undefined && { idleTimeoutMs: opts.idleTimeoutMs }),\n    });\n    this.worker.start();\n  }\n\n  /** True if the running worker exited because it went idle. */\n  get workerIdled(): boolean {\n    return this.worker?.idled ?? false;\n  }\n\n  /** Stop claiming new runs and wait for active runs to finish. */\n  async drain(): Promise<void> {\n    if (this.worker) {\n      await this.worker.drain();\n      this.worker = null;\n    }\n  }\n\n  /** Number of workflow runs currently in flight. */\n  running(): number {\n    return this.worker?.runningCount ?? 0;\n  }\n\n  /** Gather registered cron schedules for `RegisterSchedules`. */\n  collectSchedules(): Array<{ name: string; cron: string }> {\n    const out: Array<{ name: string; cron: string }> = [];\n    for (const [name, reg] of this.registrations) {\n      if (reg.opts.schedule) {\n        out.push({ name, cron: reg.opts.schedule });\n      }\n    }\n    return out;\n  }\n\n  /** Test-only: reset all state. */\n  _reset(): void {\n    this.client = null;\n    this.worker = null;\n    this.workerId = \"\";\n    this.configuredFlag = false;\n    this.registrations.clear();\n  }\n}\n\n/** Singleton exported on the global Tako object. */\nexport const workflowsEngine = new WorkflowEngine();\n"],"mappings":"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"}