{"version":3,"sources":["../src/queue.ts"],"sourcesContent":["import type { HitlStepConfig } from './hitlConfig.js';\nimport type { SmartRetryConfig } from './retryConfig.js';\n\n/**\n * Queue definition and context types for worker queues.\n *\n * ## Human-in-the-loop (HITL) pause / resume\n *\n * **Pause (`awaiting_approval`)** — After a step completes, if the **next** step has\n * `requiresApproval: true`, the runtime calls the step's `chain` function (if any),\n * stores the result as the pending input for that step, marks it `awaiting_approval`,\n * and does **not** dispatch the worker until a human approves.\n *\n * **Resume (`POST .../approve`)** — The app route calls `dispatchWorker` for that step\n * with `__hitlInput` (reviewer form payload) attached. The `wrapHandlerForQueue` runtime\n * calls the step's `resume` function (or merges inputs by default) to produce the final\n * domain input, then strips all envelope keys before the user handler receives it.\n *\n * Workers **do not** need to accept any `__workerQueue` / `__hitlPending` / `__hitlInput`\n * keys in their Zod schemas — the runtime strips them automatically.\n */\n\n/** Output from one completed step, available to subsequent steps via ChainContext / HitlResumeContext. */\nexport interface QueueStepOutput {\n  stepIndex: number;\n  workerId: string;\n  output: unknown;\n}\n\n/**\n * Context passed to a step's {@link WorkerQueueStep.chain} function when the queue\n * advances normally (previous step completed without HITL).\n */\nexport interface ChainContext {\n  /** Original input passed to `dispatchQueue` (the first step's input). */\n  initialInput: unknown;\n  /**\n   * Outputs from all previous steps in order.\n   * `previousOutputs[0]` = step 0 output; last entry = most recent.\n   */\n  previousOutputs: QueueStepOutput[];\n}\n\n/**\n * Context passed to a step's {@link WorkerQueueStep.resume} function when a human has\n * approved the HITL pause and the step is being re-dispatched.\n *\n * @template T - Shape of the reviewer / UI form payload.\n *               Derive it from your `hitl.inputSchema` if defined:\n *               `HitlResumeContext<z.infer<typeof reviewerSchema>>`.\n */\nexport interface HitlResumeContext<T = unknown> {\n  /** Original input passed to `dispatchQueue` (the first step's input). */\n  initialInput: unknown;\n  /**\n   * Outputs from all previous steps in order.\n   * `previousOutputs[0]` = step 0 output; last entry = most recent.\n   */\n  previousOutputs: QueueStepOutput[];\n  /** Reviewer / UI form payload submitted via `POST .../approve` (`input` body field). */\n  reviewerInput: T;\n  /**\n   * The computed next-step input that was stored pending approval (domain fields only;\n   * all `__workerQueue` / `__hitlPending` / `hitl` envelope keys are stripped).\n   * This is what the `chain` function produced before the step was paused.\n   */\n  pendingInput: Record<string, unknown>;\n}\n\n/** Internal envelope keys injected by the queue runtime. Never passed to user handlers. */\nexport const QUEUE_ORCHESTRATION_KEYS = [\n  '__workerQueue',\n  '__hitlInput',\n  '__hitlDecision',\n  '__hitlPending',\n  'hitl',\n] as const;\n\nexport interface WorkerQueueStep {\n  /** Worker ID for this step. Must match an existing registered worker. */\n  workerId: string;\n  /**\n   * Optional delay (in seconds) before this step is executed.\n   * Implemented via SQS DelaySeconds (max 900).\n   */\n  delaySeconds?: number;\n  /**\n   * Called when the queue advances to this step after the previous step completes\n   * normally (no HITL). Receives a {@link ChainContext} and must return the input\n   * object for this worker.\n   *\n   * **Built-in shortcuts** (use a string instead of a function):\n   * - `'passthrough'` — pass the previous step's output directly as this step's input.\n   * - `'continueFromPrevious'` — extract `{ current, history }` from the previous\n   *   output and build a `{ mode: 'continue', ... }` payload (useful for multi-round sessions).\n   *\n   * When omitted, the previous step's output is used as-is (equivalent to `'passthrough'`).\n   *\n   * @example\n   * ```ts\n   * chain: (ctx) => ({\n   *   mode: 'review' as const,\n   *   data: ctx.previousOutputs[ctx.previousOutputs.length - 1]?.output,\n   * }),\n   * ```\n   */\n  chain?: ((ctx: ChainContext) => unknown) | 'passthrough' | 'continueFromPrevious';\n  /**\n   * Called when this step resumes after a human approves a HITL pause.\n   * Receives a {@link HitlResumeContext} with the reviewer's form payload and the\n   * stored pending input, and must return the final domain input for this worker.\n   *\n   * When omitted, a shallow merge of `pendingInput` + `reviewerInput` is used as the\n   * default (suitable for simple cases where reviewer fields override pending fields).\n   *\n   * @example\n   * ```ts\n   * resume: (ctx: HitlResumeContext<ReviewerSchema>) => ({\n   *   ...ctx.pendingInput,\n   *   overriddenField: ctx.reviewerInput.overriddenField,\n   * }),\n   * ```\n   */\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  resume?: (ctx: HitlResumeContext<any>) => unknown;\n  /**\n   * When `true`, queue execution pauses before dispatching this step.\n   * The step waits until a human calls `POST .../approve` (or `POST .../reject`).\n   * Define a `resume` function to control how the reviewer's payload is merged with\n   * the pending input.\n   */\n  requiresApproval?: boolean;\n  /**\n   * Optional HITL UI/metadata for this step (consumed by app UI and tooling).\n   * Use {@link defineHitlConfig} for type-safe authoring.\n   * The worker runtime uses only `requiresApproval` — this field is UI-only.\n   */\n  hitl?: HitlStepConfig;\n  /**\n   * Smart retry configuration for this queue step.\n   * Overrides any retry config on the worker definition for this step only.\n   * Retries run in-process (same Lambda invocation); ctx.retryContext is populated\n   * on each retry so the handler can self-correct (e.g. inject error into prompt).\n   *\n   * @example\n   * ```ts\n   * retry: { maxAttempts: 3, on: ['rate-limit', 'json-parse'] }\n   * ```\n   */\n  retry?: SmartRetryConfig;\n  /**\n   * When defined, evaluated after each run of this step to decide whether to\n   * re-run it (another iteration) instead of advancing to the next step.\n   *\n   * Combine with `requiresApproval: true` for HITL-gated loops where the\n   * reviewer's decision (e.g. a `continueLoop` field in their payload)\n   * controls whether another round starts.\n   *\n   * @example\n   * ```ts\n   * // Loop continues until the worker returns { finalized: true }\n   * loop: {\n   *   shouldContinue: ({ output }) => !(output as { finalized?: boolean }).finalized,\n   *   maxIterations: 20,\n   * }\n   * ```\n   */\n  loop?: {\n    /** Return true to run this step again; false to advance to the next step. */\n    shouldContinue: (ctx: LoopContext) => boolean | Promise<boolean>;\n    /**\n     * Hard cap on total iterations (including the first run).\n     * Prevents runaway loops. Default: 50.\n     */\n    maxIterations?: number;\n  };\n}\n\nexport interface WorkerQueueConfig<InitialInput = any, StepOutput = any> {\n  /** Stable queue identifier, e.g. `\"cost-review\"`. */\n  id: string;\n  /** Ordered list of steps forming the queue pipeline. */\n  steps: WorkerQueueStep[];\n  /**\n   * Optional schedule for the queue (cron or rate expression).\n   * When set, the CLI generates a queue-starter Lambda triggered by this schedule.\n   * @example `'cron(0 3 * * ? *)'` — daily at 03:00 UTC.\n   */\n  schedule?: string | { rate: string; enabled?: boolean; input?: Record<string, any> };\n  // Reserved phantom types for IDE hints — do not affect runtime.\n  _initialInputType?: InitialInput;\n  _stepOutputType?: StepOutput;\n}\n\n/**\n * Context passed to a step's {@link WorkerQueueStep.loop | loop.shouldContinue} function\n * after each iteration of a looping step.\n */\nexport interface LoopContext {\n  /** Output returned by the worker for this iteration. */\n  output: unknown;\n  /** Step definition index (stable; does not change across iterations). */\n  stepIndex: number;\n  /** 0-based count of how many times this step has already run (0 = first run). */\n  iterationCount: number;\n  /** Original input passed to `dispatchQueue`. */\n  initialInput: unknown;\n  /** Outputs from all previous steps (and previous iterations of this step). */\n  previousOutputs: QueueStepOutput[];\n}\n\n/**\n * Queue execution context embedded into job input so queue-aware wrappers\n * know their position in the pipeline. Injected automatically by the runtime.\n */\nexport interface WorkerQueueContext<InitialInput = any> {\n  id: string;\n  /** Queue definition step index — used to look up chain/resume/loop config. Stays fixed across loop iterations. */\n  stepIndex: number;\n  /**\n   * Actual array position of this step in the job's steps[] store.\n   * Differs from stepIndex when the same step has looped multiple times\n   * (each iteration is appended as a new entry). Defaults to stepIndex when absent.\n   */\n  arrayStepIndex?: number;\n  initialInput: InitialInput;\n  /** Queue job ID for progress tracking (same as first worker's jobId). */\n  queueJobId?: string;\n  /** How many times this step has already run (used by looping steps). */\n  iterationCount?: number;\n}\n\n/**\n * Repeat a step definition `count` times, calling `factory(index)` for each repetition.\n * Eliminates copy-paste for multi-round HITL workflows.\n *\n * @example\n * ```ts\n * const queue = defineWorkerQueue({\n *   id: 'multi-review',\n *   steps: [\n *     { workerId: 'ingest' },\n *     ...repeatStep(3, (i) => ({\n *       workerId: 'review',\n *       chain: chainFromPrev,\n *       resume: resumeFromHitl,\n *       requiresApproval: true,\n *       hitl: defineHitlConfig({ taskKey: `review-r${i + 1}`, ui: { type: 'schema-form', title: `Round ${i + 1}` } }),\n *     })),\n *   ],\n * });\n * ```\n */\nexport function repeatStep(\n  count: number,\n  factory: (index: number) => WorkerQueueStep\n): WorkerQueueStep[] {\n  return Array.from({ length: count }, (_, i) => factory(i));\n}\n\n/**\n * Identity helper for defining worker queues in `.queue.ts` files.\n * Use `satisfies WorkerQueueConfig<InitialInput, StepOutput>` for phantom-type docs.\n *\n * @example\n * ```ts\n * const q = defineWorkerQueue({\n *   id: 'my-queue',\n *   steps: [ ... ],\n * }) satisfies WorkerQueueConfig<MyInit, MyOutput>;\n * export default q;\n * ```\n */\nexport function defineWorkerQueue<T extends WorkerQueueConfig>(config: T): T {\n  return config;\n}\n"],"mappings":";AAsEO,IAAM,2BAA2B;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAiLO,SAAS,WACd,OACA,SACmB;AACnB,SAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,CAAC,GAAG,MAAM,QAAQ,CAAC,CAAC;AAC3D;AAeO,SAAS,kBAA+C,QAAc;AAC3E,SAAO;AACT;","names":[]}