{"version":3,"sources":["../../src/errors.ts","../../src/utils/clone.ts","../../src/storage/memory.ts"],"names":["list"],"mappings":"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","file":"memory.cjs","sourcesContent":["import type { SerializedError } from './types.js';\n\n/** Mark an error as permanently fatal — the executor must not retry it. */\nexport class PermanentError extends Error {\n  readonly permanent = true as const;\n  readonly code?: string;\n\n  constructor(message: string, options?: { cause?: unknown; code?: string }) {\n    super(message);\n    this.name = 'PermanentError';\n    if (options?.cause !== undefined) (this as { cause?: unknown }).cause = options.cause;\n    if (options?.code) this.code = options.code;\n  }\n}\n\n/** Mark an error as transient — explicitly eligible for retry. */\nexport class TransientError extends Error {\n  readonly transient = true as const;\n  readonly code?: string;\n\n  constructor(message: string, options?: { cause?: unknown; code?: string }) {\n    super(message);\n    this.name = 'TransientError';\n    if (options?.cause !== undefined) (this as { cause?: unknown }).cause = options.cause;\n    if (options?.code) this.code = options.code;\n  }\n}\n\n/** Thrown when a step exceeds its configured timeout. Retryable by default. */\nexport class StepTimeoutError extends Error {\n  readonly timeout = true as const;\n\n  constructor(\n    public readonly stepName: string,\n    public readonly timeoutMs: number,\n  ) {\n    super(`step \"${stepName}\" timed out after ${timeoutMs}ms`);\n    this.name = 'StepTimeoutError';\n  }\n}\n\n/** Thrown when execution is cancelled via AbortSignal. */\nexport class FlowAbortedError extends Error {\n  readonly aborted = true as const;\n\n  constructor(reason?: unknown) {\n    const msg =\n      reason instanceof Error\n        ? reason.message\n        : typeof reason === 'string'\n          ? reason\n          : 'flow aborted';\n    super(msg);\n    this.name = 'FlowAbortedError';\n    if (reason !== undefined) (this as { cause?: unknown }).cause = reason;\n  }\n}\n\n/**\n * Thrown when the storage adapter cannot acquire a lock within the configured\n * wait timeout — typically because another worker is currently executing the\n * same idempotency key.\n */\nexport class LockAcquisitionError extends Error {\n  constructor(\n    public readonly flowName: string,\n    public readonly flowId: string,\n    reason?: string,\n  ) {\n    super(\n      reason\n        ? `failed to acquire lock for ${flowName}/${flowId}: ${reason}`\n        : `failed to acquire lock for ${flowName}/${flowId}`,\n    );\n    this.name = 'LockAcquisitionError';\n  }\n}\n\n/** Thrown by the executor when a step fails and compensation runs. */\nexport class FlowError extends Error {\n  constructor(\n    message: string,\n    public readonly flowId: string,\n    public readonly flowName: string,\n    public readonly failedStep: string,\n    public readonly originalError: unknown,\n    public readonly compensationErrors: Array<{ step: string; error: unknown }> = [],\n  ) {\n    super(message);\n    this.name = 'FlowError';\n    (this as { cause?: unknown }).cause = originalError;\n  }\n}\n\n/** Heuristic: errors are retryable unless explicitly marked permanent. */\nexport function isPermanent(err: unknown): boolean {\n  return (\n    err instanceof PermanentError ||\n    (typeof err === 'object' && err !== null && (err as { permanent?: boolean }).permanent === true)\n  );\n}\n\nexport function isTransient(err: unknown): boolean {\n  return (\n    err instanceof TransientError ||\n    err instanceof StepTimeoutError ||\n    (typeof err === 'object' && err !== null && (err as { transient?: boolean }).transient === true)\n  );\n}\n\nexport function serializeError(err: unknown): SerializedError {\n  if (err instanceof Error) {\n    const out: SerializedError = { name: err.name, message: err.message };\n    if (err.stack) out.stack = err.stack;\n    const withCode = err as { code?: unknown };\n    if (typeof withCode.code === 'string') out.code = withCode.code;\n    if (isTransient(err)) out.transient = true;\n    return out;\n  }\n  return { name: 'UnknownError', message: String(err) };\n}\n","/**\n * Deep-clone a value for snapshot isolation. Prefers structuredClone (Node 17+,\n * modern browsers, Hermes 0.72+) and falls back to JSON for older runtimes.\n * Flow state is already constrained to serializable shapes.\n */\nexport function deepClone<T>(value: T): T {\n  if (value === undefined || value === null) return value;\n  const sc = (globalThis as { structuredClone?: <V>(v: V) => V }).structuredClone;\n  if (typeof sc === 'function') {\n    return sc(value);\n  }\n  return JSON.parse(JSON.stringify(value)) as T;\n}\n","import type { AcquireLockOptions, FlowState, Lock, StorageAdapter } from '../types.js';\nimport { LockAcquisitionError } from '../errors.js';\nimport { deepClone } from '../utils/clone.js';\n\ntype Waiter = {\n  resolve: () => void;\n  reject: (err: Error) => void;\n  timer: ReturnType<typeof setTimeout>;\n};\n\ntype LockEntry = {\n  released: boolean;\n  ttlTimer: ReturnType<typeof setTimeout>;\n};\n\n/**\n * In-memory storage adapter. Safe default for tests, single-process services,\n * and browser/mobile usage where durability isn't required.\n *\n * Implements in-process locking — sufficient for single-process safety.\n * For multi-worker deployments use a durable adapter (Postgres/Redis) whose\n * locks survive across processes.\n *\n * State is cloned on both read and write so callers can't accidentally mutate\n * stored snapshots.\n */\nexport class MemoryStorage implements StorageAdapter {\n  private readonly store = new Map<string, FlowState>();\n  private readonly locks = new Map<string, LockEntry>();\n  private readonly waiters = new Map<string, Waiter[]>();\n\n  private key(flowName: string, flowId: string): string {\n    return `${flowName}:${flowId}`;\n  }\n\n  async load(flowName: string, flowId: string): Promise<FlowState | null> {\n    const entry = this.store.get(this.key(flowName, flowId));\n    return entry ? deepClone(entry) : null;\n  }\n\n  async save(state: FlowState): Promise<void> {\n    this.store.set(this.key(state.flowName, state.flowId), deepClone(state));\n  }\n\n  async delete(flowName: string, flowId: string): Promise<void> {\n    this.store.delete(this.key(flowName, flowId));\n  }\n\n  async acquireLock(\n    flowName: string,\n    flowId: string,\n    options: AcquireLockOptions,\n  ): Promise<Lock> {\n    const key = this.key(flowName, flowId);\n    const { ttlMs, timeoutMs } = options;\n\n    // Fast path: lock free.\n    if (!this.locks.has(key)) {\n      return this.claim(key, ttlMs);\n    }\n\n    // Fail fast if the caller declined to wait.\n    if (timeoutMs <= 0) {\n      throw new LockAcquisitionError(flowName, flowId, 'lock is held');\n    }\n\n    // Wait for the current holder (or TTL) to release, then claim.\n    await new Promise<void>((resolve, reject) => {\n      const timer = setTimeout(() => {\n        const list = this.waiters.get(key);\n        if (list) {\n          const idx = list.findIndex((w) => w.timer === timer);\n          if (idx >= 0) list.splice(idx, 1);\n          if (list.length === 0) this.waiters.delete(key);\n        }\n        reject(new LockAcquisitionError(flowName, flowId, `wait timeout after ${timeoutMs}ms`));\n      }, timeoutMs);\n\n      const list = this.waiters.get(key) ?? [];\n      list.push({ resolve, reject, timer });\n      this.waiters.set(key, list);\n    });\n\n    // At this point the prior holder has released and we've been selected —\n    // claim synchronously before any other microtask can interleave.\n    return this.claim(key, ttlMs);\n  }\n\n  private claim(key: string, ttlMs: number): Lock {\n    const entry: LockEntry = {\n      released: false,\n      // placeholder; assigned just below so closure can reference `entry`.\n      ttlTimer: null as unknown as ReturnType<typeof setTimeout>,\n    };\n\n    const releaseImpl = (): void => {\n      if (entry.released) return;\n      entry.released = true;\n      clearTimeout(entry.ttlTimer);\n      if (this.locks.get(key) === entry) {\n        this.locks.delete(key);\n      }\n      // Wake the next FIFO waiter, if any.\n      const list = this.waiters.get(key);\n      if (list && list.length > 0) {\n        const next = list.shift()!;\n        if (list.length === 0) this.waiters.delete(key);\n        clearTimeout(next.timer);\n        next.resolve();\n      }\n    };\n\n    entry.ttlTimer = setTimeout(releaseImpl, ttlMs);\n    this.locks.set(key, entry);\n\n    return {\n      async release() {\n        releaseImpl();\n      },\n      async refresh() {\n        if (entry.released) return;\n        clearTimeout(entry.ttlTimer);\n        entry.ttlTimer = setTimeout(releaseImpl, ttlMs);\n      },\n    };\n  }\n\n  /** Return every persisted state (useful for introspection/tests). */\n  snapshot(): FlowState[] {\n    return Array.from(this.store.values(), (s) => deepClone(s));\n  }\n\n  clear(): void {\n    // Cancel all pending waiters and timers so tests don't leak handles.\n    for (const [, entry] of this.locks) clearTimeout(entry.ttlTimer);\n    for (const [, list] of this.waiters) {\n      for (const w of list) {\n        clearTimeout(w.timer);\n        w.reject(new Error('storage cleared'));\n      }\n    }\n    this.store.clear();\n    this.locks.clear();\n    this.waiters.clear();\n  }\n\n  get size(): number {\n    return this.store.size;\n  }\n}\n\nexport function createMemoryStorage(): MemoryStorage {\n  return new MemoryStorage();\n}\n"]}