{"version":3,"sources":["../../src/testing/index.ts","../../src/clients/memory.ts","../../src/context.ts","../../src/errors.ts","../../src/guard.ts","../../src/limits.ts","../../src/config.ts","../../src/clients/filesystem.ts","../../src/wire-version.ts","../../src/clients/shared.ts","../../src/clients/rest.ts"],"sourcesContent":["/**\n * @zapier/zapier-durable/testing\n *\n * Test/dev helpers: in-memory client adapter.\n *\n * MemoryClient has no Node-specific imports but is not part of the\n * production caller API. It belongs in a dedicated subpath so the\n * root stays focused on definition + caller concerns.\n */\n\nexport { MemoryClient } from \"../clients/memory\";\n","/**\n * In-memory DurableClient implementation for testing.\n */\n\nimport Ajv from \"ajv\";\nimport { type Clock, defaultClock } from \"../context\";\nimport { SDK_WIRE_VERSION_MAX } from \"../wire-version\";\nimport { CallbackConflictError, CallbackExpiredError } from \"../errors\";\nimport {\n  applyCheckpointUpdate,\n  classifyDelivery,\n  resolveDeadlineFields,\n  resolveResumeAt,\n  settleElapsedDeadlines,\n} from \"./shared\";\nimport type {\n  DurableClient,\n  CreateExecutionRequest,\n  CreateExecutionResponse,\n  CheckoutRequest,\n  CheckoutResponse,\n  CheckpointRequest,\n  CheckpointResponse,\n  ReleaseRequest,\n  ReleaseResponse,\n  CallbackRequest,\n  CallbackResponse,\n  Execution,\n  Operation,\n} from \"../types\";\n\n// Ajv instance for JSON Schema validation\nconst AjvClass = (Ajv as unknown as { default?: typeof Ajv }).default || Ajv;\nconst ajv = new AjvClass({ allErrors: true });\n\nfunction generateUuidV7(): string {\n  const timestamp = Date.now();\n  const timestampHex = timestamp.toString(16).padStart(12, \"0\");\n  const randomPart = Math.random().toString(16).slice(2, 14).padStart(12, \"0\");\n  const randomPart2 = Math.random().toString(16).slice(2, 6).padStart(4, \"0\");\n  return `${timestampHex.slice(0, 8)}-${timestampHex.slice(8, 12)}-7${randomPart.slice(0, 3)}-${randomPart2}-${randomPart.slice(3, 15)}`;\n}\n\nexport class MemoryClient implements DurableClient {\n  readonly callbackBaseUrl = \"memory://callbacks\";\n\n  private executions = new Map<string, Execution>();\n  private operations = new Map<string, Operation[]>();\n  /** `inbox\\0idempotency_key` -> execution id, for ensure-by-key creates. */\n  private ensured = new Map<string, string>();\n  private callbackIndex = new Map<\n    string,\n    { executionId: string; name: string }\n  >();\n  private logging = false;\n  private clock: Clock;\n  private wireVersion: number;\n\n  constructor(options?: {\n    /** Clock used for wait auto-completion at checkout and for callback\n     *  expiry / completed_at. When using a mock clock in tests, pass the\n     *  same instance to runTick(). */\n    clock?: Clock;\n    wireVersion?: number;\n  }) {\n    this.clock = options?.clock ?? defaultClock;\n    this.wireVersion = options?.wireVersion ?? SDK_WIRE_VERSION_MAX;\n  }\n\n  setLogging(enabled: boolean): void {\n    this.logging = enabled;\n  }\n\n  private log(msg: string): void {\n    if (this.logging) {\n      console.log(`  [memory-client] ${msg}`);\n    }\n  }\n\n  async create(req: CreateExecutionRequest): Promise<CreateExecutionResponse> {\n    // An inbox plus an idempotency key makes create an ensure: the pair maps to\n    // at most one execution, so a replayed event resumes the original instead of\n    // forking a second one. Either half alone does not dedupe.\n    const ensureKey =\n      req.inbox && req.idempotency_key\n        ? `${req.inbox}\\u0000${req.idempotency_key}`\n        : null;\n    const ensured = ensureKey ? this.ensured.get(ensureKey) : undefined;\n    if (ensured) {\n      const existing = this.executions.get(ensured)!;\n      this.log(`create: ${ensured} (ensure matched)`);\n      return {\n        id: existing.id,\n        name: existing.name,\n        status: existing.status,\n        inbox: req.inbox,\n        idempotency_key: req.idempotency_key,\n        created_at: existing.created_at,\n      };\n    }\n\n    const id = generateUuidV7();\n    const execution: Execution = {\n      id,\n      name: req.name,\n      status: \"running\",\n      input: req.input,\n      metadata: req.metadata,\n      wire_version: this.wireVersion,\n      created_at: new Date().toISOString(),\n    };\n    this.executions.set(id, execution);\n    this.operations.set(id, []);\n    if (ensureKey) this.ensured.set(ensureKey, id);\n    this.log(`create: ${id}`);\n    return {\n      id,\n      name: req.name,\n      status: \"running\",\n      inbox: req.inbox,\n      idempotency_key: req.idempotency_key,\n      created_at: execution.created_at,\n    };\n  }\n\n  async checkout(\n    executionId: string,\n    req?: CheckoutRequest,\n  ): Promise<CheckoutResponse> {\n    const execution = this.executions.get(executionId);\n    if (!execution) {\n      return { leased: false };\n    }\n\n    // Simple lease - always grant in memory mode\n    const leaseToken = generateUuidV7();\n    execution.lease_token = leaseToken;\n    execution.lease_expires_at = new Date(\n      Date.now() + 15 * 60 * 1000,\n    ).toISOString();\n\n    if (req?.resume_url) {\n      execution.resume_url = req.resume_url;\n    }\n    if (req?.resume_url_delivery_state) {\n      execution.resume_url_delivery_state = req.resume_url_delivery_state;\n    }\n\n    const ops = this.operations.get(executionId) ?? [];\n\n    // Auto-complete elapsed pending waits (mirrors server behaviour).\n    const now = this.clock.now();\n    for (const op of ops) {\n      if (\n        op.type === \"wait\" &&\n        op.status === \"pending\" &&\n        op.resume_at &&\n        new Date(op.resume_at).getTime() <= now\n      ) {\n        op.status = \"completed\";\n        op.completed_at = op.resume_at;\n      }\n    }\n\n    // Mirrors server behaviour.\n    settleElapsedDeadlines(ops, now);\n\n    this.log(`checkout: ${executionId}, ${ops.length} operations`);\n\n    return {\n      leased: true,\n      lease_token: leaseToken,\n      execution,\n      operations: ops,\n    };\n  }\n\n  async checkpoint(\n    executionId: string,\n    req: CheckpointRequest,\n  ): Promise<CheckpointResponse> {\n    const ops = this.operations.get(executionId) ?? [];\n    const existing = ops.find((op) => op.name === req.operation.name);\n\n    let op: Operation;\n\n    if (existing) {\n      // Update existing (see shared.ts applyCheckpointUpdate).\n      applyCheckpointUpdate(existing, req.operation);\n      op = existing;\n      this.log(\n        `checkpoint (update): ${req.operation.name} -> ${existing.status}`,\n      );\n    } else {\n      // Insert new - generate callback_token server-side for callback ops\n      // Local adapters use simple hex tokens (no version byte)\n      const callbackToken =\n        req.operation.type === \"callback\"\n          ? generateUuidV7().replace(/-/g, \"\").slice(0, 22)\n          : undefined;\n\n      const nowMs = this.clock.now();\n      const deadline = resolveDeadlineFields(req.operation, nowMs);\n\n      op = {\n        id: generateUuidV7(),\n        execution_id: executionId,\n        name: req.operation.name,\n        type: req.operation.type,\n        status: req.operation.status,\n        result: req.operation.result,\n        error: req.operation.error,\n        retry_count: req.operation.retry_count ?? 0,\n        max_attempts: req.operation.max_attempts,\n        next_retry_at: req.operation.next_retry_at,\n        resume_at: resolveResumeAt(req.operation, nowMs),\n        callback_token: callbackToken,\n        payload_schema: req.operation.payload_schema,\n        expires_at: deadline.expires_at,\n        timeout_seconds: deadline.timeout_seconds,\n        created_at: new Date().toISOString(),\n      };\n      ops.push(op);\n      this.operations.set(executionId, ops);\n      this.log(\n        `checkpoint (insert): ${req.operation.name} -> ${req.operation.status}`,\n      );\n\n      // Index callback token\n      if (op.callback_token) {\n        this.callbackIndex.set(op.callback_token, {\n          executionId,\n          name: op.name,\n        });\n      }\n    }\n\n    return { ok: true, operation: op };\n  }\n\n  async release(\n    executionId: string,\n    req: ReleaseRequest,\n  ): Promise<ReleaseResponse> {\n    const execution = this.executions.get(executionId);\n    if (execution) {\n      execution.status = req.status;\n      execution.output = req.output;\n      execution.error = req.error;\n      execution.lease_token = undefined;\n      execution.lease_expires_at = undefined;\n    }\n\n    const done = req.status === \"completed\" || req.status === \"failed\";\n    this.log(`release: ${executionId} -> ${req.status}, done=${done}`);\n    return { ok: true, done };\n  }\n\n  async callback(\n    token: string,\n    req: CallbackRequest,\n  ): Promise<CallbackResponse> {\n    const index = this.callbackIndex.get(token);\n    if (!index) {\n      return { error: \"not_found\" };\n    }\n\n    const ops = this.operations.get(index.executionId) ?? [];\n    const op = ops.find((o) => o.name === index.name);\n    if (!op) {\n      return { error: \"not_found\" };\n    }\n\n    // Deadline classification happens before payload validation (mirrors\n    // the server: expiry is decided from ingress time, and dead-callback\n    // paths never compile attacker-controllable schemas).\n    const verdict = classifyDelivery(op, this.clock.now());\n    if (verdict === \"refuse_settled\") {\n      throw new CallbackConflictError(token);\n    }\n    if (verdict === \"expire_and_refuse\") {\n      // Decided-once: journal the verdict before refusing (see classifyDelivery)\n      op.status = \"expired\";\n      this.log(`callback expired on late delivery: ${token} -> ${index.name}`);\n      throw new CallbackExpiredError(token);\n    }\n    if (verdict === \"refuse_expired\") {\n      throw new CallbackExpiredError(token);\n    }\n\n    // Validate payload against schema (if present) - matches API behavior\n    // req IS the payload (no wrapper) - third-party systems send raw payloads\n    if (op.payload_schema) {\n      const validate = ajv.compile(op.payload_schema as object);\n      if (!validate(req)) {\n        return { error: \"validation_failed\", details: validate.errors ?? [] };\n      }\n    }\n\n    op.status = \"completed\";\n    op.payload = req;\n    op.completed_at = new Date(this.clock.now()).toISOString(); // For race disambiguation\n    this.log(`callback delivered: ${token} -> ${index.name}`);\n\n    return { ok: true };\n  }\n\n  // Test helpers\n  getExecution(id: string): Execution | undefined {\n    return this.executions.get(id);\n  }\n\n  getOperations(executionId: string): Operation[] {\n    return this.operations.get(executionId) ?? [];\n  }\n\n  // Simulate callback delivery for testing (payload IS the body, no wrapper)\n  async deliverCallback(token: string, payload: unknown): Promise<boolean> {\n    try {\n      const result = await this.callback(token, payload);\n      return \"ok\" in result;\n    } catch (err) {\n      if (\n        err instanceof CallbackExpiredError ||\n        err instanceof CallbackConflictError\n      ) {\n        return false;\n      }\n      throw err;\n    }\n  }\n}\n","/**\n * DurableContext - The context object passed to durable execution functions.\n *\n * Provides:\n * - step(name, fn) - Execute a durable step\n * - wait(name, seconds) - Wait for a duration\n * - createCallback(name) - Create a callback and get [promise, url]\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { z } from \"zod\";\nimport type {\n  DurableClient,\n  CheckpointRequest,\n  ErrorMetadata,\n  Operation,\n  OperationType,\n  HeldRunState,\n} from \"./types\";\nimport { classifyError, heldReasonFor } from \"./errorClassification\";\nimport {\n  DuplicateNameError,\n  NestedStepError,\n  SuspendInsideStepError,\n  StepExhaustedError,\n  OperationTypeMismatchError,\n  ReservedOperationNameError,\n  TickReleasedError,\n  ResultCorruptError,\n  RequestOutcomeUnknownError,\n  LeaseConflictError,\n  isSdkError,\n} from \"./errors\";\nimport type { DeterminismGuard } from \"./guard\";\nimport { DeterminismViolation } from \"./guard\";\nimport type { DormancyTracker } from \"./dormancy\";\nimport type { OperationBundleResolver } from \"./externalization/resolver\";\nimport {\n  isSentinelPrefix,\n  type DeferrableField,\n} from \"./externalization/constants\";\nimport {\n  validateMaxAttempts,\n  validateWaitSeconds,\n  validateCallbackSeconds,\n  clampRetryDelayMs,\n} from \"./limits\";\nimport { getConfig } from \"./config\";\nimport {\n  serializeError,\n  deserializeError,\n  guardErrorCause,\n} from \"./errorCause\";\nimport { TrackedPromise } from \"./dormancy\";\n\n/**\n * Clock interface for time operations.\n * Allows injecting a mock clock for testing.\n */\nexport interface Clock {\n  /** Returns current time in milliseconds since epoch (like Date.now()). */\n  now(): number;\n}\n\n/** Default clock using global Date. */\nexport const defaultClock: Clock = {\n  now: () => Date.now(),\n};\n\n/**\n * Reserved prefix for synthetic DormancyTracker ids the SDK uses to\n * protect in-flight checkpoint HTTP calls from being abandoned by\n * dormancy. User operation names that start with this prefix are\n * rejected at validation time so a user-named operation cannot collide\n * with a synthetic id and cause the synthetic worker's complete() to\n * terminate a real operation's tracker entry.\n */\nexport const INTERNAL_TRACKER_PREFIX = \"__zapier_internal__:\";\n\n/** Real-time sleep, used only to absorb a sub-threshold ctx.wait in-process. */\nfunction sleep(ms: number): Promise<void> {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Strip $schema URI from JSON Schema - AJV draft-07 doesn't understand draft 2020-12 URIs. */\nfunction stripSchemaUri<T extends object>(schema: T): Omit<T, \"$schema\"> {\n  const copy = { ...schema } as T & { $schema?: string };\n  delete copy.$schema;\n  return copy as Omit<T, \"$schema\">;\n}\n\n/**\n * Tracks whether execution is inside a step, for enforcing step boundaries.\n * Prevents nested steps and waits/callbacks inside steps.\n */\nclass StepScope {\n  private als = new AsyncLocalStorage<{ name: string }>();\n\n  /** Returns true if currently executing inside a step. */\n  isInside(): boolean {\n    return this.als.getStore() !== undefined;\n  }\n\n  /** Returns the current step name, or null if not inside a step. */\n  currentName(): string | null {\n    return this.als.getStore()?.name ?? null;\n  }\n\n  /** Execute fn inside a step scope. */\n  enter<T>(name: string, fn: () => T): T {\n    return this.als.run({ name }, fn);\n  }\n}\n\nexport interface DurableContextOptions {\n  client: DurableClient;\n  tracker: DormancyTracker;\n  guard: DeterminismGuard;\n  executionId: string;\n  leaseToken: string;\n  operations: Map<string, Operation>;\n  /**\n   * Resolver for externalized field bags.\n   *\n   * `runTick` always constructs one and passes it in. The field is\n   * `optional` only to support direct construction of `DurableContext`\n   * outside the runner (test fixtures, future embeddings) — no in-tree\n   * caller does that today.\n   *\n   * Behavior when a sentinel-shaped value is read from a completed\n   * operation:\n   *   - resolver present (production path): fetches the bundle. If the\n   *     underlying client lacks `fetchDeferred` and the presigned path\n   *     is unavailable, the resolver's `deferredFetcher` wrapper throws\n   *     and the tick fails.\n   *   - resolver absent (direct-construction only): the sentinel string\n   *     flows through verbatim as the step result.\n   */\n  bundleResolver?: OperationBundleResolver;\n  maxAttempts?: number;\n  /** Clock for time operations. Defaults to Date.now(). Inject a mock for testing. */\n  clock?: Clock;\n  /** `execution.wire_version ?? 0`, immutably stamped by the server at the start of the execution. */\n  wireVersion?: number;\n}\n\n// Type for step options\nexport interface StepOptions<T> {\n  name: string;\n  run: () => Promise<T>;\n  maxAttempts?: number;\n  retryDelaySeconds?: number;\n  outputSchema?: z.ZodSchema<T>;\n}\n\n// Type for wait options\nexport interface WaitOptions {\n  name: string;\n  seconds: number;\n}\n\n// No deadline: awaiting resolves the bare payload.\nexport interface CallbackOptions<T = unknown> {\n  name: string;\n  payloadSchema?: z.ZodSchema<T>;\n}\n\n// Has a deadline: awaiting resolves a CallbackResult<T>.\nexport interface CallbackOptionsWithTimeout<T = unknown>\n  extends CallbackOptions<T> {\n  timeoutSeconds: number;\n}\n\nexport type CallbackResult<T = unknown> =\n  | { status: \"delivered\"; value: T; at: string }\n  | { status: \"expired\"; at: string };\n\n/**\n * A step that failed on this tick but still has attempts left, so the\n * execution suspended to retry rather than exhausting. Recorded on the tick's\n * DurableResult so a host can observe the failure that occurred without\n * waiting for the step to exhaust.\n *\n * This records the failure event, not the retry state: a step that is still\n * in backoff on a later tick (replayed via the time gate without executing)\n * is not recorded again.\n */\nexport interface RetryingStep {\n  /** The step (operation) name that failed. */\n  name: string;\n  /**\n   * The underlying error, already serialized (JSON-safe) by `serializeError`:\n   * name, message, stack, own properties, and the recursive `cause`. The same\n   * bytes journaled with the failed checkpoint.\n   */\n  error: unknown;\n  /** 1-based attempt number that just failed. */\n  attempt: number;\n  /** ISO timestamp when the step is next eligible to run. */\n  nextRetryAt: string;\n}\n\nexport class DurableContext {\n  private client: DurableClient;\n  private tracker: DormancyTracker;\n  private guard: DeterminismGuard;\n  private stepScope = new StepScope();\n  private usedNames = new Set<string>();\n  private operations: Map<string, Operation>;\n  private executionId: string;\n  private leaseToken: string;\n  private maxAttempts: number;\n  private clock: Clock;\n  // Execution's stamped wire version (execution.wire_version ?? 0), fixed for\n  // the execution's life. Dispatches callback resolution: v0 replays legacy,\n  // v1+ resolves a timeoutSeconds callback as a CallbackResult. Under v0 such a\n  // callback is typed CallbackResult but resolves the bare payload — the\n  // \"type-lie\" the createCallbackV0 warn flags.\n  private wireVersion: number;\n  private bundleResolver?: OperationBundleResolver;\n\n  // For resolving callbacks externally (test helper)\n  private callbackResolvers = new Map<string, (payload: unknown) => void>();\n\n  // Stores checkpoint errors for runner to check after dormancy\n  private checkpointError?: Error;\n\n  // Numbers each checkpoint request's DormancyTracker id.\n  private checkpointRequests = 0;\n\n  // Seconds absorbed by in-process waits so far this tick. The context is\n  // rebuilt fresh every tick, so this doubles as the per-tick budget counter.\n  private inProcessWaitSecondsUsed = 0;\n\n  // Set by the runner immediately before it releases this tick's lease. An\n  // in-process sleep still in flight when this flips checks it after waking\n  // to skip a completed checkpoint that could only fail against the\n  // already-released lease.\n  private tickReleased = false;\n\n  // Set when a checkpoint leaves the tick unable to write: its outcome is\n  // unknown (the server may have saved it even though no response arrived),\n  // or the server rejected it because this tick no longer holds a valid\n  // lease. From then on the tick must not write or start anything, even if\n  // user code catches the error, so the next tick replays exactly what the\n  // server saved. Release accepts an expired lease whose token still\n  // matches, so a tick that kept going could otherwise complete or fail the\n  // execution without the rejected step.\n  private writeError?: RequestOutcomeUnknownError | LeaseConflictError;\n\n  /** The first checkpoint error that ended this tick's writes, if any. */\n  getWriteError(): RequestOutcomeUnknownError | LeaseConflictError | undefined {\n    return this.writeError;\n  }\n\n  /** Returns any checkpoint error that occurred during the tick. */\n  getCheckpointError(): Error | undefined {\n    return this.checkpointError;\n  }\n\n  /** Runner calls this immediately before every client.release call. */\n  markReleased(): void {\n    this.tickReleased = true;\n  }\n\n  // Steps that failed this tick with attempts remaining, so the execution\n  // suspended to retry. The runner reads this on the \"waiting\" return so a\n  // suspended tick can report the error that occurred without waiting for\n  // exhaustion. Distinct from checkpointError (an SDK-internal checkpoint\n  // failure); this is a user step's failure.\n  private retryingSteps: RetryingStep[] = [];\n\n  /** Steps that failed this tick with retries remaining (empty if none). */\n  getRetryingSteps(): RetryingStep[] {\n    return this.retryingSteps;\n  }\n\n  // Set when a step's failure on this tick is classified as should be held.\n  // Saved in-memory only, so each tick builds a fresh context, and re-derives from\n  // the live error every time.\n  private pendingHold?: HeldRunState;\n\n  /** Returns held run override for this tick's release, if any step earned one. */\n  getPendingHold(): HeldRunState | undefined {\n    return this.pendingHold;\n  }\n\n  /** Dormancy termination promise — resolves when all work is done and execution is suspended. */\n  get termination(): Promise<unknown> {\n    return this.tracker.termination;\n  }\n\n  /**\n   * Creates a TrackedPromise that runs its onAwaited callback in ALLOWED mode.\n   *\n   * TrackedPromise callbacks execute when user code awaits - which happens in\n   * GUARDED context. This helper centralizes the mode switch for SDK internals.\n   */\n  private guardedPromise<T>(\n    inner: Promise<T>,\n    onAwaited: () => void,\n  ): TrackedPromise<T> {\n    return new TrackedPromise(inner, () => this.guardAllowed(onAwaited));\n  }\n\n  /** Runs fn in ALLOWED mode (permits non-deterministic APIs). */\n  private guardAllowed<T>(fn: () => T): T {\n    return this.guard.runAllowed(fn);\n  }\n\n  /**\n   * Replay a settled callback outcome, ordered by the journaled readyAt.\n   */\n  private replaySettled<V>(\n    name: string,\n    readyAt: number,\n    value: V,\n  ): TrackedPromise<V> {\n    let resolve: (v: V) => void;\n    const inner = new Promise<V>((r) => {\n      resolve = r;\n    });\n    return this.guardedPromise(inner, () => {\n      this.tracker.activateWait(name);\n      this.tracker.registerReady(name, readyAt, () => {\n        resolve(value);\n        this.tracker.complete(name);\n      });\n    });\n  }\n\n  /**\n   * Suspend a pending callback. The stored resolver fires only via the\n   * resolveCallback test helper — production deliveries replay from the\n   * journal.\n   */\n  private suspendPending<V>(\n    name: string,\n    toValue: (payload: unknown) => V,\n  ): TrackedPromise<V> {\n    let resolve: (v: V) => void;\n    const inner = new Promise<V>((r) => {\n      resolve = r;\n    });\n    this.callbackResolvers.set(name, (payload: unknown) => {\n      resolve(toValue(payload));\n    });\n    return this.guardedPromise(inner, () => this.tracker.activateWait(name));\n  }\n\n  /** Returns a promise that never resolves - signals suspension to the runtime. */\n  private suspend(): Promise<never> {\n    return new Promise(() => {});\n  }\n\n  /**\n   * Checkpoints an operation and updates local cache with server response.\n   *\n   * The request counts as ACTIVE work until it settles, so dormancy cannot\n   * release the tick while a write is in flight. Without this, a parallel\n   * branch that is already WAITING or PAUSED lets the tick release under a\n   * createCallback checkpoint. The callback then resolves after the release,\n   * and user code runs its next step against a released lease.\n   */\n  private async checkpoint(\n    operation: CheckpointRequest[\"operation\"],\n  ): Promise<Operation> {\n    if (this.writeError) throw this.writeError;\n    const workId = `${INTERNAL_TRACKER_PREFIX}checkpoint-request:${++this.checkpointRequests}`;\n    this.tracker.beginWork(workId);\n    let response;\n    try {\n      response = await this.client.checkpoint(this.executionId, {\n        lease_token: this.leaseToken,\n        operation,\n      });\n    } catch (error) {\n      if (\n        error instanceof RequestOutcomeUnknownError ||\n        error instanceof LeaseConflictError\n      ) {\n        this.writeError ??= error;\n      }\n      throw error;\n    } finally {\n      this.tracker.complete(workId);\n    }\n    // Sync local cache with server-generated fields\n    this.operations.set(response.operation.name, response.operation);\n    return response.operation;\n  }\n\n  /** Constructs callback URL from token using client's base URL. */\n  private callbackUrl(token: string): string {\n    return `${this.client.callbackBaseUrl}/${token}`;\n  }\n\n  /**\n   * Validates operation invariants and returns existing operation if any.\n   *\n   * Checks:\n   * - Name uniqueness (throws DuplicateNameError)\n   * - Not inside a step (throws NestedStepError or SuspendInsideStepError)\n   * - Type consistency with existing operation (throws OperationTypeMismatchError)\n   */\n  private validateOperation(\n    name: string,\n    type: OperationType,\n  ): Operation | undefined {\n    // Nothing new starts once the tick can no longer write.\n    if (this.writeError) throw this.writeError;\n    // Nothing new starts once the tick has released: it could not be saved.\n    if (this.tickReleased) throw new TickReleasedError(name);\n    if (name.startsWith(INTERNAL_TRACKER_PREFIX)) {\n      throw new ReservedOperationNameError(name, INTERNAL_TRACKER_PREFIX);\n    }\n    if (this.usedNames.has(name)) {\n      throw new DuplicateNameError(name);\n    }\n    this.usedNames.add(name);\n\n    if (this.stepScope.isInside()) {\n      throw type === \"step\"\n        ? new NestedStepError(name, this.stepScope.currentName())\n        : new SuspendInsideStepError(type, name, this.stepScope.currentName());\n    }\n\n    const existing = this.operations.get(name);\n    if (existing && existing.type !== type) {\n      throw new OperationTypeMismatchError(name, type, existing.type);\n    }\n\n    return existing;\n  }\n\n  constructor(options: DurableContextOptions) {\n    this.client = options.client;\n    this.tracker = options.tracker;\n    this.guard = options.guard;\n    this.executionId = options.executionId;\n    this.leaseToken = options.leaseToken;\n    this.operations = options.operations;\n    this.bundleResolver = options.bundleResolver;\n    this.maxAttempts = validateMaxAttempts(options.maxAttempts);\n    this.clock = options.clock ?? defaultClock;\n    this.wireVersion = options.wireVersion ?? 0;\n  }\n\n  /**\n   * Returns the materialized value of a deferrable field on a completed\n   * operation, handling the externalized-bundle case transparently. If the\n   * inline value is a sentinel string, the bundle is fetched (or read from\n   * cache) via the resolver and the requested field is read from it.\n   * Without a resolver (e.g. memory client), sentinels pass through as\n   * raw strings — those clients don't produce sentinels anyway.\n   *\n   * `field` is typed against `DEFERRABLE_FIELDS`, so adding a new field to\n   * the externalization contract requires updating the constants module —\n   * the call sites won't compile against a stale list.\n   */\n  private async readDeferredField<T>(\n    existing: Operation,\n    field: DeferrableField,\n  ): Promise<T> {\n    const inline = (existing as unknown as Record<string, unknown>)[field];\n    if (this.bundleResolver && isSentinelPrefix(inline)) {\n      // Register the S3/fetchDeferred round-trip as ACTIVE work so dormancy\n      // cannot terminate the tick while hydration is in flight. Without this,\n      // a completed externalized step replayed alongside a live blocker (e.g.\n      // inside Promise.all) is invisible to shouldTerminate() (no ACTIVE op),\n      // so the settle loop suspends the tick mid-fetch, abandons this promise,\n      // and strands the run. Mirrors the checkpoint guard below.\n      const hydrateWorkId = `${INTERNAL_TRACKER_PREFIX}hydrate:${existing.name}`;\n      this.tracker.beginWork(hydrateWorkId);\n      try {\n        const bag = await this.bundleResolver.resolve(existing);\n        if (!(field in bag)) {\n          throw new ResultCorruptError(\n            `Bundle for operation ${existing.id} missing expected field \"${field}\"`,\n            {\n              kind: \"decompress_error\",\n              executionId: this.executionId,\n              operationId: existing.id,\n            },\n          );\n        }\n        return bag[field] as T;\n      } finally {\n        this.tracker.complete(hydrateWorkId);\n      }\n    }\n    return inline as T;\n  }\n\n  // Overloaded step signatures\n  step<T>(name: string, fn: () => Promise<T>): Promise<T>;\n  step<T>(options: StepOptions<T>): Promise<T>;\n  async step<T>(\n    nameOrOptions: string | StepOptions<T>,\n    fn?: () => Promise<T>,\n  ): Promise<T> {\n    const name =\n      typeof nameOrOptions === \"string\" ? nameOrOptions : nameOrOptions.name;\n    const run = typeof nameOrOptions === \"string\" ? fn! : nameOrOptions.run;\n    const maxAttempts =\n      typeof nameOrOptions === \"string\"\n        ? this.maxAttempts\n        : validateMaxAttempts(nameOrOptions.maxAttempts ?? this.maxAttempts);\n    const retryDelaySeconds =\n      typeof nameOrOptions === \"string\"\n        ? 5\n        : (nameOrOptions.retryDelaySeconds ?? 5);\n    const existing = this.validateOperation(name, \"step\");\n\n    if (existing?.status === \"completed\") {\n      // SDK-internal transport (fetch / crypto.subtle) — run in ALLOWED so\n      // the determinism guard's globals patch doesn't trip user code that\n      // happens to be awaiting a sentinel-bearing step replay.\n      return this.guardAllowed(() =>\n        this.readDeferredField<T>(existing, \"result\"),\n      );\n    }\n    if (existing?.status === \"exhausted\") {\n      throw new StepExhaustedError(\n        name,\n        guardErrorCause(deserializeError(existing.error), this.guard),\n      );\n    }\n\n    // Entire step body in ALLOWED - SDK internals + user fn\n    return this.stepScope.enter(name, () => {\n      return this.guardAllowed(async () => {\n        // Time gating: if retry not due yet, suspend without executing\n        // Uses operation's next_retry_at from server, compared against current time\n        if (existing?.status === \"failed\" && existing.next_retry_at) {\n          const nextRetry = new Date(existing.next_retry_at).getTime();\n          if (nextRetry > this.clock.now()) {\n            this.tracker.beginWork(name);\n            this.tracker.pause(name);\n            return this.suspend();\n          }\n        }\n\n        this.tracker.beginWork(name);\n\n        try {\n          const result = await run();\n          await this.checkpoint({\n            name,\n            type: \"step\",\n            status: \"completed\",\n            result,\n          });\n          this.tracker.complete(name);\n          return result;\n        } catch (error) {\n          if (isSdkError(error) || error instanceof DeterminismViolation) {\n            this.tracker.complete(name);\n            throw error;\n          }\n\n          // Serialize once: the journaled bytes are both what we checkpoint\n          // and what the live-exhaustion cause is rehydrated from, so the\n          // cause a workflow catches on this tick is identical to the one it\n          // catches on every replay tick.\n          const serializedError = serializeError(error);\n          const classification = classifyError({ error });\n          const errorMetadata: ErrorMetadata = { cause: classification.cause };\n          if (classification.statusCode !== undefined) {\n            errorMetadata.statusCode = classification.statusCode;\n          }\n          const attempt = (existing?.retry_count ?? 0) + 1;\n          // SDK is authoritative on exhaustion; server uses max_attempts only\n          // for wake scheduling (retry_count < max_attempts).\n\n          // Wrap the failure/exhausted checkpoint in a synthetic ACTIVE\n          // worker so dormancy cannot fire while the checkpoint is in\n          // flight. Without this guard, pause(name) below would transition\n          // the step to PAUSED before the HTTP call completes; the runner\n          // would then race ahead, call release(), null the lease, and the\n          // checkpoint would land as 409 \"Lease invalid or expired\" with the\n          // operation never recorded.\n          //\n          // The id uses INTERNAL_TRACKER_PREFIX so it cannot collide with\n          // a user-named operation -- validateOperation rejects any user\n          // name that starts with that prefix.\n          const checkpointWorkId = `${INTERNAL_TRACKER_PREFIX}checkpoint:${name}`;\n\n          if (attempt < maxAttempts) {\n            const baseMs = retryDelaySeconds * 1000;\n            const backoffMs = clampRetryDelayMs(\n              baseMs * Math.pow(2, attempt - 1),\n            );\n            // Compute next_retry_at client-side (SDK owns retry policy)\n            const nextRetryAt = new Date(\n              this.clock.now() + backoffMs,\n            ).toISOString();\n            this.tracker.beginWork(checkpointWorkId);\n            try {\n              await this.checkpoint({\n                name,\n                type: \"step\",\n                status: \"failed\",\n                error: serializedError,\n                error_metadata: errorMetadata,\n                retry_count: attempt,\n                max_attempts: maxAttempts,\n                next_retry_at: nextRetryAt,\n              });\n            } finally {\n              this.tracker.complete(checkpointWorkId);\n            }\n            this.tracker.pause(name);\n            // Record the failure so the runner can report it on this tick's\n            // \"waiting\" return. serializedError is the same JSON-safe chain\n            // journaled above.\n            this.retryingSteps.push({\n              name,\n              error: serializedError,\n              attempt,\n              nextRetryAt,\n            });\n            // The `!this.pendingHold` check is for cases like\n            // `Promise.all()` where multiple steps are in the `held` condition\n            // The first one to resolve with a hold will populate the held reason.\n            const heldReason = heldReasonFor(classification.cause);\n            if (heldReason && !this.pendingHold) {\n              this.pendingHold = {\n                status: \"held\",\n                reason: heldReason,\n                ...(classification.detail !== undefined\n                  ? { detail: classification.detail }\n                  : {}),\n              };\n            }\n            return this.suspend();\n          } else {\n            this.tracker.beginWork(checkpointWorkId);\n            try {\n              await this.checkpoint({\n                name,\n                type: \"step\",\n                status: \"exhausted\",\n                error: serializedError,\n                error_metadata: errorMetadata,\n                retry_count: attempt,\n                max_attempts: maxAttempts,\n              });\n            } finally {\n              this.tracker.complete(checkpointWorkId);\n            }\n            this.tracker.complete(name);\n            throw new StepExhaustedError(\n              name,\n              guardErrorCause(deserializeError(serializedError), this.guard),\n            );\n          }\n        }\n      });\n    });\n  }\n\n  /**\n   * Await-time absorption decision: eligible waits sleep out the remainder\n   * in-process and checkpoint completed; ineligible ones just activateWait\n   * and suspend as today. Shared by a wait's first tick (pendingSucceeded\n   * settles its call-time pending checkpoint) and a replay that finds it\n   * already pending (pendingSucceeded is a resolved-true promise; the\n   * journaled resume_at is already in this.operations from checkout).\n   *\n   * The decision and the sleep both derive from the server-stamped\n   * resume_at -- never a local clock snapshot taken before the checkpoint\n   * response lands.\n   */\n  private async absorbWaitAtAwait(\n    name: string,\n    pendingSucceeded: Promise<boolean>,\n    resolve: () => void,\n  ): Promise<void> {\n    this.tracker.activateWait(name);\n\n    // The wait is now a WAITING blocker, not ACTIVE work, so it alone\n    // wouldn't stop dormancy from firing while we're still awaiting the\n    // pending checkpoint's response. Cover that gap with our own ACTIVE\n    // work rather than relying on the call site's checkpointWorkId, whose\n    // `finally` may already have completed by the time we get here.\n    const pendingWaitWorkId = `${INTERNAL_TRACKER_PREFIX}wait-pending:${name}`;\n    this.tracker.beginWork(pendingWaitWorkId);\n    let ok: boolean;\n    try {\n      ok = await pendingSucceeded;\n    } finally {\n      this.tracker.complete(pendingWaitWorkId);\n    }\n    // Checkpoint failed (checkpointError is already stored for the runner\n    // to surface): suspend as a normal blocker. No absorption, no budget\n    // charge -- the sticky checkpointError makes this tick's eventual\n    // release report failed, same as any other checkpoint failure.\n    if (!ok) return;\n\n    // Authoritative: the pending checkpoint landed, so this.operations\n    // carries the server-stamped resume_at.\n    const resumeAtIso = this.operations.get(name)!.resume_at!;\n    const resumeAtMs = new Date(resumeAtIso).getTime();\n    const remainingSeconds = Math.max(0, resumeAtMs - this.clock.now()) / 1000;\n\n    const config = getConfig();\n    const eligible =\n      config.waitInProcessThresholdSeconds > 0 &&\n      remainingSeconds <= config.waitInProcessThresholdSeconds &&\n      this.inProcessWaitSecondsUsed + remainingSeconds <=\n        config.waitInProcessBudgetSeconds;\n    if (!eligible) return;\n\n    this.inProcessWaitSecondsUsed += remainingSeconds;\n    const sleepWorkId = `${INTERNAL_TRACKER_PREFIX}inprocess-sleep:${name}`;\n    this.tracker.beginWork(sleepWorkId);\n\n    await sleep(remainingSeconds * 1000);\n\n    if (this.tickReleased) {\n      // The tick released mid-sleep; the pending row already covers the\n      // wait, so a post-release checkpoint could only fail against the\n      // released lease. This branch skips registerReady below, so it must\n      // complete the wait's own tracker id itself.\n      this.tracker.complete(sleepWorkId);\n      this.tracker.complete(name);\n      resolve();\n      return;\n    }\n\n    try {\n      await this.checkpoint({\n        name,\n        type: \"wait\",\n        status: \"completed\",\n        resume_at: resumeAtIso,\n      });\n    } catch {\n      // A completed checkpoint that fails after a successful pending\n      // checkpoint does not poison the run: the pending row already covers\n      // durability, and replay resolves this wait on the same branch below.\n    }\n\n    this.tracker.complete(sleepWorkId);\n    this.tracker.registerReady(name, resumeAtMs, () => {\n      resolve();\n      this.tracker.complete(name);\n    });\n  }\n\n  // Overloaded wait signatures\n  wait(name: string, seconds: number): TrackedPromise<void>;\n  wait(options: WaitOptions): TrackedPromise<void>;\n  wait(\n    nameOrOptions: string | WaitOptions,\n    secondsArg?: number,\n  ): TrackedPromise<void> {\n    const name =\n      typeof nameOrOptions === \"string\" ? nameOrOptions : nameOrOptions.name;\n    const seconds = validateWaitSeconds(\n      typeof nameOrOptions === \"string\" ? secondsArg! : nameOrOptions.seconds,\n    );\n    const existing = this.validateOperation(name, \"wait\");\n\n    // Entire wait body in ALLOWED (no user code here, just SDK internals)\n    return this.guardAllowed(() => {\n      // Completed wait (either from replay or server-side auto-completion at\n      // checkout) — register with ready queue.\n      if (existing?.status === \"completed\") {\n        this.tracker.registerWait(name);\n\n        let resolve: () => void;\n        const inner = new Promise<void>((r) => {\n          resolve = r;\n        });\n\n        // Use resume_at if available, otherwise use created_at as fallback\n        const readyAt = existing.resume_at\n          ? new Date(existing.resume_at).getTime()\n          : new Date(existing.created_at).getTime();\n\n        return this.guardedPromise(inner, () => {\n          this.tracker.activateWait(name);\n          // Register with ready queue for proper ordering\n          this.tracker.registerReady(name, readyAt, () => {\n            resolve();\n            this.tracker.complete(name);\n          });\n        });\n      }\n\n      // First time or pending: register, and on first encounter always\n      // checkpoint pending (the in-process threshold/budget decision moves\n      // entirely to await time, in absorbWaitAtAwait). Until awaited this\n      // is indistinguishable from an above-threshold wait: an unawaited\n      // wait is a journaled pending row and nothing more, and no timer\n      // exists before the first await, matching the suspend path.\n      let resolve: () => void;\n      const inner = new Promise<void>((r) => {\n        resolve = r;\n      });\n\n      if (!existing) {\n        this.tracker.registerWait(name);\n\n        // See INTERNAL_TRACKER_PREFIX docs: this id cannot collide with a\n        // user-named operation because validateOperation rejects names with\n        // the reserved prefix.\n        const checkpointWorkId = `${INTERNAL_TRACKER_PREFIX}checkpoint:${name}`;\n        this.tracker.beginWork(checkpointWorkId);\n        // Send the duration; the server stamps resume_at from its own clock.\n        // pendingSucceeded conveys success: true once the response landed\n        // and this.operations carries the server-stamped resume_at, false\n        // on failure (the error is still stored to checkpointError below).\n        const pendingSucceeded: Promise<boolean> = this.checkpoint({\n          name,\n          type: \"wait\",\n          status: \"pending\",\n          duration_seconds: seconds,\n        })\n          .then(() => true)\n          .catch((error) => {\n            this.checkpointError = error; // Store for runner to check after dormancy\n            return false;\n          })\n          .finally(() => {\n            this.tracker.complete(checkpointWorkId); // Always complete - enables dormancy\n          });\n\n        return this.guardedPromise(inner, () =>\n          this.absorbWaitAtAwait(name, pendingSucceeded, resolve),\n        );\n      }\n\n      // Replay: journal already has this wait pending from an earlier tick,\n      // with its server-stamped resume_at already in this.operations from\n      // checkout. Same await-time decision as first encounter; no checkpoint\n      // to send here since a previous tick already did.\n      this.tracker.registerWait(name);\n\n      return this.guardedPromise(inner, () =>\n        this.absorbWaitAtAwait(name, Promise.resolve(true), resolve),\n      );\n    });\n  }\n\n  // Overloaded createCallback signatures\n  createCallback(name: string): Promise<[TrackedPromise<unknown>, string]>;\n  createCallback<T>(\n    options: CallbackOptionsWithTimeout<T>,\n  ): Promise<[TrackedPromise<CallbackResult<T>>, string]>;\n  createCallback<T>(\n    options: CallbackOptions<T>,\n  ): Promise<[TrackedPromise<T>, string]>;\n  async createCallback<T = unknown>(\n    nameOrOptions: string | CallbackOptions<T> | CallbackOptionsWithTimeout<T>,\n  ): Promise<[TrackedPromise<T> | TrackedPromise<CallbackResult<T>>, string]> {\n    const name =\n      typeof nameOrOptions === \"string\" ? nameOrOptions : nameOrOptions.name;\n    const timeoutSeconds =\n      typeof nameOrOptions !== \"string\" && \"timeoutSeconds\" in nameOrOptions\n        ? nameOrOptions.timeoutSeconds\n        : undefined;\n    const payloadSchema =\n      typeof nameOrOptions === \"string\"\n        ? undefined\n        : nameOrOptions.payloadSchema;\n    const op = this.validateOperation(name, \"callback\");\n\n    if (this.wireVersion >= 1) {\n      return this.createCallbackV1<T>({\n        name,\n        timeoutSeconds,\n        payloadSchema,\n        op,\n      });\n    }\n    return this.createCallbackV0<T>({\n      name,\n      timeoutSeconds,\n      payloadSchema,\n      op,\n    });\n  }\n\n  /**\n   * The wire v0 callback path. v0 has no server-side expiry, so a callback\n   * here can only ever be delivered: with timeoutSeconds it resolves a\n   * delivered CallbackResult (never an expired one) to honour the overload's\n   * type; without it, the bare payload, byte-identical to legacy.\n   */\n  private async createCallbackV0<T>({\n    name,\n    timeoutSeconds,\n    payloadSchema,\n    op: existing,\n  }: {\n    name: string;\n    timeoutSeconds: number | undefined;\n    payloadSchema: z.ZodSchema<T> | undefined;\n    op: Operation | undefined;\n  }): Promise<[TrackedPromise<T> | TrackedPromise<CallbackResult<T>>, string]> {\n    let op = existing;\n    const hasDeadline = timeoutSeconds !== undefined;\n\n    // Entire createCallback body in ALLOWED (no user code here, just SDK internals)\n    return this.guardAllowed(async () => {\n      // First time: checkpoint (server generates token, updates local cache)\n      if (!op) {\n        if (timeoutSeconds !== undefined) {\n          // v0 honours the CallbackResult shape but has no server expiry, so\n          // the callback can only ever resolve { status: \"delivered\" }. We\n          // accept it (in-flight v0 executions pass timeoutSeconds); warn once\n          // that the deadline isn't enforced until the account is on v1.\n          console.warn(\n            `[zapier-durable] execution ${this.executionId}: callback ` +\n              `\"${name}\" was created with timeoutSeconds, but this execution ` +\n              `replays under wire v0 — it resolves a delivered CallbackResult ` +\n              `and never expires. The deadline is not enforced until the ` +\n              `account is on durable_wire_version v1.`,\n          );\n        }\n        const expiresMs = validateCallbackSeconds(timeoutSeconds) * 1000;\n        this.tracker.registerWait(name);\n        // Compute expires_at client-side (SDK owns timeout duration)\n        op = await this.checkpoint({\n          name,\n          type: \"callback\",\n          status: \"pending\",\n          expires_at: new Date(this.clock.now() + expiresMs).toISOString(),\n          payload_schema: payloadSchema\n            ? stripSchemaUri(payloadSchema.toJSONSchema())\n            : undefined,\n        });\n      }\n\n      // op now has server-generated callback_token\n      if (!op.callback_token) {\n        throw new Error(\n          `Callback \"${name}\" missing callback_token - data corruption`,\n        );\n      }\n      const url = this.callbackUrl(op.callback_token);\n\n      // An expired row can't exist in a legitimate v0 journal (the\n      // timeout_seconds column only rides the wire on v1). Fail loudly rather than fall\n      // through to suspend and hang forever.\n      if (op.status === \"expired\") {\n        throw new Error(\n          `Callback \"${name}\" is expired in the journal but this execution ` +\n            `replays under wire v0, which cannot produce expired ` +\n            `callbacks. The journal and the execution's wire version ` +\n            `disagree - data corruption.`,\n        );\n      }\n\n      // Completed: replay the delivered outcome, ordered by completed_at.\n      if (op.status === \"completed\") {\n        this.tracker.registerWait(name);\n        const readyAt = new Date(op.completed_at ?? op.created_at).getTime();\n\n        if (hasDeadline) {\n          // v0 has no server expiry, so a settled callback is always delivered.\n          const outcome: CallbackResult<T> = {\n            status: \"delivered\",\n            value: op.payload as T,\n            at: op.completed_at ?? op.created_at,\n          };\n          return [this.replaySettled(name, readyAt, outcome), url];\n        }\n        return [this.replaySettled<T>(name, readyAt, op.payload as T), url];\n      }\n\n      // Pending: suspend until delivery (v0 never expires).\n      this.tracker.registerWait(name);\n\n      if (hasDeadline) {\n        const tracked = this.suspendPending<CallbackResult<T>>(\n          name,\n          (payload) => ({\n            status: \"delivered\",\n            value: payload as T,\n            at: new Date(this.clock.now()).toISOString(),\n          }),\n        );\n        return [tracked, url];\n      }\n      return [this.suspendPending<T>(name, (payload) => payload as T), url];\n    });\n  }\n\n  /**\n   * Wire v1 callback path. The deadline rides the wire as timeout_seconds\n   * for the server to stamp from its own clock. A call site that passed\n   * timeoutSeconds awaits a CallbackResult; one that didn't resolves the\n   * bare payload and cannot expire.\n   */\n  private async createCallbackV1<T>({\n    name,\n    timeoutSeconds,\n    payloadSchema,\n    op: existing,\n  }: {\n    name: string;\n    timeoutSeconds: number | undefined;\n    payloadSchema: z.ZodSchema<T> | undefined;\n    op: Operation | undefined;\n  }): Promise<[TrackedPromise<T> | TrackedPromise<CallbackResult<T>>, string]> {\n    let op = existing;\n    const hasDeadline = timeoutSeconds !== undefined;\n\n    // Entire createCallback body in ALLOWED (no user code here, just SDK internals)\n    return this.guardAllowed(async () => {\n      // Server generates the callback_token and updates the local cache.\n      if (!op) {\n        const checkpointTimeout = hasDeadline\n          ? validateCallbackSeconds(timeoutSeconds)\n          : undefined;\n        this.tracker.registerWait(name);\n        op = await this.checkpoint({\n          name,\n          type: \"callback\",\n          status: \"pending\",\n          timeout_seconds: checkpointTimeout,\n          payload_schema: payloadSchema\n            ? stripSchemaUri(payloadSchema.toJSONSchema())\n            : undefined,\n        });\n      } else {\n        // Journal wins on values; a mismatch means the durable code changed\n        // between ticks. An absent key (vs explicit null = no-timeout) means the\n        // server didn't echo the column — no opinion, no warning.\n        const journaled = op.timeout_seconds;\n        if (journaled !== undefined && journaled !== (timeoutSeconds ?? null)) {\n          console.warn(\n            `[zapier-durable] execution ${this.executionId}: ` +\n              `Callback \"${name}\": code requests ` +\n              `timeoutSeconds=${timeoutSeconds ?? \"none\"} but the journal ` +\n              `recorded timeout_seconds=${journaled ?? \"none\"}. ` +\n              `The journaled deadline wins.`,\n          );\n        }\n      }\n      const journaledOp = op;\n\n      // Replay shape is journal-derived: an existing row's wrapper-ness is\n      // fixed by its journaled timeout_seconds, so changing the code's\n      // timeoutSeconds between ticks can't flip a settled callback's shape.\n      // An un-echoed column (undefined) means no opinion — use the call site.\n      const wrap =\n        journaledOp.timeout_seconds === undefined\n          ? hasDeadline\n          : journaledOp.timeout_seconds !== null;\n\n      if (!journaledOp.callback_token) {\n        throw new Error(\n          `Callback \"${name}\" missing callback_token - data corruption`,\n        );\n      }\n      const url = this.callbackUrl(journaledOp.callback_token);\n\n      // Settled (completed or expired): replay the journaled outcome.\n      if (\n        journaledOp.status === \"completed\" ||\n        journaledOp.status === \"expired\"\n      ) {\n        this.tracker.registerWait(name);\n\n        // Sort by when the outcome happened: delivery at completed_at,\n        // expiry at expires_at; created_at as fallback for legacy rows.\n        const readyAt = new Date(\n          (journaledOp.status === \"completed\"\n            ? journaledOp.completed_at\n            : journaledOp.expires_at) ?? journaledOp.created_at,\n        ).getTime();\n\n        if (wrap) {\n          // Build the wrapper from journaled fields. Key on status, not\n          // field presence — a delivered JSON null payload is legal.\n          const outcome: CallbackResult<T> =\n            journaledOp.status === \"completed\"\n              ? {\n                  status: \"delivered\",\n                  value: journaledOp.payload as T,\n                  at: journaledOp.completed_at ?? journaledOp.created_at,\n                }\n              : {\n                  status: \"expired\",\n                  at: journaledOp.expires_at ?? journaledOp.created_at,\n                };\n\n          return [this.replaySettled(name, readyAt, outcome), url];\n        }\n\n        if (journaledOp.status === \"expired\") {\n          // Reached only when the journal didn't echo timeout_seconds (so\n          // `wrap` fell back to the call site) and the code now passes none:\n          // an expired callback has no payload to resolve. Fail loudly.\n          throw new Error(\n            `Callback \"${name}\" expired in the journal but neither the ` +\n              `journal nor the current code carries a timeoutSeconds; an ` +\n              `expired callback has no payload to resolve.`,\n          );\n        }\n\n        return [\n          this.replaySettled<T>(name, readyAt, journaledOp.payload as T),\n          url,\n        ];\n      }\n\n      this.tracker.registerWait(name);\n\n      if (wrap) {\n        // The test-helper resolver can only mean a delivery, so a\n        // clock-stamped `at` is acceptable here (see suspendPending).\n        const tracked = this.suspendPending<CallbackResult<T>>(\n          name,\n          (payload) => ({\n            status: \"delivered\",\n            value: payload as T,\n            at: new Date(this.clock.now()).toISOString(),\n          }),\n        );\n        return [tracked, url];\n      }\n\n      return [this.suspendPending<T>(name, (payload) => payload as T), url];\n    });\n  }\n\n  // Test helper: deliver a callback payload in-process. The stored resolver\n  // wraps it to match what the call site awaits (bare payload or\n  // CallbackResult).\n  resolveCallback(name: string, payload: unknown): void {\n    this.guardAllowed(() => {\n      const resolver = this.callbackResolvers.get(name);\n      if (resolver) {\n        resolver(payload);\n        this.tracker.complete(name);\n      }\n    });\n  }\n}\n","/**\n * Error classes for the Durable Execution SDK.\n */\n\nexport class DuplicateNameError extends Error {\n  constructor(name: string) {\n    super(\n      `Duplicate operation name: \"${name}\". Each step/wait/callback must have a unique name.`,\n    );\n    this.name = \"DuplicateNameError\";\n  }\n}\n\nexport class NestedStepError extends Error {\n  constructor(innerName: string, outerName: string | null) {\n    super(\n      `Cannot nest step \"${innerName}\" inside step \"${outerName}\". ` +\n        `Steps must be flat. Use separate steps and pass data between them.`,\n    );\n    this.name = \"NestedStepError\";\n  }\n}\n\nexport class SuspendInsideStepError extends Error {\n  constructor(\n    type: \"wait\" | \"callback\",\n    name: string,\n    stepName: string | null,\n  ) {\n    super(\n      `Cannot call ${type}(\"${name}\") inside step \"${stepName}\". ` +\n        `Waits and callbacks must be at the top level, not inside steps.`,\n    );\n    this.name = \"SuspendInsideStepError\";\n  }\n}\n\nexport class StepExhaustedError extends Error {\n  constructor(name: string, cause: unknown) {\n    super(`Step \"${name}\" exhausted all retry attempts.`, { cause });\n    this.name = \"StepExhaustedError\";\n  }\n}\n\nconst LEASE_CONFLICT_SYMBOL = Symbol.for(\n  \"@zapier/zapier-durable/LeaseConflictError\",\n);\n\nexport class LeaseConflictError extends Error {\n  static [Symbol.hasInstance](error: unknown): boolean {\n    if (this !== LeaseConflictError) {\n      return Function.prototype[Symbol.hasInstance].call(this, error);\n    }\n    return error instanceof Error && LEASE_CONFLICT_SYMBOL in error;\n  }\n\n  constructor(executionId: string) {\n    super(\n      `Lease conflict for execution \"${executionId}\". Ownership could not be established; any prior write outcome is unknown.`,\n    );\n    this.name = \"LeaseConflictError\";\n    Object.defineProperty(this, LEASE_CONFLICT_SYMBOL, { value: true });\n  }\n}\n\n/**\n * Thrown when a request to the durable server ran out of attempts on a\n * retriable failure (timeout, network error, 5xx, 408, 429). The server may\n * or may not have applied it: a response can be lost after the write\n * commits. The tick must stop without writing anything else, so a later tick\n * replays whatever the server actually saved.\n */\nconst REQUEST_OUTCOME_UNKNOWN_SYMBOL = Symbol.for(\n  \"@zapier/zapier-durable/RequestOutcomeUnknownError\",\n);\n\nexport class RequestOutcomeUnknownError extends Error {\n  // Like LeaseConflictError: each entry point bundles its own copy of this\n  // class, and the runner must recognize one thrown by the other copy.\n  static [Symbol.hasInstance](error: unknown): boolean {\n    if (this !== RequestOutcomeUnknownError) {\n      return Function.prototype[Symbol.hasInstance].call(this, error);\n    }\n    return error instanceof Error && REQUEST_OUTCOME_UNKNOWN_SYMBOL in error;\n  }\n\n  constructor(operation: string, attempts: number, lastError: string) {\n    super(\n      `${operation} outcome unknown after ${attempts} attempt(s); the server may or may not have applied it. Last error: ${lastError}`,\n    );\n    this.name = \"RequestOutcomeUnknownError\";\n    Object.defineProperty(this, REQUEST_OUTCOME_UNKNOWN_SYMBOL, {\n      value: true,\n    });\n  }\n}\n\n/**\n * Thrown when an operation name is reused with a different type (e.g., step vs wait).\n * This can only happen with non-deterministic control flow - which the DeterminismGuard\n * should catch first. If user somehow bypasses the guard (unguarded non-determinism source),\n * catching this error and continuing could lead to invalid state. In practice, the guard\n * catches common sources (Date.now, Math.random, etc.) before this error is reachable.\n */\nexport class OperationTypeMismatchError extends Error {\n  constructor(name: string, expected: string, actual: string) {\n    super(\n      `Operation \"${name}\" was previously recorded as type \"${actual}\" but is now called as \"${expected}\". ` +\n        `This indicates non-deterministic control flow.`,\n    );\n    this.name = \"OperationTypeMismatchError\";\n  }\n}\n\n/**\n * Result exceeded the documented size limit. Surfaced from a 413 on\n * checkpoint. Sizes/ratio/guidance mirror the structured 413 body so\n * callers can build accurate user-facing messages. Terminal — the SDK\n * does not retry.\n */\nexport class ResultTooLargeError extends Error {\n  readonly kind: \"uncompressed_exceeds_limit\" | \"compressed_exceeds_limit\";\n  readonly operationName: string;\n  readonly resultSizeBytes: number;\n  readonly resultSizeAfterCompressionBytes: number;\n  readonly maxSizeBytes: number;\n  readonly maxSizeAfterCompressionBytes: number;\n  readonly compressionRatio: number;\n  readonly guidance: string;\n  readonly docsUrl?: string;\n  readonly correlationId?: string;\n\n  constructor(args: {\n    message: string;\n    kind: \"uncompressed_exceeds_limit\" | \"compressed_exceeds_limit\";\n    operationName: string;\n    resultSizeBytes: number;\n    resultSizeAfterCompressionBytes: number;\n    maxSizeBytes: number;\n    maxSizeAfterCompressionBytes: number;\n    compressionRatio: number;\n    guidance: string;\n    docsUrl?: string;\n    correlationId?: string;\n  }) {\n    super(args.message);\n    this.name = \"ResultTooLargeError\";\n    this.kind = args.kind;\n    this.operationName = args.operationName;\n    this.resultSizeBytes = args.resultSizeBytes;\n    this.resultSizeAfterCompressionBytes = args.resultSizeAfterCompressionBytes;\n    this.maxSizeBytes = args.maxSizeBytes;\n    this.maxSizeAfterCompressionBytes = args.maxSizeAfterCompressionBytes;\n    this.compressionRatio = args.compressionRatio;\n    this.guidance = args.guidance;\n    this.docsUrl = args.docsUrl;\n    this.correlationId = args.correlationId;\n  }\n}\n\n/**\n * Externalized result's S3 object is missing — sentinel points to a key\n * that returned 404 (or a fetchDeferred fallback returned not-found).\n * Possible causes: lifecycle expiration with stale Postgres reference,\n * GDPR purge mid-replay, or a writer/reader binding inconsistency.\n * Terminal.\n */\nexport class ResultNotFoundError extends Error {\n  readonly executionId?: string;\n  readonly operationId?: string;\n  readonly correlationId?: string;\n\n  constructor(\n    message: string,\n    args: {\n      executionId?: string;\n      operationId?: string;\n      correlationId?: string;\n    } = {},\n  ) {\n    super(message);\n    this.name = \"ResultNotFoundError\";\n    this.executionId = args.executionId;\n    this.operationId = args.operationId;\n    this.correlationId = args.correlationId;\n  }\n}\n\n/**\n * Externalized result failed integrity verification. `kind` discriminates\n * the failure mode so callers can branch on it for diagnostics. Terminal —\n * the SDK does not retry, since retry would surface the same corruption.\n */\nexport class ResultCorruptError extends Error {\n  readonly kind:\n    | \"checksum_mismatch\"\n    | \"decompress_error\"\n    | \"zstd_version_mismatch\"\n    | \"envelope_sig_invalid\";\n  readonly executionId?: string;\n  readonly operationId?: string;\n  readonly correlationId?: string;\n\n  constructor(\n    message: string,\n    args: {\n      kind:\n        | \"checksum_mismatch\"\n        | \"decompress_error\"\n        | \"zstd_version_mismatch\"\n        | \"envelope_sig_invalid\";\n      executionId?: string;\n      operationId?: string;\n      correlationId?: string;\n    },\n  ) {\n    super(message);\n    this.name = \"ResultCorruptError\";\n    this.kind = args.kind;\n    this.executionId = args.executionId;\n    this.operationId = args.operationId;\n    this.correlationId = args.correlationId;\n  }\n}\n\n/**\n * Thrown when an operation name starts with a reserved prefix used by the\n * SDK for internal dormancy tracker bookkeeping. Without this guard, a\n * user-named operation could collide with a synthetic tracker id (e.g.\n * the checkpoint protectors registered in the step and wait paths) and\n * cause the synthetic worker's complete() to terminate the user's\n * operation prematurely.\n */\nexport class ReservedOperationNameError extends Error {\n  constructor(name: string, prefix: string) {\n    super(\n      `Operation name \"${name}\" uses the reserved prefix \"${prefix}\" -- ` +\n        `this prefix is used by the SDK for internal bookkeeping. ` +\n        `Pick a different name.`,\n    );\n    this.name = \"ReservedOperationNameError\";\n  }\n}\n\n/**\n * Thrown when user code starts a durable operation after its tick released\n * the lease. This happens when work outlives the run: for example, one\n * branch of a Promise.all rejects, the run ends, and another branch goes on\n * to its next step. The operation cannot be saved, so it must not run.\n */\nconst TICK_RELEASED_SYMBOL = Symbol.for(\n  \"@zapier/zapier-durable/TickReleasedError\",\n);\n\nexport class TickReleasedError extends Error {\n  // Like LeaseConflictError: user code imports the main entry point, and the\n  // runner that throws this is a separate bundled copy.\n  static [Symbol.hasInstance](error: unknown): boolean {\n    if (this !== TickReleasedError) {\n      return Function.prototype[Symbol.hasInstance].call(this, error);\n    }\n    return error instanceof Error && TICK_RELEASED_SYMBOL in error;\n  }\n\n  constructor(name: string) {\n    super(\n      `Operation \"${name}\" started after this tick released its lease; it was not run.`,\n    );\n    this.name = \"TickReleasedError\";\n    Object.defineProperty(this, TICK_RELEASED_SYMBOL, { value: true });\n  }\n}\n\n/**\n * Checkout refused with 426: the execution was stamped with a wire_version\n * higher than this package advertises it understands (the\n * x-zapier-durable-wire-version header). Terminal — upgrade the SDK; the\n * runtime does not retry.\n */\nexport class WireVersionMismatchError extends Error {\n  constructor(executionId: string) {\n    super(\n      `Execution \"${executionId}\" requires a newer SDK: its wire ` +\n        `version exceeds the maximum this SDK understands.`,\n    );\n    this.name = \"WireVersionMismatchError\";\n  }\n}\n\n/**\n * Checkout was refused because the execution is already terminal (server\n * responded 409 Conflict on a `completed` or `failed` execution). The common\n * cause is a duplicate event replayed against an inbox execution that already\n * finished: create matched the existing execution by (inbox, idempotencyKey),\n * but there is no tick left to run. Terminal — read the outcome with\n * `GET /api/v0/executions/{id}` rather than retrying.\n */\nexport class ExecutionTerminalError extends Error {\n  readonly executionId: string;\n\n  constructor(executionId: string) {\n    super(\n      `Execution \"${executionId}\" is already completed or failed and cannot ` +\n        `be checked out.`,\n    );\n    this.name = \"ExecutionTerminalError\";\n    this.executionId = executionId;\n  }\n}\n\n/**\n * Create was refused because the `idempotencyKey` is already in use within the\n * inbox for a structurally different request (server responded 409 Conflict).\n * An identical re-create returns the existing execution instead. Terminal —\n * retrying sends the same conflicting body; pick a distinct key.\n */\nexport class IdempotencyConflictError extends Error {\n  readonly inbox: string;\n  readonly idempotencyKey: string;\n\n  constructor(inbox: string, idempotencyKey: string) {\n    super(\n      `Idempotency key \"${idempotencyKey}\" in inbox \"${inbox}\" is already ` +\n        `used by an execution created from a different request.`,\n    );\n    this.name = \"IdempotencyConflictError\";\n    this.inbox = inbox;\n    this.idempotencyKey = idempotencyKey;\n  }\n}\n\n/**\n * Callback delivery was refused because the callback has expired and can no\n * longer be delivered (server responded 410 Gone): a gated callback past its\n * server deadline, or a legacy callback that crossed its advisory expiry while\n * the deciding update ran. Terminal — the payload was not recorded and the\n * deliverer remains the source of truth; the SDK does not retry.\n */\nexport class CallbackExpiredError extends Error {\n  readonly token: string;\n\n  constructor(token: string) {\n    super(`Callback \"${token}\" has expired and can no longer be delivered.`);\n    this.name = \"CallbackExpiredError\";\n    this.token = token;\n  }\n}\n\n/**\n * Callback delivery conflicted with a settled state (server responded 409\n * Conflict): the callback already completed with a structurally different\n * payload, or it is otherwise no longer deliverable (a rare delivery-race\n * re-read where the row moved on or vanished). An idempotent, structurally\n * identical re-delivery returns 200 instead. Terminal — the SDK does not retry.\n *\n * Note: the server sends `{ error: \"already_completed\" }` as the 409 body; this\n * error is keyed on the 409 status, not that string, so the mapping holds\n * across all three server cases (different-payload, non-pending, vanished).\n */\nexport class CallbackConflictError extends Error {\n  readonly token: string;\n\n  constructor(token: string) {\n    super(\n      `Callback \"${token}\" could not be delivered: it was already settled ` +\n        `(completed with a different payload, or no longer deliverable).`,\n    );\n    this.name = \"CallbackConflictError\";\n    this.token = token;\n  }\n}\n\n/**\n * A user-supplied value failed SDK-side validation before any checkpoint was\n * sent (e.g. an out-of-range or non-integer wait duration). Carries the\n * offending value. Terminal — a deterministic input error fails identically on\n * every replay, so the runtime does not retry.\n */\nexport class DurableValidationError extends Error {\n  readonly value: unknown;\n\n  constructor(value: unknown, message: string) {\n    super(message);\n    this.name = \"DurableValidationError\";\n    this.value = value;\n  }\n}\n\n/**\n * Check if an error is an SDK error that should NOT be retried.\n * Note: DeterminismViolation is checked separately in runner.ts.\n */\nexport function isSdkError(error: unknown): boolean {\n  return (\n    error instanceof DuplicateNameError ||\n    error instanceof NestedStepError ||\n    error instanceof SuspendInsideStepError ||\n    error instanceof StepExhaustedError ||\n    error instanceof LeaseConflictError ||\n    error instanceof RequestOutcomeUnknownError ||\n    error instanceof OperationTypeMismatchError ||\n    error instanceof ResultTooLargeError ||\n    error instanceof ResultNotFoundError ||\n    error instanceof ResultCorruptError ||\n    error instanceof ReservedOperationNameError ||\n    error instanceof TickReleasedError ||\n    error instanceof WireVersionMismatchError ||\n    error instanceof DurableValidationError ||\n    error instanceof CallbackExpiredError ||\n    error instanceof CallbackConflictError ||\n    error instanceof ExecutionTerminalError ||\n    error instanceof IdempotencyConflictError\n  );\n}\n","/**\n * Determinism Guard\n *\n * Provides runtime protection against non-deterministic API usage\n * outside of steps. Uses AsyncLocalStorage for mode tracking.\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\n\n// ============================================================================\n//  CONFIGURATION SCHEMA\n// ============================================================================\n\n/**\n * Kind of global to patch - affects how patching works.\n */\ntype GlobalKind = \"function\" | \"constructor\" | \"method\" | \"getter\";\n\n/**\n * Configuration for a global property to guard.\n */\nexport interface GlobalGuardConfig {\n  /** Path to the global (e.g., \"Math.random\", \"Date.now\", \"fetch\") */\n  path: string;\n  /** Kind of global - affects patching strategy */\n  kind?: GlobalKind;\n  /** Custom guard function (optional, defaults to standard assert) */\n  guard?: (guard: DeterminismGuard) => (...args: unknown[]) => unknown;\n}\n\n/**\n * Configuration for a module to shim.\n */\nexport interface ModuleShimConfig {\n  /** Primary module specifier (e.g., \"node:crypto\") */\n  module: string;\n  /** Additional specifiers to match (e.g., [\"crypto\"] for bare import) */\n  match?: string[];\n  /** Functions to guard (calls assert before invoking) */\n  guarded: string[];\n  /** Functions to pass through unchanged (or \"*\" for all others) */\n  passthrough: string[] | \"*\";\n}\n\n/**\n * Full configuration for the determinism guard system.\n */\nexport interface DeterminismGuardConfig {\n  globals: GlobalGuardConfig[];\n  modules: ModuleShimConfig[];\n}\n\n// ============================================================================\n//  DEFAULT CONFIGURATIONS\n// ============================================================================\n\nexport const NODE_GLOBALS: GlobalGuardConfig[] = [\n  // Random\n  { path: \"Math.random\", kind: \"method\" },\n\n  // Time - Date proxy handles Date(), new Date(), AND Date.now()\n  { path: \"Date\", kind: \"constructor\" },\n  // NOTE: Date.now is NOT listed separately - it's handled by the Date proxy\n\n  // Network\n  { path: \"fetch\", kind: \"function\" },\n\n  // Timers\n  { path: \"setTimeout\", kind: \"function\" },\n  { path: \"setInterval\", kind: \"function\" },\n  { path: \"setImmediate\", kind: \"function\" },\n\n  // High-resolution time\n  { path: \"performance.now\", kind: \"method\" },\n  { path: \"performance.timeOrigin\", kind: \"getter\" },\n\n  // Process (node-specific, guarded at global level)\n  { path: \"process.hrtime\", kind: \"method\" },\n  { path: \"process.hrtime.bigint\", kind: \"method\" },\n  { path: \"process.uptime\", kind: \"method\" },\n  { path: \"process.pid\", kind: \"getter\" },\n];\n\nexport const NODE_MODULES: ModuleShimConfig[] = [\n  // Crypto - random functions\n  {\n    module: \"node:crypto\",\n    match: [\"crypto\"],\n    guarded: [\n      \"randomUUID\",\n      \"randomBytes\",\n      \"randomInt\",\n      \"randomFill\",\n      \"randomFillSync\",\n      \"getRandomValues\",\n    ],\n    passthrough: \"*\",\n  },\n\n  // HTTP/HTTPS - network requests\n  {\n    module: \"node:http\",\n    match: [\"http\"],\n    guarded: [\"request\", \"get\", \"createServer\"],\n    passthrough: \"*\",\n  },\n  {\n    module: \"node:https\",\n    match: [\"https\"],\n    guarded: [\"request\", \"get\", \"createServer\"],\n    passthrough: \"*\",\n  },\n\n  // Timers\n  {\n    module: \"node:timers\",\n    match: [\"timers\"],\n    guarded: [\"setTimeout\", \"setInterval\", \"setImmediate\"],\n    passthrough: \"*\",\n  },\n\n  // File system - external state\n  {\n    module: \"node:fs\",\n    match: [\"fs\"],\n    guarded: [\n      \"readFile\",\n      \"readFileSync\",\n      \"writeFile\",\n      \"writeFileSync\",\n      \"readdir\",\n      \"readdirSync\",\n      \"stat\",\n      \"statSync\",\n      \"access\",\n      \"accessSync\",\n    ],\n    passthrough: \"*\",\n  },\n  {\n    module: \"node:fs/promises\",\n    match: [\"fs/promises\"],\n    guarded: [\"readFile\", \"writeFile\", \"readdir\", \"stat\", \"access\"],\n    passthrough: \"*\",\n  },\n\n  // DNS - network lookups\n  {\n    module: \"node:dns\",\n    match: [\"dns\"],\n    guarded: [\"lookup\", \"resolve\", \"resolve4\", \"resolve6\"],\n    passthrough: \"*\",\n  },\n\n  // Child process - external execution\n  {\n    module: \"node:child_process\",\n    match: [\"child_process\"],\n    guarded: [\"exec\", \"execSync\", \"spawn\", \"spawnSync\", \"fork\", \"execFile\"],\n    passthrough: \"*\",\n  },\n\n  // Net - raw sockets\n  {\n    module: \"node:net\",\n    match: [\"net\"],\n    guarded: [\"connect\", \"createConnection\", \"createServer\"],\n    passthrough: \"*\",\n  },\n\n  // Performance hooks\n  {\n    module: \"node:perf_hooks\",\n    match: [\"perf_hooks\"],\n    guarded: [\"performance\"],\n    passthrough: \"*\",\n  },\n];\n\nexport const BROWSER_GLOBALS: GlobalGuardConfig[] = [\n  { path: \"Math.random\", kind: \"method\" },\n  { path: \"Date\", kind: \"constructor\" },\n  { path: \"Date.now\", kind: \"method\" },\n  { path: \"fetch\", kind: \"function\" },\n  { path: \"setTimeout\", kind: \"function\" },\n  { path: \"setInterval\", kind: \"function\" },\n  { path: \"crypto.getRandomValues\", kind: \"method\" },\n  { path: \"crypto.randomUUID\", kind: \"method\" },\n];\n\nexport const CLOUDFLARE_GLOBALS: GlobalGuardConfig[] = [\n  { path: \"Math.random\", kind: \"method\" },\n  { path: \"Date\", kind: \"constructor\" },\n  { path: \"Date.now\", kind: \"method\" },\n  { path: \"fetch\", kind: \"function\" },\n  { path: \"setTimeout\", kind: \"function\" },\n  { path: \"crypto.getRandomValues\", kind: \"method\" },\n];\n\n// ============================================================================\n//  CORE GUARD\n// ============================================================================\n\n/** Symbol key for marking functions as already patched */\nconst PATCHED_SYMBOL = Symbol.for(\"@zapier/determinism-guard/patched\");\n\n/** Symbol key for storing the true original Date constructor */\nconst ORIGINAL_DATE_SYMBOL = Symbol.for(\n  \"@zapier/determinism-guard/original-date\",\n);\n\ntype Mode = \"GUARDED\" | \"ALLOWED\";\n\ninterface Store {\n  readonly stack: readonly Mode[];\n}\n\nexport class DeterminismViolation extends Error {\n  constructor(api: string) {\n    super(\n      `Non-deterministic API \"${api}\" called in GUARDED mode. Move this call into a step.`,\n    );\n    this.name = \"DeterminismViolation\";\n  }\n}\n\n/** Global symbol key for guard singleton - avoids duplicate package issues */\nconst GUARD_SYMBOL_KEY = \"@zapier/determinism-guard\";\n\nexport class DeterminismGuard {\n  private als = new AsyncLocalStorage<Store>();\n  private logging = false;\n  private violationCallback?: (error: DeterminismViolation) => void;\n\n  // Singleton via global symbol - survives duplicate package instances\n  private static _instance: DeterminismGuard;\n  static get instance(): DeterminismGuard {\n    // Check global symbol first (set by initGlobal or preload)\n    const global = (globalThis as any)[Symbol.for(GUARD_SYMBOL_KEY)];\n    if (global?.instance) {\n      return global.instance;\n    }\n    // Fallback to module-level singleton\n    if (!DeterminismGuard._instance) {\n      DeterminismGuard._instance = new DeterminismGuard();\n    }\n    return DeterminismGuard._instance;\n  }\n\n  /**\n   * Initialize global symbol for shims to find us.\n   * Call this once at startup (SDK does this automatically).\n   * This ensures shims work even with duplicate package copies.\n   */\n  initGlobal(): void {\n    const sym = Symbol.for(GUARD_SYMBOL_KEY);\n    (globalThis as any)[sym] = {\n      instance: this,\n      mode: null as Mode | null,\n      assert: this.assert.bind(this),\n    };\n    // Keep mode getter updated\n    Object.defineProperty((globalThis as any)[sym], \"mode\", {\n      get: () => this.mode,\n    });\n  }\n\n  // Default configs (exported as static data for ESLint plugins to consume)\n  static readonly NODE_GLOBALS = NODE_GLOBALS;\n  static readonly NODE_MODULES = NODE_MODULES;\n  static readonly BROWSER_GLOBALS = BROWSER_GLOBALS;\n  static readonly CLOUDFLARE_GLOBALS = CLOUDFLARE_GLOBALS;\n\n  setLogging(enabled: boolean): void {\n    this.logging = enabled;\n  }\n\n  /**\n   * Set a callback to be invoked when a violation is detected.\n   * Called BEFORE the error is thrown, allowing the SDK to signal\n   * a race condition even if user code catches the error.\n   */\n  setViolationCallback(\n    cb: ((error: DeterminismViolation) => void) | undefined,\n  ): void {\n    this.violationCallback = cb;\n  }\n\n  get mode(): Mode | null {\n    const store = this.als.getStore();\n    if (!store || store.stack.length === 0) return null;\n    return store.stack[store.stack.length - 1];\n  }\n\n  runGuarded<T>(fn: () => T): T {\n    return this.runWithMode(\"GUARDED\", fn);\n  }\n\n  runAllowed<T>(fn: () => T): T {\n    return this.runWithMode(\"ALLOWED\", fn);\n  }\n\n  private runWithMode<T>(mode: Mode, fn: () => T): T {\n    const parent = this.als.getStore();\n    const stack = parent ? [...parent.stack, mode] : [mode];\n    this.log(`-> ${mode} (depth ${stack.length})`);\n    try {\n      return this.als.run({ stack }, fn);\n    } finally {\n      this.log(`<- ${mode} (depth ${stack.length})`);\n    }\n  }\n\n  assert(api: string): void {\n    if (this.mode === \"GUARDED\") {\n      this.log(`BLOCKED: ${api}`);\n      const error = new DeterminismViolation(api);\n      this.violationCallback?.(error); // Signal before throwing\n      throw error;\n    }\n    this.log(`allowed: ${api}`);\n  }\n\n  wrap<T extends (...args: unknown[]) => unknown>(api: string, fn: T): T {\n    const self = this;\n    return function (this: unknown, ...args: unknown[]) {\n      self.assert(api);\n      return fn.apply(this, args);\n    } as T;\n  }\n\n  // -------------------------------------------------------------------------\n  // EXTENSIBLE GLOBAL PATCHING\n  // -------------------------------------------------------------------------\n\n  installGlobalGuards(configs: GlobalGuardConfig[] = NODE_GLOBALS): void {\n    // Idempotent: each global is tagged with PATCHED_SYMBOL to prevent double-wrapping.\n    for (const config of configs) {\n      this.patchGlobal(config);\n    }\n    this.log(`Processed ${configs.length} global guard configs`);\n  }\n\n  private patchGlobal(config: GlobalGuardConfig): void {\n    const { path: apiPath, guard: customGuard } = config;\n    const parts = apiPath.split(\".\");\n\n    // Special case for Date constructor\n    if (apiPath === \"Date\") {\n      this.patchDateConstructor();\n      return;\n    }\n\n    // Safety: Date.now is handled by the Date proxy - patching it separately causes recursion\n    if (apiPath === \"Date.now\") {\n      this.log(`Skipping Date.now (handled by Date proxy)`);\n      return;\n    }\n\n    if (parts.length === 1) {\n      const name = parts[0];\n      const current = (globalThis as Record<string, unknown>)[name];\n      if (typeof current === \"function\") {\n        // Skip if already patched (idempotent)\n        if ((current as any)[PATCHED_SYMBOL] === apiPath) {\n          this.log(`Skipping ${apiPath} (already patched)`);\n          return;\n        }\n\n        let wrapped: (...args: unknown[]) => unknown;\n        if (customGuard) {\n          wrapped = customGuard(this) as (...args: unknown[]) => unknown;\n        } else {\n          wrapped = this.wrap(\n            apiPath,\n            current as (...args: unknown[]) => unknown,\n          );\n        }\n        (wrapped as any)[PATCHED_SYMBOL] = apiPath;\n        (globalThis as Record<string, unknown>)[name] = wrapped;\n      }\n    } else if (parts.length === 2) {\n      const [obj, prop] = parts;\n      const target = (\n        globalThis as unknown as Record<string, Record<string, unknown>>\n      )[obj];\n      if (target && typeof target[prop] === \"function\") {\n        const current = target[prop] as (...args: unknown[]) => unknown;\n        // Skip if already patched (idempotent)\n        if ((current as any)[PATCHED_SYMBOL] === apiPath) {\n          this.log(`Skipping ${apiPath} (already patched)`);\n          return;\n        }\n\n        const wrapped = this.wrap(apiPath, current.bind(target));\n        (wrapped as any)[PATCHED_SYMBOL] = apiPath;\n        target[prop] = wrapped;\n      }\n    }\n  }\n\n  private patchDateConstructor(): void {\n    const self = this;\n\n    // Check if already patched (idempotent)\n    const existing = (globalThis as any).Date;\n    if (existing && (existing as any)[PATCHED_SYMBOL] === \"Date\") {\n      this.log(`Skipping Date (already patched)`);\n      return;\n    }\n\n    // Always wrap the TRUE original Date, not the current (possibly proxied) Date.\n    // This prevents recursive calls when Date.now() is invoked.\n    const OriginalDate: typeof Date =\n      (globalThis as any)[ORIGINAL_DATE_SYMBOL] ?? Date;\n\n    // Store the original Date once (survives multiple package copies via Symbol.for)\n    if (!(globalThis as any)[ORIGINAL_DATE_SYMBOL]) {\n      (globalThis as any)[ORIGINAL_DATE_SYMBOL] = OriginalDate;\n    }\n\n    const GuardedDate = new Proxy(OriginalDate, {\n      apply(_target, _thisArg, argArray) {\n        self.assert(\"Date()\");\n        return (OriginalDate as unknown as (...args: unknown[]) => unknown)(\n          ...argArray,\n        );\n      },\n      construct(_target, argArray, newTarget) {\n        self.assert(\"new Date()\");\n        return Reflect.construct(OriginalDate, argArray, newTarget);\n      },\n      get(target, prop, receiver) {\n        if (prop === \"now\") {\n          // CRITICAL: Call OriginalDate.now, NOT target.now (which could be patched)\n          const fn = () => {\n            self.assert(\"Date.now()\");\n            return OriginalDate.now();\n          };\n          (fn as any)[PATCHED_SYMBOL] = \"Date.now()\";\n          return fn;\n        }\n        return Reflect.get(target, prop, receiver);\n      },\n    });\n\n    (GuardedDate as any)[PATCHED_SYMBOL] = \"Date\";\n    (globalThis as { Date: typeof Date }).Date = GuardedDate as typeof Date;\n  }\n\n  private log(msg: string): void {\n    if (this.logging) {\n      console.log(`  [guard] ${msg}`);\n    }\n  }\n}\n\n// ============================================================================\n//  SHIM GENERATOR\n// ============================================================================\n\n/**\n * Generate ESM shim source code.\n * Uses global symbol for guard lookup to avoid duplicate singleton issues\n * when bundlers create multiple copies of the package.\n */\nexport function generateShimSource(config: ModuleShimConfig): string {\n  const { module: moduleName, guarded } = config;\n  const requireName = moduleName.replace(/^node:/, \"\");\n  const apiPrefix = requireName;\n\n  // Get all exports from the real module\n  let realExports: string[] = [];\n  try {\n    const req = createRequire(import.meta.url);\n    realExports = Object.keys(req(requireName)).filter(\n      (k) =>\n        !guarded.includes(k) && !k.startsWith(\"_\") && /^[a-zA-Z_$]/.test(k),\n    );\n  } catch {\n    realExports = [];\n  }\n\n  return `// Generated shim for ${moduleName}\n// Uses global symbol to avoid duplicate singleton issues\nimport { createRequire } from \"node:module\";\n\nconst require = createRequire(import.meta.url);\nconst real = require(\"${requireName}\");\n\n// Guard lookup via global symbol - set by DeterminismGuard.initGlobal()\nconst GUARD_SYMBOL = Symbol.for(\"@zapier/determinism-guard\");\n\nfunction getGuard() {\n  return globalThis[GUARD_SYMBOL];\n}\n\nfunction assert(api) {\n  const guard = getGuard();\n  if (guard && guard.mode === \"GUARDED\") {\n    throw new Error(\\`Non-deterministic API \"\\${api}\" called in GUARDED mode. Move this call into a step.\\`);\n  }\n}\n\n// Guarded exports\n${guarded\n  .map(\n    (fn) => `\nexport function ${fn}(...args) {\n  assert(\"${apiPrefix}.${fn}\");\n  return real.${fn}.apply(real, args);\n}`,\n  )\n  .join(\"\\n\")}\n\n// Default export with guarded functions\nexport default {\n  ...real,\n${guarded.map((fn) => `  ${fn},`).join(\"\\n\")}\n};\n\n// Re-export non-guarded items (deterministic functions pass through)\n${realExports.map((k) => `export const ${k} = real.${k};`).join(\"\\n\")}\n`;\n}\n\n// ============================================================================\n//  ESBUILD PLUGIN\n// ============================================================================\n\ninterface EsbuildPluginOptions {\n  modules?: ModuleShimConfig[];\n  shimDir?: string;\n  inline?: boolean;\n  /** Log every shimmed module to stdout. Default false. */\n  verbose?: boolean;\n}\n\nexport function guardedImportsPlugin(options: EsbuildPluginOptions = {}) {\n  const {\n    modules = NODE_MODULES,\n    shimDir = \"./node_modules/.determinism-guard-shims\",\n    inline = true,\n    verbose = false,\n  } = options;\n\n  // Build lookup map from all specifiers\n  const moduleMap = new Map<string, ModuleShimConfig>();\n  for (const config of modules) {\n    moduleMap.set(config.module, config);\n    if (config.match) {\n      for (const alias of config.match) {\n        moduleMap.set(alias, config);\n      }\n    }\n    if (config.module.startsWith(\"node:\")) {\n      const bare = config.module.slice(5);\n      if (!moduleMap.has(bare)) {\n        moduleMap.set(bare, config);\n      }\n    }\n  }\n\n  // Build regex from config (not hardcoded)\n  const specifiers = Array.from(moduleMap.keys()).map((s) =>\n    s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"),\n  );\n  const filterRegex = new RegExp(`^(${specifiers.join(\"|\")})$`);\n\n  return {\n    name: \"determinism-guard\",\n    setup(build: any) {\n      build.onResolve({ filter: filterRegex }, (args: any) => {\n        const config = moduleMap.get(args.path);\n        if (config) {\n          if (verbose) {\n            console.log(`[determinism-guard] Shimming: ${args.path}`);\n          }\n          return {\n            path: args.path,\n            namespace: \"determinism-guard-shim\",\n          };\n        }\n        return null;\n      });\n\n      build.onLoad(\n        { filter: /.*/, namespace: \"determinism-guard-shim\" },\n        (args: any) => {\n          const config = moduleMap.get(args.path);\n          if (!config) {\n            return { contents: `export * from \"${args.path}\";` };\n          }\n\n          if (inline) {\n            return {\n              contents: generateShimSource(config),\n              loader: \"js\",\n            };\n          } else {\n            const shimPath = path.join(\n              shimDir,\n              `${config.module.replace(\"node:\", \"\")}.mjs`,\n            );\n            return {\n              contents: `export * from \"${shimPath}\";`,\n              loader: \"js\",\n              resolveDir: process.cwd(),\n            };\n          }\n        },\n      );\n    },\n  };\n}\n\n// ============================================================================\n//  CJS PRELOAD GENERATOR\n// ============================================================================\n\nexport function generatePreloadSource(\n  config: {\n    globals?: GlobalGuardConfig[];\n    modules?: ModuleShimConfig[];\n  } = {},\n): string {\n  const { globals = NODE_GLOBALS, modules = NODE_MODULES } = config;\n\n  return `// Generated determinism guard preload\n// Use: NODE_OPTIONS=\"--require ./preload.cjs\" node app.mjs\n\nconst { AsyncLocalStorage } = require(\"node:async_hooks\");\n\nconst als = new AsyncLocalStorage();\n\nfunction getMode() {\n  const store = als.getStore();\n  return store?.stack?.[store.stack.length - 1] ?? null;\n}\n\nfunction assert(api) {\n  if (getMode() === \"GUARDED\") {\n    throw new Error(\\`Non-deterministic API \"\\${api}\" called in GUARDED mode. Move this call into a step.\\`);\n  }\n}\n\n// Exports for SDK to control mode\nmodule.exports.runGuarded = function(fn) {\n  const parent = als.getStore();\n  const stack = parent ? [...parent.stack, \"GUARDED\"] : [\"GUARDED\"];\n  return als.run({ stack }, fn);\n};\n\nmodule.exports.runAllowed = function(fn) {\n  const parent = als.getStore();\n  const stack = parent ? [...parent.stack, \"ALLOWED\"] : [\"ALLOWED\"];\n  return als.run({ stack }, fn);\n};\n\nmodule.exports.getMode = getMode;\n\n// ---- GLOBAL PATCHES ----\n${globals\n  .map((g) => {\n    const parts = g.path.split(\".\");\n    if (g.path === \"Date\") {\n      return `\nconst OriginalDate = Date;\nglobal.Date = new Proxy(OriginalDate, {\n  apply(target, thisArg, args) {\n    assert(\"Date()\");\n    return target(...args);\n  },\n  construct(target, args, newTarget) {\n    assert(\"new Date()\");\n    return Reflect.construct(target, args, newTarget);\n  },\n  get(target, prop, receiver) {\n    if (prop === \"now\") {\n      return () => { assert(\"Date.now()\"); return target.now(); };\n    }\n    return Reflect.get(target, prop, receiver);\n  },\n});`;\n    } else if (parts.length === 1) {\n      return `\nif (typeof global.${g.path} === \"function\") {\n  const original_${parts[0]} = global.${g.path};\n  global.${g.path} = function(...args) {\n    assert(\"${g.path}\");\n    return original_${parts[0]}.apply(this, args);\n  };\n}`;\n    } else if (parts.length === 2) {\n      return `\nif (global.${parts[0]} && typeof global.${parts[0]}.${parts[1]} === \"function\") {\n  const original_${parts.join(\"_\")} = global.${parts[0]}.${parts[1]}.bind(global.${parts[0]});\n  global.${parts[0]}.${parts[1]} = function(...args) {\n    assert(\"${g.path}\");\n    return original_${parts.join(\"_\")}(...args);\n  };\n}`;\n    }\n    return \"\";\n  })\n  .join(\"\\n\")}\n\n// ---- MODULE PATCHES ----\n${modules\n  .map((m) => {\n    const requireName = m.module.replace(/^node:/, \"\");\n    const varName = requireName.replace(/[^a-z]/gi, \"_\");\n    return `\ntry {\n  const ${varName} = require(\"${requireName}\");\n  ${m.guarded\n    .map(\n      (fn) => `\n  if (typeof ${varName}.${fn} === \"function\") {\n    const original_${varName}_${fn} = ${varName}.${fn};\n    ${varName}.${fn} = function(...args) {\n      assert(\"${requireName}.${fn}\");\n      return original_${varName}_${fn}.apply(this, args);\n    };\n  }`,\n    )\n    .join(\"\")}\n} catch (e) {}`;\n  })\n  .join(\"\\n\")}\n`;\n}\n","/**\n * Durable Execution Limits\n *\n * Sanity bounds for user-controllable fields. These limits must stay in\n * sync with the server-side schema; changes here require a coordinated\n * server change.\n */\n\nimport { DurableValidationError } from \"./errors\";\n\n/** Duration limits in seconds */\nexport const DURATION_LIMITS = {\n  /** Minimum duration for any timed operation */\n  MIN_SECONDS: 1,\n  /** Maximum duration: 1 year (365 days) */\n  MAX_SECONDS: 365 * 24 * 60 * 60, // 31536000\n} as const;\n\n/** Retry attempt limits */\nexport const RETRY_LIMITS = {\n  /** Minimum retry attempts (must try at least once) */\n  MIN_ATTEMPTS: 1,\n  /** Maximum retry attempts */\n  MAX_ATTEMPTS: 100,\n  /** Default retry attempts */\n  DEFAULT_ATTEMPTS: 5,\n} as const;\n\n/** Wait operation limits (ctx.wait) */\nexport const WAIT_LIMITS = {\n  /** Minimum wait duration in seconds */\n  MIN_SECONDS: DURATION_LIMITS.MIN_SECONDS,\n  /** Maximum wait duration in seconds (1 year) */\n  MAX_SECONDS: DURATION_LIMITS.MAX_SECONDS,\n} as const;\n\n/** Callback operation limits (ctx.createCallback) */\nexport const CALLBACK_LIMITS = {\n  /** Minimum callback TTL in seconds (1 minute) */\n  MIN_SECONDS: 60,\n  /** Maximum callback TTL in seconds (1 year) */\n  MAX_SECONDS: DURATION_LIMITS.MAX_SECONDS,\n  /** Default callback TTL in seconds (30 days) */\n  DEFAULT_SECONDS: 30 * 24 * 60 * 60, // 2592000\n} as const;\n\n/** Retry delay limits (exponential backoff) */\nexport const RETRY_DELAY_LIMITS = {\n  /** Minimum retry delay in milliseconds */\n  MIN_MS: 1000,\n  /** Maximum retry delay in milliseconds (5 minutes) */\n  MAX_MS: 5 * 60 * 1000, // 300000\n  /** Default base retry delay in milliseconds */\n  DEFAULT_BASE_MS: 5000,\n} as const;\n\n/**\n * Clamp a numeric value to within bounds (silent, no errors).\n * Use for computed values like retry delays.\n */\nexport function clamp(value: number, min: number, max: number): number {\n  return Math.max(min, Math.min(max, value));\n}\n\n/**\n * Validate and return wait duration in seconds.\n * @param seconds - User-provided wait duration\n * @throws Error if out of bounds\n *\n * Test mode: Set ZAPIER_DURABLE_TEST_MAX_WAIT_SECONDS to cap wait durations.\n * This allows integration tests to run quickly without waiting for real timers.\n */\nexport function validateWaitSeconds(seconds: number): number {\n  if (!Number.isSafeInteger(seconds)) {\n    throw new DurableValidationError(\n      seconds,\n      `Wait duration must be a whole number of seconds, got ${seconds}`,\n    );\n  }\n  if (seconds < WAIT_LIMITS.MIN_SECONDS || seconds > WAIT_LIMITS.MAX_SECONDS) {\n    throw new DurableValidationError(\n      seconds,\n      `Wait duration must be between ${WAIT_LIMITS.MIN_SECONDS} and ${WAIT_LIMITS.MAX_SECONDS} seconds, got ${seconds}`,\n    );\n  }\n\n  // Test mode: cap wait durations for faster integration tests\n  const testMaxWait = process.env.ZAPIER_DURABLE_TEST_MAX_WAIT_SECONDS;\n  if (testMaxWait) {\n    const maxWait = parseInt(testMaxWait, 10);\n    if (!isNaN(maxWait) && maxWait > 0 && seconds > maxWait) {\n      return maxWait;\n    }\n  }\n\n  return seconds;\n}\n\n/**\n * Validate and return callback timeout in seconds.\n * @param seconds - User-provided callback TTL (undefined = use default)\n * @throws Error if explicitly provided value is out of bounds\n *\n * The undefined → DEFAULT_SECONDS fallback is only reached on the legacy\n * (wire_version 0) callback path; v1 calls this only for explicit values.\n */\nexport function validateCallbackSeconds(seconds: number | undefined): number {\n  if (seconds === undefined) {\n    return CALLBACK_LIMITS.DEFAULT_SECONDS;\n  }\n  if (seconds < CALLBACK_LIMITS.MIN_SECONDS) {\n    throw new Error(\n      `Callback timeout ${seconds}s is below minimum (${CALLBACK_LIMITS.MIN_SECONDS}s = 1 minute)`,\n    );\n  }\n  if (seconds > CALLBACK_LIMITS.MAX_SECONDS) {\n    throw new Error(\n      `Callback timeout ${seconds}s exceeds maximum (${CALLBACK_LIMITS.MAX_SECONDS}s = 1 year)`,\n    );\n  }\n  return seconds;\n}\n\n/** Absolute expires_at from a timeout offset (storage clock, mirroring the server). */\nexport function computeExpiresAt(\n  nowMs: number,\n  timeoutSeconds: number,\n): string {\n  return new Date(nowMs + timeoutSeconds * 1000).toISOString();\n}\n\n/** Absolute resume_at from a wait duration (storage clock, mirroring the server). */\nexport function computeResumeAt(\n  nowMs: number,\n  durationSeconds: number,\n): string {\n  return new Date(nowMs + durationSeconds * 1000).toISOString();\n}\n\n/**\n * Validate and return max retry attempts.\n * @param attempts - User-provided max attempts (undefined = use default)\n * @throws Error if explicitly provided value is out of bounds\n */\nexport function validateMaxAttempts(attempts: number | undefined): number {\n  if (attempts === undefined) {\n    return RETRY_LIMITS.DEFAULT_ATTEMPTS;\n  }\n  if (attempts < RETRY_LIMITS.MIN_ATTEMPTS) {\n    throw new Error(\n      `Max attempts ${attempts} is below minimum (${RETRY_LIMITS.MIN_ATTEMPTS})`,\n    );\n  }\n  if (attempts > RETRY_LIMITS.MAX_ATTEMPTS) {\n    throw new Error(\n      `Max attempts ${attempts} exceeds maximum (${RETRY_LIMITS.MAX_ATTEMPTS})`,\n    );\n  }\n  return attempts;\n}\n\n/**\n * Clamp retry delay in milliseconds (for exponential backoff).\n * Silent clamping - this is computed internally, not user-provided.\n * @param ms - Computed retry delay\n * @returns Clamped delay between 1 second and 5 minutes\n *\n * Test mode: Set ZAPIER_DURABLE_TEST_MAX_RETRY_DELAY_MS to cap retry delays.\n * This allows integration tests to run quickly without waiting for retries.\n */\nexport function clampRetryDelayMs(ms: number): number {\n  let maxMs = RETRY_DELAY_LIMITS.MAX_MS;\n\n  // Test mode: cap retry delays for faster integration tests.\n  // `..._MS` is the deprecated abbreviated env var, read as a fallback.\n  const testMaxDelay =\n    process.env.ZAPIER_DURABLE_TEST_MAX_RETRY_DELAY_MILLISECONDS ??\n    process.env.ZAPIER_DURABLE_TEST_MAX_RETRY_DELAY_MS;\n  if (testMaxDelay) {\n    const parsed = parseInt(testMaxDelay, 10);\n    if (!isNaN(parsed) && parsed > 0) {\n      maxMs = parsed;\n    }\n  }\n\n  return clamp(ms, RETRY_DELAY_LIMITS.MIN_MS, maxMs);\n}\n","/**\n * Configuration management for the Durable SDK.\n *\n * Environment variables:\n * - ZAPIER_DURABLE_ADAPTER: \"filesystem\" (default) or \"zapier\"\n * - ZAPIER_DURABLE_FS_DIR: Directory for filesystem adapter (default: ~/.config/zapier-sdk/durable)\n * - ZAPIER_DURABLE_DETERMINISM_GUARD: \"on\" (default) or \"off\"\n * - ZAPIER_DURABLE_API_URL: Base URL for the API (default: https://sdkapi.zapier.com/api/v0/sdk/code-substrate-runner)\n * - ZAPIER_DURABLE_API_JWT: JWT token for API authentication (auto-generated for localhost)\n * - ZAPIER_DURABLE_WAIT_INPROCESS_THRESHOLD_SECONDS: a ctx.wait whose time\n *   remaining at first await is at or below this sleeps in-process instead\n *   of suspending the tick (default: 0, disabled)\n * - ZAPIER_DURABLE_WAIT_INPROCESS_BUDGET_SECONDS: per-tick cap on total\n *   seconds absorbed by in-process waits (default: 120)\n */\n\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { Clock } from \"./context\";\nimport type { DurableClient } from \"./types\";\nimport { MemoryClient } from \"./clients/memory\";\nimport { FilesystemClient } from \"./clients/filesystem\";\nimport { RestClient } from \"./clients/rest\";\n\n/**\n * Get the default durable state directory.\n * Uses ~/.config/zapier-sdk/durable on all platforms.\n */\nfunction getDefaultFsDir(): string {\n  return path.join(os.homedir(), \".config\", \"zapier-sdk\", \"durable\");\n}\n\nexport type AdapterType = \"filesystem\" | \"zapier\" | \"memory\";\n\nexport interface DurableConfig {\n  /** Adapter type: \"filesystem\", \"zapier\", or \"memory\" */\n  adapter: AdapterType;\n  /** Directory for filesystem adapter */\n  fsDir: string;\n  /** Enable determinism guard */\n  guardEnabled: boolean;\n  /** Base URL for Zapier API */\n  apiUrl: string;\n  /** JWT token for Zapier API */\n  apiToken?: string;\n  /** Enable debug logging */\n  logging: boolean;\n  /**\n   * A wait is always journaled pending at the call. If the time remaining\n   * until resume_at is at or below this threshold when the wait is first\n   * awaited, it sleeps out the remainder in-process and journals completed\n   * instead of suspending. 0 disables in-process waits (the default).\n   */\n  waitInProcessThresholdSeconds: number;\n  /**\n   * Per-tick cap on total seconds absorbed by in-process waits. Once a\n   * tick's cumulative in-process sleep would exceed this, further waits\n   * fall back to the checkpoint-and-suspend path even if under threshold.\n   */\n  waitInProcessBudgetSeconds: number;\n}\n\n// Global config singleton\nlet globalConfig: DurableConfig | null = null;\n\n/**\n * Get configuration from environment variables.\n */\nfunction getConfigFromEnv(): DurableConfig {\n  const adapter = (process.env.ZAPIER_DURABLE_ADAPTER ??\n    \"filesystem\") as AdapterType;\n  const fsDir = process.env.ZAPIER_DURABLE_FS_DIR ?? getDefaultFsDir();\n  const guardEnabled = process.env.ZAPIER_DURABLE_DETERMINISM_GUARD !== \"off\";\n  const apiUrl =\n    process.env.ZAPIER_DURABLE_API_URL ??\n    \"https://sdkapi.zapier.com/api/v0/sdk/code-substrate-runner\";\n  // New name: ZAPIER_DURABLE_API_JWT, old name kept for backwards compat\n  const apiToken =\n    process.env.ZAPIER_DURABLE_API_JWT ?? process.env.ZAPIER_DURABLE_API_TOKEN;\n  const logging = process.env.ZAPIER_DURABLE_DEBUG === \"true\";\n\n  const parsedThreshold = parseInt(\n    process.env.ZAPIER_DURABLE_WAIT_INPROCESS_THRESHOLD_SECONDS ?? \"\",\n    10,\n  );\n  const waitInProcessThresholdSeconds =\n    Number.isFinite(parsedThreshold) && parsedThreshold >= 1\n      ? parsedThreshold\n      : 0;\n\n  const parsedBudget = parseInt(\n    process.env.ZAPIER_DURABLE_WAIT_INPROCESS_BUDGET_SECONDS ?? \"\",\n    10,\n  );\n  const waitInProcessBudgetSeconds =\n    Number.isFinite(parsedBudget) && parsedBudget >= 1 ? parsedBudget : 120;\n\n  return {\n    adapter,\n    fsDir,\n    guardEnabled,\n    apiUrl,\n    apiToken,\n    logging,\n    waitInProcessThresholdSeconds,\n    waitInProcessBudgetSeconds,\n  };\n}\n\n/**\n * Get current configuration. If not explicitly set, reads from environment.\n */\nexport function getConfig(): DurableConfig {\n  if (!globalConfig) {\n    globalConfig = getConfigFromEnv();\n  }\n  return globalConfig;\n}\n\n/**\n * Set global configuration. Call this at startup if you need custom config.\n */\nexport function configureDurable(\n  config: Partial<DurableConfig>,\n): DurableConfig {\n  const defaults = getConfigFromEnv();\n  globalConfig = {\n    ...defaults,\n    ...config,\n  };\n  return globalConfig;\n}\n\n/**\n * Reset configuration to defaults (mainly for testing).\n */\nexport function resetConfig(): void {\n  globalConfig = null;\n}\n\n/**\n * Create a DurableClient based on current configuration.\n */\nexport function createClient(\n  configOverrides?: Partial<DurableConfig>,\n  clientOptions?: {\n    /** Client-side clock injection is intended for local adapters (memory,\n     *  filesystem) and tests; pass the same instance to runTick /\n     *  DurableCallOptions for deterministic timing. The zapier adapter does\n     *  not receive it. */\n    clock?: Clock;\n  },\n): DurableClient {\n  const config = configOverrides\n    ? { ...getConfig(), ...configOverrides }\n    : getConfig();\n\n  switch (config.adapter) {\n    case \"memory\":\n      const memClient = new MemoryClient({ clock: clientOptions?.clock });\n      memClient.setLogging(config.logging);\n      return memClient;\n\n    case \"filesystem\":\n      const fsClient = new FilesystemClient({\n        baseDir: config.fsDir,\n        logging: config.logging,\n        clock: clientOptions?.clock,\n      });\n      return fsClient;\n\n    case \"zapier\":\n      return new RestClient({\n        baseUrl: config.apiUrl,\n        token: config.apiToken,\n        logging: config.logging,\n      });\n\n    default:\n      throw new Error(`Unknown adapter type: ${config.adapter}`);\n  }\n}\n","/**\n * Filesystem-based DurableClient implementation for local development and CLI.\n *\n * Storage structure:\n * .zapier-durable/\n *   executions/\n *     {execution_id}/\n *       execution.json\n *       operations.json\n *   callbacks/\n *     {callback_token}.json\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport Ajv from \"ajv\";\nimport { type Clock, defaultClock } from \"../context\";\nimport { SDK_WIRE_VERSION_MAX } from \"../wire-version\";\nimport { CallbackConflictError, CallbackExpiredError } from \"../errors\";\nimport {\n  applyCheckpointUpdate,\n  classifyDelivery,\n  resolveDeadlineFields,\n  resolveResumeAt,\n  settleElapsedDeadlines,\n} from \"./shared\";\nimport type {\n  DurableClient,\n  CreateExecutionRequest,\n  CreateExecutionResponse,\n  CheckoutRequest,\n  CheckoutResponse,\n  CheckpointRequest,\n  CheckpointResponse,\n  ReleaseRequest,\n  ReleaseResponse,\n  CallbackRequest,\n  CallbackResponse,\n  Execution,\n  Operation,\n} from \"../types\";\n\n// Ajv instance for JSON Schema validation\nconst AjvClass = (Ajv as unknown as { default?: typeof Ajv }).default || Ajv;\nconst ajv = new AjvClass({ allErrors: true });\n\nfunction generateUuidV7(): string {\n  const timestamp = Date.now();\n  const timestampHex = timestamp.toString(16).padStart(12, \"0\");\n  const randomPart = Math.random().toString(16).slice(2, 14).padStart(12, \"0\");\n  const randomPart2 = Math.random().toString(16).slice(2, 6).padStart(4, \"0\");\n  return `${timestampHex.slice(0, 8)}-${timestampHex.slice(8, 12)}-7${randomPart.slice(0, 3)}-${randomPart2}-${randomPart.slice(3, 15)}`;\n}\n\nexport interface FilesystemClientOptions {\n  /** Base directory for storage (default: .zapier-durable) */\n  baseDir?: string;\n  /** Enable debug logging */\n  logging?: boolean;\n  /** Clock used for wait auto-completion at checkout and for callback\n   *  expiry / completed_at. When using a mock clock in tests, pass the\n   *  same instance to runTick(). */\n  clock?: Clock;\n  wireVersion?: number;\n}\n\ninterface StoredExecution extends Execution {\n  inbox?: string;\n  idempotency_key?: string;\n}\n\nexport class FilesystemClient implements DurableClient {\n  private baseDir: string;\n  private logging: boolean;\n  private clock: Clock;\n  private wireVersion: number;\n\n  /**\n   * Base URL for constructing callback URLs.\n   * For filesystem client, uses file:// protocol.\n   */\n  get callbackBaseUrl(): string {\n    return `file://${path.resolve(this.baseDir, \"callbacks\")}`;\n  }\n\n  constructor(options: FilesystemClientOptions = {}) {\n    this.baseDir = options.baseDir ?? \".zapier-durable\";\n    this.logging = options.logging ?? false;\n    this.clock = options.clock ?? defaultClock;\n    this.wireVersion = options.wireVersion ?? SDK_WIRE_VERSION_MAX;\n    this.ensureDirectories();\n  }\n\n  setLogging(enabled: boolean): void {\n    this.logging = enabled;\n  }\n\n  private log(msg: string): void {\n    if (this.logging) {\n      console.log(`  [fs-client] ${msg}`);\n    }\n  }\n\n  private ensureDirectories(): void {\n    const dirs = [\n      this.baseDir,\n      path.join(this.baseDir, \"executions\"),\n      path.join(this.baseDir, \"callbacks\"),\n    ];\n    for (const dir of dirs) {\n      if (!fs.existsSync(dir)) {\n        fs.mkdirSync(dir, { recursive: true });\n      }\n    }\n  }\n\n  private executionDir(executionId: string): string {\n    return path.join(this.baseDir, \"executions\", executionId);\n  }\n\n  private executionFile(executionId: string): string {\n    return path.join(this.executionDir(executionId), \"execution.json\");\n  }\n\n  private operationsFile(executionId: string): string {\n    return path.join(this.executionDir(executionId), \"operations.json\");\n  }\n\n  private callbackFile(token: string): string {\n    return path.join(this.baseDir, \"callbacks\", `${token}.json`);\n  }\n\n  private readExecution(executionId: string): StoredExecution | null {\n    const file = this.executionFile(executionId);\n    if (!fs.existsSync(file)) {\n      return null;\n    }\n    return JSON.parse(fs.readFileSync(file, \"utf-8\"));\n  }\n\n  private writeExecution(execution: StoredExecution): void {\n    const dir = this.executionDir(execution.id);\n    if (!fs.existsSync(dir)) {\n      fs.mkdirSync(dir, { recursive: true });\n    }\n    fs.writeFileSync(\n      this.executionFile(execution.id),\n      JSON.stringify(execution, null, 2),\n    );\n  }\n\n  private readOperations(executionId: string): Operation[] {\n    const file = this.operationsFile(executionId);\n    if (!fs.existsSync(file)) {\n      return [];\n    }\n    return JSON.parse(fs.readFileSync(file, \"utf-8\"));\n  }\n\n  private writeOperations(executionId: string, operations: Operation[]): void {\n    const dir = this.executionDir(executionId);\n    if (!fs.existsSync(dir)) {\n      fs.mkdirSync(dir, { recursive: true });\n    }\n    fs.writeFileSync(\n      this.operationsFile(executionId),\n      JSON.stringify(operations, null, 2),\n    );\n  }\n\n  private readCallback(\n    token: string,\n  ): { executionId: string; name: string } | null {\n    const file = this.callbackFile(token);\n    if (!fs.existsSync(file)) {\n      return null;\n    }\n    return JSON.parse(fs.readFileSync(file, \"utf-8\"));\n  }\n\n  private writeCallback(\n    token: string,\n    data: { executionId: string; name: string },\n  ): void {\n    fs.writeFileSync(this.callbackFile(token), JSON.stringify(data, null, 2));\n  }\n\n  async create(req: CreateExecutionRequest): Promise<CreateExecutionResponse> {\n    if (req.inbox && req.idempotency_key) {\n      for (const executionId of this.listExecutions()) {\n        const existing = this.readExecution(executionId);\n        if (\n          existing?.inbox === req.inbox &&\n          existing.idempotency_key === req.idempotency_key\n        ) {\n          this.log(`create: ${executionId} (ensure matched)`);\n          return {\n            id: existing.id,\n            name: existing.name,\n            status: existing.status,\n            inbox: existing.inbox,\n            idempotency_key: existing.idempotency_key,\n            created_at: existing.created_at,\n          };\n        }\n      }\n    }\n\n    const id = generateUuidV7();\n    const execution: StoredExecution = {\n      id,\n      name: req.name,\n      status: \"running\",\n      input: req.input,\n      metadata: req.metadata,\n      inbox: req.inbox,\n      idempotency_key: req.idempotency_key,\n      wire_version: this.wireVersion,\n      created_at: new Date().toISOString(),\n    };\n\n    this.writeExecution(execution);\n    this.writeOperations(id, []);\n    this.log(`create: ${id}`);\n\n    return {\n      id,\n      name: req.name,\n      status: \"running\",\n      inbox: req.inbox,\n      idempotency_key: req.idempotency_key,\n      created_at: execution.created_at,\n    };\n  }\n\n  async checkout(\n    executionId: string,\n    req?: CheckoutRequest,\n  ): Promise<CheckoutResponse> {\n    const execution = this.readExecution(executionId);\n    if (!execution) {\n      return { leased: false };\n    }\n\n    // Simple lease - always grant in filesystem mode\n    const leaseToken = generateUuidV7();\n    execution.lease_token = leaseToken;\n    execution.lease_expires_at = new Date(\n      Date.now() + 15 * 60 * 1000,\n    ).toISOString();\n\n    if (req?.resume_url) {\n      execution.resume_url = req.resume_url;\n    }\n    if (req?.resume_url_delivery_state) {\n      execution.resume_url_delivery_state = req.resume_url_delivery_state;\n    }\n\n    this.writeExecution(execution);\n\n    const ops = this.readOperations(executionId);\n\n    // Auto-complete elapsed pending waits (mirrors server behaviour).\n    const now = this.clock.now();\n    let opsChanged = false;\n    for (const op of ops) {\n      if (\n        op.type === \"wait\" &&\n        op.status === \"pending\" &&\n        op.resume_at &&\n        new Date(op.resume_at).getTime() <= now\n      ) {\n        op.status = \"completed\";\n        op.completed_at = op.resume_at;\n        opsChanged = true;\n      }\n    }\n\n    // Mirrors server behaviour.\n    if (settleElapsedDeadlines(ops, now)) {\n      opsChanged = true;\n    }\n\n    if (opsChanged) {\n      this.writeOperations(executionId, ops);\n    }\n\n    this.log(`checkout: ${executionId}, ${ops.length} operations`);\n\n    return {\n      leased: true,\n      lease_token: leaseToken,\n      execution,\n      operations: ops,\n    };\n  }\n\n  async checkpoint(\n    executionId: string,\n    req: CheckpointRequest,\n  ): Promise<CheckpointResponse> {\n    const ops = this.readOperations(executionId);\n    const existingIndex = ops.findIndex((op) => op.name === req.operation.name);\n\n    let op: Operation;\n\n    if (existingIndex >= 0) {\n      // Update existing (see shared.ts applyCheckpointUpdate).\n      const existing = ops[existingIndex];\n      applyCheckpointUpdate(existing, req.operation);\n      op = existing;\n      this.log(\n        `checkpoint (update): ${req.operation.name} -> ${existing.status}`,\n      );\n    } else {\n      // Insert new - generate callback_token server-side for callback ops\n      // Local adapters use simple hex tokens (no version byte)\n      const callbackToken =\n        req.operation.type === \"callback\"\n          ? generateUuidV7().replace(/-/g, \"\").slice(0, 22)\n          : undefined;\n\n      const nowMs = this.clock.now();\n      const deadline = resolveDeadlineFields(req.operation, nowMs);\n\n      op = {\n        id: generateUuidV7(),\n        execution_id: executionId,\n        name: req.operation.name,\n        type: req.operation.type,\n        status: req.operation.status,\n        result: req.operation.result,\n        error: req.operation.error,\n        retry_count: req.operation.retry_count ?? 0,\n        max_attempts: req.operation.max_attempts,\n        next_retry_at: req.operation.next_retry_at,\n        resume_at: resolveResumeAt(req.operation, nowMs),\n        callback_token: callbackToken,\n        payload_schema: req.operation.payload_schema,\n        expires_at: deadline.expires_at,\n        timeout_seconds: deadline.timeout_seconds,\n        created_at: new Date().toISOString(),\n      };\n      ops.push(op);\n      this.log(\n        `checkpoint (insert): ${req.operation.name} -> ${req.operation.status}`,\n      );\n\n      // Index callback token\n      if (op.callback_token) {\n        this.writeCallback(op.callback_token, { executionId, name: op.name });\n      }\n    }\n\n    this.writeOperations(executionId, ops);\n    return { ok: true, operation: op };\n  }\n\n  async release(\n    executionId: string,\n    req: ReleaseRequest,\n  ): Promise<ReleaseResponse> {\n    const execution = this.readExecution(executionId);\n    if (execution) {\n      execution.status = req.status;\n      execution.output = req.output;\n      execution.error = req.error;\n      execution.lease_token = undefined;\n      execution.lease_expires_at = undefined;\n      this.writeExecution(execution);\n    }\n\n    const done = req.status === \"completed\" || req.status === \"failed\";\n    this.log(`release: ${executionId} -> ${req.status}, done=${done}`);\n    return { ok: true, done };\n  }\n\n  async callback(\n    token: string,\n    req: CallbackRequest,\n  ): Promise<CallbackResponse> {\n    const index = this.readCallback(token);\n    if (!index) {\n      return { error: \"not_found\" };\n    }\n\n    const ops = this.readOperations(index.executionId);\n    const op = ops.find((o) => o.name === index.name);\n    if (!op) {\n      return { error: \"not_found\" };\n    }\n\n    // Deadline classification happens before payload validation (mirrors\n    // the server: expiry is decided from ingress time, and dead-callback\n    // paths never compile attacker-controllable schemas).\n    const verdict = classifyDelivery(op, this.clock.now());\n    if (verdict === \"refuse_settled\") {\n      throw new CallbackConflictError(token);\n    }\n    if (verdict === \"expire_and_refuse\") {\n      // Decided-once: journal the verdict before refusing (see classifyDelivery)\n      op.status = \"expired\";\n      this.writeOperations(index.executionId, ops);\n      this.log(`callback expired on late delivery: ${token} -> ${index.name}`);\n      throw new CallbackExpiredError(token);\n    }\n    if (verdict === \"refuse_expired\") {\n      throw new CallbackExpiredError(token);\n    }\n\n    // Validate payload against schema (if present) - matches API behavior\n    // req IS the payload (no wrapper) - third-party systems send raw payloads\n    if (op.payload_schema) {\n      const validate = ajv.compile(op.payload_schema as object);\n      if (!validate(req)) {\n        return { error: \"validation_failed\", details: validate.errors ?? [] };\n      }\n    }\n\n    op.status = \"completed\";\n    op.payload = req;\n    op.completed_at = new Date(this.clock.now()).toISOString(); // For race disambiguation\n    this.writeOperations(index.executionId, ops);\n    this.log(`callback delivered: ${token} -> ${index.name}`);\n\n    return { ok: true };\n  }\n\n  // Helper methods for CLI\n\n  /**\n   * Get an execution by ID. Returns null if not found.\n   */\n  getExecution(executionId: string): Execution | null {\n    return this.readExecution(executionId);\n  }\n\n  /**\n   * Get all operations for an execution.\n   */\n  getOperations(executionId: string): Operation[] {\n    return this.readOperations(executionId);\n  }\n\n  /**\n   * List all execution IDs in the store.\n   */\n  listExecutions(): string[] {\n    const dir = path.join(this.baseDir, \"executions\");\n    if (!fs.existsSync(dir)) {\n      return [];\n    }\n    return fs.readdirSync(dir).filter((name) => {\n      const stat = fs.statSync(path.join(dir, name));\n      return stat.isDirectory();\n    });\n  }\n\n  /**\n   * Delete an execution and its operations.\n   */\n  deleteExecution(executionId: string): boolean {\n    const dir = this.executionDir(executionId);\n    if (!fs.existsSync(dir)) {\n      return false;\n    }\n    fs.rmSync(dir, { recursive: true });\n    return true;\n  }\n\n  /**\n   * Clean up all data (useful for tests).\n   */\n  clear(): void {\n    if (fs.existsSync(this.baseDir)) {\n      fs.rmSync(this.baseDir, { recursive: true });\n    }\n    this.ensureDirectories();\n  }\n}\n","/**\n * Execution wire versioning.\n *\n * `executions.wire_version` is stamped once by the server as\n * min(server_current, sdk_declared_max) at the execution's first checkout\n * (before any operations exist) and echoed on every checkout thereafter.\n * The SDK dispatches callback-resolution behavior on it: v0 replays the\n * legacy behavior byte-identically; v1 resolves callbacks created with\n * `timeoutSeconds` to a CallbackResult.\n *\n * The server rejects a checkout with 426 wire-version-mismatch when an\n * SDK declares a lower max than the execution's stamped version — that\n * direction is unrecoverable (the SDK cannot know how to replay a newer\n * wire version). The opposite direction is safe: a newer SDK replays older\n * executions under their stamped version.\n *\n * Bump criterion: bump only when an execution created yesterday would\n * observe a different value at the same await under the new code.\n * Wire-protocol additions and new columns don't bump; the CallbackResult\n * wrapper does.\n */\n\n/** Highest execution wire version this SDK understands. */\nexport const SDK_WIRE_VERSION_MAX = 1;\n\n/**\n * Dedicated header the SDK uses to advertise its max wire version.\n * It rides every request, but the server reads it only at an execution's\n * first checkout, where it negotiates min(server_max, advertised) and\n * stamps `executions.wire_version` once. A later checkout by an SDK whose\n * max is below the stamped version gets a 426 wire-version-mismatch.\n */\nexport const WIRE_VERSION_HEADER = \"x-zapier-durable-wire-version\";\n","// Deadline state machine shared by the in-process clients; mirrors the server.\n\nimport type { CheckpointRequest, Operation } from \"../types\";\nimport { computeExpiresAt, computeResumeAt } from \"../limits\";\n\nfunction hasCallbackDeadline(op: Operation): boolean {\n  return op.type === \"callback\" && op.timeout_seconds != null;\n}\n\nfunction deadlinePassed(op: Operation, nowMs: number): boolean {\n  return (\n    op.expires_at !== undefined && new Date(op.expires_at).getTime() <= nowMs\n  );\n}\n\nexport function settleElapsedDeadlines(\n  ops: Operation[],\n  nowMs: number,\n): boolean {\n  let changed = false;\n  for (const op of ops) {\n    if (\n      hasCallbackDeadline(op) &&\n      op.status === \"pending\" &&\n      deadlinePassed(op, nowMs)\n    ) {\n      op.status = \"expired\";\n      changed = true;\n    }\n  }\n  return changed;\n}\n\nexport type DeliveryVerdict =\n  | \"accept\"\n  | \"expire_and_refuse\"\n  | \"refuse_expired\"\n  | \"refuse_settled\";\n\nexport function classifyDelivery(\n  op: Operation,\n  nowMs: number,\n): DeliveryVerdict {\n  if (op.status === \"expired\") {\n    return \"refuse_expired\";\n  }\n  if (op.status !== \"pending\") {\n    return \"refuse_settled\";\n  }\n  if (deadlinePassed(op, nowMs)) {\n    return hasCallbackDeadline(op) ? \"expire_and_refuse\" : \"refuse_expired\";\n  }\n  return \"accept\";\n}\n\nexport function resolveResumeAt(\n  op: CheckpointRequest[\"operation\"],\n  nowMs: number,\n): string | undefined {\n  if (op.type === \"wait\" && op.duration_seconds !== undefined) {\n    return computeResumeAt(nowMs, op.duration_seconds);\n  }\n  return op.resume_at;\n}\n\nexport function resolveDeadlineFields(\n  op: CheckpointRequest[\"operation\"],\n  nowMs: number,\n): Pick<Operation, \"expires_at\" | \"timeout_seconds\"> {\n  if (op.type !== \"callback\") {\n    return { expires_at: op.expires_at, timeout_seconds: undefined };\n  }\n  if (op.timeout_seconds !== undefined) {\n    return {\n      expires_at: computeExpiresAt(nowMs, op.timeout_seconds),\n      timeout_seconds: op.timeout_seconds,\n    };\n  }\n  // No-timeout callback: never synthesize a deadline — it must stay pending\n  // indefinitely. The expires_at passthrough is load-bearing: it preserves a\n  // real legacy v0 expires_at (client-stamped on the v0 path) so v0 journals\n  // replay byte-identically.\n  return {\n    expires_at: op.expires_at,\n    timeout_seconds: null,\n  };\n}\n\nexport function applyCheckpointUpdate(\n  existing: Operation,\n  update: CheckpointRequest[\"operation\"],\n): void {\n  const settledCallback =\n    existing.type === \"callback\" &&\n    (existing.status === \"completed\" || existing.status === \"expired\");\n\n  // Assign deadline fields unconditionally — null ?? x would flip a no-timeout callback into one with a deadline.\n  Object.assign(existing, update, {\n    callback_token: existing.callback_token,\n    status: settledCallback ? existing.status : update.status,\n    expires_at: existing.expires_at,\n    timeout_seconds: existing.timeout_seconds,\n  });\n}\n","/**\n * REST API DurableClient implementation for production use.\n *\n * Communicates with the Zapier-hosted durable execution backend.\n * Uses openapi-fetch for type-safe API requests.\n */\n\nimport createClientModule from \"openapi-fetch\";\nimport type {\n  DurableClient,\n  CreateExecutionRequest,\n  CreateExecutionResponse,\n  CheckoutRequest,\n  CheckoutResponse,\n  CheckpointRequest,\n  CheckpointResponse,\n  DeferredFieldsResponse,\n  ReleaseRequest,\n  ReleaseResponse,\n  CallbackRequest,\n  CallbackResponse,\n} from \"../types\";\nimport {\n  CAPABILITY_HEADER,\n  CapabilityPresignedV1,\n} from \"../externalization/constants\";\nimport { SDK_WIRE_VERSION_MAX, WIRE_VERSION_HEADER } from \"../wire-version\";\nimport {\n  CallbackConflictError,\n  CallbackExpiredError,\n  ExecutionTerminalError,\n  IdempotencyConflictError,\n  LeaseConflictError,\n  RequestOutcomeUnknownError,\n  ResultNotFoundError,\n  WireVersionMismatchError,\n} from \"../errors\";\n\n// openapi-fetch is external in the tsup build, and its CJS entry exposes the\n// client factory on `exports.default`. esbuild's node-mode interop therefore\n// hands the CJS build the whole exports object instead of the factory, so\n// unwrap `.default` when present. The ESM build binds the real default\n// export, making the fallback a no-op there.\nconst createClient =\n  (createClientModule as unknown as { default?: typeof createClientModule })\n    .default ?? createClientModule;\n\ninterface ApiPaths {\n  \"/api/v0/executions\": {\n    post: {\n      requestBody: { content: { \"application/json\": CreateExecutionRequest } };\n      responses: {\n        201: { content: { \"application/json\": CreateExecutionResponse } };\n      };\n    };\n  };\n  \"/api/v0/executions/{id}/checkout\": {\n    post: {\n      parameters: { path: { id: string } };\n      requestBody?: { content: { \"application/json\": CheckoutRequest } };\n      responses: {\n        200: { content: { \"application/json\": CheckoutResponse } };\n      };\n    };\n  };\n  \"/api/v0/executions/{id}/checkpoint\": {\n    post: {\n      parameters: { path: { id: string } };\n      requestBody: { content: { \"application/json\": CheckpointRequest } };\n      responses: {\n        200: { content: { \"application/json\": CheckpointResponse } };\n      };\n    };\n  };\n  \"/api/v0/executions/{id}/release\": {\n    post: {\n      parameters: { path: { id: string } };\n      requestBody: { content: { \"application/json\": ReleaseRequest } };\n      responses: {\n        200: { content: { \"application/json\": ReleaseResponse } };\n      };\n    };\n  };\n  \"/api/v0/callbacks/{token}\": {\n    post: {\n      parameters: { path: { token: string } };\n      requestBody: { content: { \"application/json\": CallbackRequest } };\n      responses: {\n        200: { content: { \"application/json\": CallbackResponse } };\n      };\n    };\n  };\n  \"/api/v0/executions/{id}/fetch_deferred\": {\n    post: {\n      parameters: { path: { id: string } };\n      requestBody: {\n        content: {\n          \"application/json\": { lease_token: string; operation_id: string };\n        };\n      };\n      responses: {\n        200: { content: { \"application/json\": DeferredFieldsResponse } };\n      };\n    };\n  };\n}\n\n// --- HTTP Retry Utilities ---\n// These handle transport-level retry (5xx, network errors).\n// Distinct from step retry (business logic retry when user code throws).\n\nexport interface HttpRetryConfig {\n  /** Maximum number of attempts (default: 3) */\n  maxAttempts: number;\n  /** Base delay in milliseconds (default: 500) */\n  baseDelayMs: number;\n  /** Maximum delay cap in milliseconds (default: 5000) */\n  maxDelayMs: number;\n  /** Jitter factor 0-1 (default: 0.5) */\n  jitterFactor: number;\n}\n\nexport const DEFAULT_HTTP_RETRY_CONFIG: HttpRetryConfig = {\n  maxAttempts: 3,\n  baseDelayMs: 500,\n  maxDelayMs: 5000,\n  jitterFactor: 0.5,\n};\n\n/**\n * Check if an HTTP status code is retriable.\n * Retriable: 5xx server errors, 408 timeout, 429 rate limit, network errors.\n */\nexport function isHttpRetriable(status: number | undefined): boolean {\n  if (status === undefined) return true; // Network error (no response)\n  if (status >= 500) return true; // Server errors\n  if (status === 408) return true; // Request timeout\n  if (status === 429) return true; // Rate limited\n  return false;\n}\n\n/**\n * Calculate delay for a given retry attempt using exponential backoff with jitter.\n */\nexport function calculateHttpDelay(\n  attempt: number,\n  config: HttpRetryConfig,\n): number {\n  const exponential = config.baseDelayMs * Math.pow(2, attempt - 1);\n  const capped = Math.min(exponential, config.maxDelayMs);\n  const jitter = Math.random() * config.jitterFactor * capped;\n  return Math.floor(capped + jitter);\n}\n\nfunction sleep(ms: number): Promise<void> {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Per-attempt request timeout for every RestClient network call. */\nconst HTTP_REQUEST_TIMEOUT_SECONDS = 30;\n\ninterface HttpResult<T> {\n  data?: T;\n  error?: unknown;\n  response?: Response;\n}\n\n/**\n * Marks fetch's own rejections (connection reset, refused connection, DNS\n * failure, a connection dropped mid-body) other than our timeout abort. The\n * request may or may not have reached the server, so a durable write that\n * fails this way has an unknown outcome. The original error is rethrown\n * unchanged; only the mark is added.\n */\nconst TRANSPORT_FAILURE = Symbol(\"durable.transportFailure\");\n\nfunction markTransportFailures(fetchImpl: typeof fetch): typeof fetch {\n  return async (input, init) => {\n    try {\n      const response = await fetchImpl(input, init);\n      // openapi-fetch reads the body after fetch returns, outside this catch.\n      // Draining a clone here buffers the whole body into the original, so a\n      // connection dropped mid-body is marked like one dropped before the\n      // headers, and openapi-fetch's later read cannot touch the socket.\n      await drainBody(response.clone());\n      return response;\n    } catch (error) {\n      if (\n        error instanceof Error &&\n        error.name !== \"AbortError\" &&\n        !(TRANSPORT_FAILURE in error)\n      ) {\n        Object.defineProperty(error, TRANSPORT_FAILURE, { value: true });\n      }\n      throw error;\n    }\n  };\n}\n\n/**\n * Read a body to its end, discarding each chunk as it arrives, so no second\n * full copy of the body is held (`fetchDeferred` can return several\n * megabytes).\n */\nasync function drainBody(response: Response): Promise<void> {\n  const reader = response.body?.getReader();\n  if (!reader) return;\n  while (!(await reader.read()).done) {\n    // Keep reading until the stream ends or rejects.\n  }\n}\n\nfunction isTransportFailure(error: unknown): error is Error {\n  return error instanceof Error && TRANSPORT_FAILURE in error;\n}\n\n/**\n * undici reports every transport failure as a bare \"fetch failed\" or\n * \"terminated\" and puts what happened (`read ECONNRESET`, `other side closed`)\n * on the cause.\n */\nfunction describeTransportFailure(error: Error): string {\n  return error.cause instanceof Error\n    ? `${error.message}: ${error.cause.message}`\n    : error.message;\n}\n\n/**\n * Run one request attempt under a bounded timeout.\n *\n * A timeout or transport failure is reported as a response-less failure, so\n * `isHttpRetriable` routes it into the caller's retry path instead of ending\n * the call.\n */\nasync function sendWithTimeout<T>(\n  operation: string,\n  send: (signal: AbortSignal) => Promise<HttpResult<T>>,\n): Promise<HttpResult<T> & { timedOut?: boolean }> {\n  const controller = new AbortController();\n  let timedOut = false;\n\n  const timer = setTimeout(() => {\n    timedOut = true;\n    controller.abort();\n  }, HTTP_REQUEST_TIMEOUT_SECONDS * 1000);\n\n  try {\n    return await send(controller.signal);\n  } catch (error) {\n    if (isTransportFailure(error)) {\n      return {\n        error: {\n          error: \"transport_failure\",\n          message: `${operation} transport failure: ${describeTransportFailure(error)}`,\n        },\n      };\n    }\n    // Aborting with no reason causes the platform to supply its default — a\n    // DOMException named \"AbortError\", which propagates up verbatim.\n    const isTimeoutAbort =\n      timedOut && error instanceof Error && error.name === \"AbortError\";\n    if (!isTimeoutAbort) throw error;\n    return {\n      timedOut: true,\n      error: {\n        error: \"request_timeout\",\n        message: `${operation} request timed out after ${HTTP_REQUEST_TIMEOUT_SECONDS}s`,\n      },\n    };\n  } finally {\n    clearTimeout(timer);\n  }\n}\n\nfunction isWireVersionMismatchBody(error: unknown): boolean {\n  return (\n    typeof error === \"object\" &&\n    error !== null &&\n    ((\"code\" in error && error.code === \"wire-version-mismatch\") ||\n      (\"error\" in error && error.error === \"wire-version-mismatch\"))\n  );\n}\n\n// --- Localhost Test JWT ---\n\n/**\n * Check if a URL is localhost (for auto-generating test JWT).\n */\nfunction isLocalhostUrl(url: string): boolean {\n  try {\n    const parsed = new URL(url);\n    return (\n      parsed.hostname === \"localhost\" ||\n      parsed.hostname === \"127.0.0.1\" || // pii:allow\n      parsed.hostname.startsWith(\"127.\")\n    );\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Generate a test JWT compatible with the durable API in dev mode.\n *\n * When the API is running with JWT signature verification disabled,\n * it skips signature verification but still validates the token structure.\n * This generates a properly-structured JWT for local development.\n */\nexport function generateLocalhostTestJwt(\n  opts: { userId?: string; accountId?: string } = {},\n): string {\n  const { userId = \"test-user-1\", accountId = \"test-account-1\" } = opts;\n\n  const header = { alg: \"RS256\", typ: \"JWT\", kid: \"localhost-dev-key\" };\n  const payload = {\n    // Standard JWT claims\n    sub: `customuser:${userId}`,\n    sub_type: \"customuser\",\n    iss: \"id.zapier.com\",\n    aud: \"zapier.com\",\n    exp: Math.floor(Date.now() / 1000) + 86400, // 24 hours\n    nbf: Math.floor(Date.now() / 1000),\n    iat: Math.floor(Date.now() / 1000),\n    jti: `localhost-${Date.now()}`,\n    scp: [\"user\"],\n    // Zapier-specific claims\n    \"zap:acc\": accountId,\n    \"zap:uid\": userId,\n    \"zap:rle\": \"admin\",\n    \"zap:rlm\": \"zapier.com\",\n    \"zap:tms\": [1],\n    \"zap:tmsown\": [1],\n  };\n\n  const encode = (obj: object) =>\n    Buffer.from(JSON.stringify(obj)).toString(\"base64url\");\n  return `${encode(header)}.${encode(payload)}.localhost-dev-signature`;\n}\n\n// --- RestClient ---\n\nexport interface RestClientOptions {\n  /** Base URL for the API (default: https://sdkapi.zapier.com/api/v0/sdk/code-substrate-runner) */\n  baseUrl?: string;\n  /** Base URL for callback URLs shown to users (may differ from API baseUrl) */\n  callbackBaseUrl?: string;\n  /** Authorization token (JWT). Auto-generated for localhost if not provided. */\n  token?: string;\n  /** Enable debug logging */\n  logging?: boolean;\n  /** HTTP retry configuration for transient failures (false to disable) */\n  httpRetry?: Partial<HttpRetryConfig> | false;\n  /**\n   * Opt out of advertising the `presigned-result-v1` capability. With the\n   * header absent, the server omits `presigned` blocks on externalized\n   * operations and the SDK falls back to `fetchDeferred` for every read.\n   * Use for restricted-egress environments that cannot reach S3 directly.\n   *\n   * Note: this does *not* disable the read-side hydration pass — the SDK\n   * still scans checkout responses for sentinel-prefixed fields and\n   * resolves them via `fetchDeferred`. Sentinels in user data would\n   * otherwise leak through as raw strings.\n   */\n  disablePresignedCapability?: boolean;\n}\n\nexport class RestClient implements DurableClient {\n  private client: ReturnType<typeof createClient<ApiPaths>>;\n  private _callbackBaseUrl: string;\n  private logging: boolean;\n  private httpRetryConfig: HttpRetryConfig | false;\n\n  get callbackBaseUrl(): string {\n    return this._callbackBaseUrl;\n  }\n\n  constructor(options: RestClientOptions = {}) {\n    const baseUrl =\n      options.baseUrl ??\n      \"https://sdkapi.zapier.com/api/v0/sdk/code-substrate-runner\";\n    this._callbackBaseUrl =\n      options.callbackBaseUrl ?? `${baseUrl}/api/v0/callbacks`;\n    this.logging = options.logging ?? false;\n\n    // Configure HTTP retry\n    if (options.httpRetry === false) {\n      this.httpRetryConfig = false;\n    } else {\n      this.httpRetryConfig = {\n        ...DEFAULT_HTTP_RETRY_CONFIG,\n        ...options.httpRetry,\n      };\n    }\n\n    // Determine token: use provided, or auto-generate for localhost\n    let token = options.token;\n    if (!token && isLocalhostUrl(baseUrl)) {\n      token = generateLocalhostTestJwt();\n      if (this.logging) {\n        console.log(\n          `  [rest-client] Auto-generated test JWT for localhost (requires the backend to be running in development mode)`,\n        );\n      }\n    }\n\n    const headers: Record<string, string> = {\n      \"Content-Type\": \"application/json\",\n    };\n\n    if (token) {\n      headers[\"Authorization\"] = `Bearer ${token}`;\n    }\n\n    if (!options.disablePresignedCapability) {\n      headers[CAPABILITY_HEADER] = CapabilityPresignedV1;\n    }\n\n    headers[WIRE_VERSION_HEADER] = String(SDK_WIRE_VERSION_MAX);\n\n    this.client = createClient<ApiPaths>({\n      baseUrl,\n      headers,\n      fetch: markTransportFailures(globalThis.fetch),\n    });\n  }\n\n  setLogging(enabled: boolean): void {\n    this.logging = enabled;\n  }\n\n  private log(msg: string): void {\n    if (this.logging) {\n      console.log(`  [rest-client] ${msg}`);\n    }\n  }\n\n  /**\n   * Execute an operation with HTTP retry logic for transient failures.\n   * Retries on 5xx, 408, 429, timeouts, and network errors.\n   */\n  private async withHttpRetry<T>(\n    operation: string,\n    fn: (signal: AbortSignal) => Promise<HttpResult<T>>,\n    options?: {\n      /** Handle a 409 identically regardless of retry history. */\n      onAny409?: () => T;\n    },\n  ): Promise<T> {\n    const config = this.httpRetryConfig;\n    const maxAttempts = config === false ? 1 : config.maxAttempts;\n\n    for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n      const { data, error, response, timedOut } = await sendWithTimeout(\n        operation,\n        fn,\n      );\n\n      if (data !== undefined) {\n        return data;\n      }\n\n      const status = response?.status;\n\n      if (status === 409 && options?.onAny409) {\n        return options.onAny409();\n      }\n\n      if (!isHttpRetriable(status)) {\n        throw new Error(`${operation} failed: ${JSON.stringify(error)}`);\n      }\n      // A retriable failure can follow a committed write, so the last one\n      // leaves the outcome unknown rather than failed.\n      if (config === false || attempt === maxAttempts) {\n        throw new RequestOutcomeUnknownError(\n          operation,\n          attempt,\n          JSON.stringify(error),\n        );\n      }\n\n      const delay = calculateHttpDelay(attempt, config);\n      this.log(\n        `${operation}: ${status ?? (timedOut ? \"timeout\" : \"network error\")}, retry ${attempt}/${maxAttempts} in ${delay}ms`,\n      );\n      await sleep(delay);\n    }\n\n    // Should never reach here, but TypeScript needs it\n    throw new Error(`${operation} failed after ${maxAttempts} attempts`);\n  }\n\n  async create(req: CreateExecutionRequest): Promise<CreateExecutionResponse> {\n    this.log(`create: ${req.name}`);\n\n    const data = await this.withHttpRetry(\n      \"create\",\n      (signal) => this.client.POST(\"/api/v0/executions\", { body: req, signal }),\n      {\n        onAny409: () => {\n          throw new IdempotencyConflictError(\n            req.inbox ?? \"\",\n            req.idempotency_key ?? \"\",\n          );\n        },\n      },\n    );\n\n    this.log(`created: ${data.id}`);\n    return data;\n  }\n\n  async checkout(\n    executionId: string,\n    req?: CheckoutRequest,\n  ): Promise<CheckoutResponse> {\n    this.log(`checkout: ${executionId}`);\n\n    const data = await this.withHttpRetry(\n      \"checkout\",\n      async (signal) => {\n        const res = await this.client.POST(\"/api/v0/executions/{id}/checkout\", {\n          params: { path: { id: executionId } },\n          body: req ?? {},\n          signal,\n        });\n        if (\n          res.response?.status === 426 ||\n          isWireVersionMismatchBody(res.error)\n        ) {\n          throw new WireVersionMismatchError(executionId);\n        }\n        return res;\n      },\n      {\n        onAny409: () => {\n          throw new ExecutionTerminalError(executionId);\n        },\n      },\n    );\n\n    if (data.leased) {\n      this.log(\n        `checkout: ${executionId}, ${data.operations.length} operations`,\n      );\n    } else {\n      this.log(`checkout: ${executionId}, not leased`);\n    }\n\n    return data;\n  }\n\n  async checkpoint(\n    executionId: string,\n    req: CheckpointRequest,\n  ): Promise<CheckpointResponse> {\n    this.log(`checkpoint: ${req.operation.name} -> ${req.operation.status}`);\n\n    const data = await this.withHttpRetry(\n      \"checkpoint\",\n      (signal) =>\n        this.client.POST(\"/api/v0/executions/{id}/checkpoint\", {\n          params: { path: { id: executionId } },\n          body: req,\n          signal,\n        }),\n      {\n        onAny409: () => {\n          throw new LeaseConflictError(executionId);\n        },\n      },\n    );\n\n    return data;\n  }\n\n  async release(\n    executionId: string,\n    req: ReleaseRequest,\n  ): Promise<ReleaseResponse> {\n    this.log(`release: ${executionId} -> ${req.status}`);\n\n    const data = await this.withHttpRetry(\n      \"release\",\n      (signal) =>\n        this.client.POST(\"/api/v0/executions/{id}/release\", {\n          params: { path: { id: executionId } },\n          body: req,\n          signal,\n        }),\n      {\n        onAny409: () => {\n          throw new LeaseConflictError(executionId);\n        },\n      },\n    );\n\n    this.log(`release: done=${data.done}`);\n    return data;\n  }\n\n  async callback(\n    token: string,\n    req: CallbackRequest,\n  ): Promise<CallbackResponse> {\n    this.log(`callback: ${token}`);\n\n    // Callback has special error handling - don't use withHttpRetry directly\n    const config = this.httpRetryConfig;\n    const maxAttempts = config === false ? 1 : config.maxAttempts;\n\n    for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n      const { data, error, response, timedOut } = await sendWithTimeout(\n        \"callback\",\n        (signal) =>\n          this.client.POST(\"/api/v0/callbacks/{token}\", {\n            params: { path: { token } },\n            body: req,\n            signal,\n          }),\n      );\n\n      if (data) {\n        this.log(`callback delivered: ${token}`);\n        return data;\n      }\n\n      // Handle specific error cases (these are not retry-able)\n      const errObj = error as { error?: string };\n      const status = response?.status;\n\n      // 410/409 are terminal delivery outcomes the server distinguishes by\n      // status code: 410 = the callback expired and can no longer be\n      // delivered; 409 = it already completed with a structurally different\n      // payload (an idempotent identical re-delivery returns 200). Surface them\n      // as typed errors so a delivering caller can tell these apart from a\n      // transient failure. Keyed on status, not the response body, so an\n      // unexpected body can't degrade a terminal outcome to a generic failure.\n      if (status === 410) {\n        throw new CallbackExpiredError(token);\n      }\n      if (status === 409) {\n        throw new CallbackConflictError(token);\n      }\n\n      if (errObj.error === \"not_found\") {\n        return { error: \"not_found\" };\n      }\n      if (errObj.error === \"validation_failed\") {\n        // Pass through AJV validation error details from API\n        const details = (error as { details?: unknown[] }).details ?? [];\n        return { error: \"validation_failed\", details };\n      }\n\n      // Check if we should retry\n      if (\n        config === false ||\n        !isHttpRetriable(status) ||\n        attempt === maxAttempts\n      ) {\n        throw new Error(`Failed to deliver callback: ${JSON.stringify(error)}`);\n      }\n\n      const delay = calculateHttpDelay(attempt, config);\n      this.log(\n        `callback: ${status ?? (timedOut ? \"timeout\" : \"network error\")}, retry ${attempt}/${maxAttempts} in ${delay}ms`,\n      );\n      await sleep(delay);\n    }\n\n    throw new Error(`Failed to deliver callback after ${maxAttempts} attempts`);\n  }\n\n  /**\n   * Universal fallback for externalized results: the server fetches and\n   * decompresses the S3 bundle and returns the full field bag inline.\n   * Used when the SDK has no capability header, when the presigned URL\n   * has expired/403'd, or when verification of the presigned path failed.\n   */\n  async fetchDeferred(\n    executionId: string,\n    operationId: string,\n    leaseToken: string,\n  ): Promise<DeferredFieldsResponse> {\n    this.log(`fetchDeferred: ${executionId}/${operationId}`);\n\n    const config = this.httpRetryConfig;\n    const maxAttempts = config === false ? 1 : config.maxAttempts;\n\n    for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n      const { data, error, response, timedOut } = await sendWithTimeout(\n        \"fetchDeferred\",\n        (signal) =>\n          this.client.POST(\"/api/v0/executions/{id}/fetch_deferred\", {\n            params: { path: { id: executionId } },\n            body: { lease_token: leaseToken, operation_id: operationId },\n            signal,\n          }),\n      );\n\n      if (data !== undefined) {\n        return data;\n      }\n\n      const status = response?.status;\n\n      // 404 = operation or its S3 object is gone; terminal, no retry.\n      if (status === 404) {\n        throw new ResultNotFoundError(\n          `fetchDeferred returned 404 for operation ${operationId}`,\n          { executionId, operationId },\n        );\n      }\n\n      if (\n        config === false ||\n        !isHttpRetriable(status) ||\n        attempt === maxAttempts\n      ) {\n        throw new Error(`fetchDeferred failed: ${JSON.stringify(error)}`);\n      }\n\n      const delay = calculateHttpDelay(attempt, config);\n      this.log(\n        `fetchDeferred: ${status ?? (timedOut ? \"timeout\" : \"network error\")}, retry ${attempt}/${maxAttempts} in ${delay}ms`,\n      );\n      await sleep(delay);\n    }\n\n    throw new Error(`fetchDeferred failed after ${maxAttempts} attempts`);\n  }\n}\n"],"mappings":"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","names":["import_ajv","import_node_async_hooks","path","path","Ajv","createClientModule","AjvClass","Ajv","ajv","op"]}