import type { StartOptions, StartOrSignalOptions, StartOrSignalSignal } from '../../types.ts'; import { type WorkflowHandle } from '../handles.ts'; import type { EngineInternals } from '../internals.ts'; import { type LifecycleCallbacks } from './shared.ts'; import { type StartOrSignalResult } from './start-or-signal-create.ts'; import { type StartOrSignalCallbacks } from './start-or-signal-resolution.ts'; export type { StartOrSignalCallbacks, StartOrSignalResult }; /** * Enforce at-most-once start for a given `idempotencyKey`. On the first call, * the workflow record and a `startIdempotency(key) → { workflowId }` mapping * commit in one compare-and-swap gated on the mapping being absent. Every later * call with the same key resolves the mapping and returns a handle to that run — * even if it has since reached a terminal state (idempotent start is a pure * dedup; it never restarts). * * Concurrent same-key callers race at the lookup→commit gap; the CAS lets exactly * one win, and the loser (its create batch rejected) resolves to the winner's * run. Requires the `conditionalBatch` capability and throws if it is absent — * single-execution semantics cannot be honored without atomic compare-and-swap. */ export declare function startWithIdempotency(internals: EngineInternals, type: string, input: unknown, options: StartOptions, callbacks: LifecycleCallbacks): Promise; /** * Atomic start-or-signal (signal-with-start). Resolves the target workflow, then: * * - **Absent** → create the workflow and deliver the signal in ONE conditional * batch (workflow record + `sig:`/`sigres:` pair + optional idempotency * mapping). The freshly-launched run consumes the signal on its first drive. * - **Non-terminal** (running, pending, suspended) → deliver the signal through * the standard engine signal path with the same `signalId`, so it dedups * against a create-batch signal a concurrent winner may have written. * - **Terminal** → throw {@link StartOrSignalConflictError} by default. With * `options.onTerminalConflict: 'start-new'`, purge the prior terminal run * through the shared terminal-replacement path, start a fresh run, and deliver * the initial signal in the create batch. * * Convergence requires a SHARED workflow identity. Concurrent callers converge on * one workflow and one signal only when they share an `options.idempotencyKey` * (the durable mapping picks one creator and the signal id derives from the key) * or an explicit `options.id` (the caller-id reservation picks one creator). * * A bare `signal.signalId` with NEITHER `options.id` nor `options.idempotencyKey` * does NOT converge: each absent-target call generates its own workflow id, so * concurrent callers create distinct runs and each delivers its own signal. In * that mode `startOrSignal` is an atomic start-with-one-initial-signal, not a * convergence primitive. Use `idempotencyKey` (id-free convergence) or * `id` + `signalId` when concurrent callers must converge. */ export declare function startOrSignal(internals: EngineInternals, type: string, input: unknown, signalSpec: StartOrSignalSignal, options: StartOrSignalOptions | undefined, callbacks: StartOrSignalCallbacks): Promise;