{"version":3,"sources":["../src/queueJobStore.ts","../src/localJobStore.ts"],"sourcesContent":["/**\n * Queue job store for worker queues (MongoDB or Upstash Redis).\n *\n * Mirrors the worker_jobs pattern but optimized for queues:\n * - MongoDB: collection `queue_jobs` (configurable via MONGODB_QUEUE_JOBS_COLLECTION)\n * - Upstash Redis: JSON blob per queue job with compact step entries\n *\n * This module is runtime-only (used by Lambda workers). Next.js APIs can read\n * the same collections/keys to show queue progress.\n */\n\nimport type { Redis } from '@upstash/redis';\nimport { Redis as UpstashRedis } from '@upstash/redis';\nimport { MongoClient, type Collection } from 'mongodb';\nimport {\n  upsertInitialLocalQueueJob,\n  updateLocalQueueJobStep,\n  appendLocalQueueJobStep,\n  getLocalQueueJob,\n} from './localJobStore';\n\ntype QueueJobStep = {\n  workerId: string;\n  workerJobId: string;\n  status: 'queued' | 'running' | 'awaiting_approval' | 'completed' | 'failed';\n  input?: unknown;\n  output?: unknown;\n  error?: { message: string };\n  startedAt?: string;\n  completedAt?: string;\n};\n\ntype QueueJobDoc = {\n  _id: string; // queueJobId\n  id: string;\n  queueId: string;\n  status: 'running' | 'completed' | 'failed' | 'partial';\n  steps: QueueJobStep[];\n  metadata?: Record<string, unknown>;\n  userId?: string;\n  createdAt: string;\n  updatedAt: string;\n  completedAt?: string;\n};\n\n\n// === Mongo backend (shares connection pattern with mongoJobStore) ===\n\nconst mongoUri = process.env.DATABASE_MONGODB_URI || process.env.MONGODB_URI;\nconst mongoDbName =\n  process.env.DATABASE_MONGODB_DB ||\n  process.env.MONGODB_DB ||\n  'mediamake';\nconst mongoQueueCollectionName =\n  process.env.MONGODB_QUEUE_JOBS_COLLECTION || 'queue_jobs';\n\nlet mongoClientPromise: Promise<MongoClient> | null = null;\n\nasync function getMongoClient(): Promise<MongoClient> {\n  if (!mongoUri) {\n    throw new Error(\n      'MongoDB URI required for queue job store. Set DATABASE_MONGODB_URI or MONGODB_URI.'\n    );\n  }\n  if (!mongoClientPromise) {\n    mongoClientPromise = new MongoClient(mongoUri, {\n      maxPoolSize: 10,\n      minPoolSize: 0,\n      serverSelectionTimeoutMS: 10_000,\n    }).connect();\n  }\n  return mongoClientPromise;\n}\n\nasync function getMongoQueueCollection(): Promise<Collection<QueueJobDoc>> {\n  const client = await getMongoClient();\n  return client.db(mongoDbName).collection<QueueJobDoc>(mongoQueueCollectionName);\n}\n\n// === Redis backend (Upstash) ===\n\nconst redisUrl =\n  process.env.WORKER_UPSTASH_REDIS_REST_URL ||\n  process.env.UPSTASH_REDIS_REST_URL ||\n  process.env.UPSTASH_REDIS_URL;\nconst redisToken =\n  process.env.WORKER_UPSTASH_REDIS_REST_TOKEN ||\n  process.env.UPSTASH_REDIS_REST_TOKEN ||\n  process.env.UPSTASH_REDIS_TOKEN;\nconst queueKeyPrefix =\n  process.env.WORKER_UPSTASH_REDIS_QUEUE_PREFIX ||\n  process.env.UPSTASH_REDIS_QUEUE_PREFIX ||\n  'worker:queue-jobs:';\n\nconst defaultTtlSeconds = 60 * 60 * 24 * 7; // 7 days\nconst queueJobTtlSeconds =\n  typeof process.env.WORKER_QUEUE_JOBS_TTL_SECONDS === 'string'\n    ? parseInt(process.env.WORKER_QUEUE_JOBS_TTL_SECONDS, 10) || defaultTtlSeconds\n    : typeof process.env.WORKER_JOBS_TTL_SECONDS === 'string'\n      ? parseInt(process.env.WORKER_JOBS_TTL_SECONDS, 10) || defaultTtlSeconds\n      : defaultTtlSeconds;\n\nlet redisClient: Redis | null = null;\n\nfunction getRedis(): Redis {\n  if (!redisUrl || !redisToken) {\n    throw new Error(\n      'Upstash Redis configuration missing for queue job store. Set WORKER_UPSTASH_REDIS_REST_URL and WORKER_UPSTASH_REDIS_REST_TOKEN (or UPSTASH_REDIS_REST_URL/UPSTASH_REDIS_REST_TOKEN).'\n    );\n  }\n  if (!redisClient) {\n    redisClient = new UpstashRedis({\n      url: redisUrl,\n      token: redisToken,\n    });\n  }\n  return redisClient;\n}\n\nfunction queueKey(id: string): string {\n  return `${queueKeyPrefix}${id}`;\n}\n\ntype QueueJobRecord = Omit<QueueJobDoc, '_id'> & { userId?: string };\n\n/** Hash values from Upstash hgetall may be auto-parsed (array/object) or raw strings. */\nfunction stepsFromHash(val: unknown): QueueJobStep[] {\n  if (Array.isArray(val)) return val as QueueJobStep[];\n  if (typeof val === 'string') {\n    try {\n      const parsed = JSON.parse(val) as QueueJobStep[];\n      return Array.isArray(parsed) ? parsed : [];\n    } catch {\n      return [];\n    }\n  }\n  return [];\n}\n\nfunction metadataFromHash(val: unknown): Record<string, unknown> {\n  if (val && typeof val === 'object' && !Array.isArray(val)) return val as Record<string, unknown>;\n  if (typeof val === 'string') {\n    try {\n      const parsed = JSON.parse(val) as Record<string, unknown>;\n      return parsed && typeof parsed === 'object' ? parsed : {};\n    } catch {\n      return {};\n    }\n  }\n  return {};\n}\n\nasync function loadQueueJobRedis(queueJobId: string): Promise<QueueJobRecord | null> {\n  const redis = getRedis();\n  const key = queueKey(queueJobId);\n  const data = await redis.hgetall(key);\n  if (!data || typeof data !== 'object' || Object.keys(data).length === 0) return null;\n  const d = data as Record<string, unknown>;\n  const record: QueueJobRecord = {\n    id: (d.id === undefined ? queueJobId : String(d.id)) as string,\n    queueId: String(d.queueId ?? ''),\n    status: (String(d.status ?? 'running') as QueueJobRecord['status']),\n    steps: stepsFromHash(d.steps),\n    metadata: metadataFromHash(d.metadata),\n    ...(d.userId ? { userId: String(d.userId) } : {}),\n    createdAt: String(d.createdAt ?? new Date().toISOString()),\n    updatedAt: String(d.updatedAt ?? new Date().toISOString()),\n    completedAt: d.completedAt != null ? String(d.completedAt) : undefined,\n  };\n  return record;\n}\n\nasync function saveQueueJobRedis(record: QueueJobRecord): Promise<void> {\n  const redis = getRedis();\n  const key = queueKey(record.id);\n  const now = new Date().toISOString();\n  const toSet: Record<string, string> = {\n    id: record.id,\n    queueId: record.queueId,\n    status: record.status,\n    steps: JSON.stringify(record.steps || []),\n    metadata: JSON.stringify(record.metadata || {}),\n    createdAt: record.createdAt || now,\n    updatedAt: record.updatedAt || now,\n  };\n  if (record.completedAt) toSet.completedAt = record.completedAt;\n  if (record.userId) toSet.userId = record.userId;\n  await redis.hset(key, toSet);\n  if (queueJobTtlSeconds > 0) {\n    await redis.expire(key, queueJobTtlSeconds);\n  }\n}\n\n// === Backend selection ===\n\nfunction getStoreType(): 'mongodb' | 'upstash-redis' | 'local' {\n  const t = (process.env.WORKER_DATABASE_TYPE || 'upstash-redis').toLowerCase();\n  if (t === 'mongodb') return 'mongodb';\n  if (t === 'local') return 'local';\n  return 'upstash-redis';\n}\n\n/** Local in-memory store — only when WORKER_DATABASE_TYPE=local is set explicitly (dev server). */\nfunction preferLocal(): boolean {\n  return getStoreType() === 'local';\n}\n\nfunction preferMongo(): boolean {\n  return getStoreType() === 'mongodb' && Boolean(mongoUri?.trim());\n}\n\nfunction preferRedis(): boolean {\n  return getStoreType() === 'upstash-redis' && Boolean((redisUrl || '').trim() && (redisToken || '').trim());\n}\n\n// === Public API used from handler.ts ===\n\nexport async function upsertInitialQueueJob(options: {\n  queueJobId: string;\n  queueId: string;\n  firstWorkerId: string;\n  firstWorkerJobId: string;\n  metadata?: Record<string, any>;\n  userId?: string;\n}): Promise<void> {\n  const { queueJobId, queueId, firstWorkerId, firstWorkerJobId, metadata, userId } = options;\n  const now = new Date().toISOString();\n\n  if (preferLocal()) {\n    await upsertInitialLocalQueueJob(options);\n    return;\n  }\n\n  if (preferMongo()) {\n    const coll = await getMongoQueueCollection();\n    const existing = await coll.findOne({ _id: queueJobId });\n    if (existing) {\n      const steps = existing.steps ?? [];\n      if (steps.length === 0) {\n        steps.push({\n          workerId: firstWorkerId,\n          workerJobId: firstWorkerJobId,\n          status: 'queued',\n        });\n      }\n      await coll.updateOne(\n        { _id: queueJobId },\n        {\n          $set: {\n            steps,\n            updatedAt: now,\n          },\n        }\n      );\n    } else {\n      const doc: QueueJobDoc = {\n        _id: queueJobId,\n        id: queueJobId,\n        queueId,\n        status: 'running',\n        steps: [\n          {\n            workerId: firstWorkerId,\n            workerJobId: firstWorkerJobId,\n            status: 'queued',\n          },\n        ],\n        metadata: metadata ?? {},\n        ...(userId ? { userId } : {}),\n        createdAt: now,\n        updatedAt: now,\n      };\n      await coll.updateOne(\n        { _id: queueJobId },\n        { $set: doc },\n        { upsert: true }\n      );\n    }\n    return;\n  }\n\n  if (preferRedis()) {\n    const existing = await loadQueueJobRedis(queueJobId);\n    if (existing) {\n      // Ensure we have at least one step\n      if (!existing.steps || existing.steps.length === 0) {\n        existing.steps = [\n          {\n            workerId: firstWorkerId,\n            workerJobId: firstWorkerJobId,\n            status: 'queued',\n          },\n        ];\n      }\n      existing.updatedAt = now;\n      await saveQueueJobRedis(existing);\n    } else {\n      const record: QueueJobRecord = {\n        id: queueJobId,\n        queueId,\n        status: 'running',\n        steps: [\n          {\n            workerId: firstWorkerId,\n            workerJobId: firstWorkerJobId,\n            status: 'queued',\n          },\n        ],\n        metadata: metadata ?? {},\n        ...(userId ? { userId } : {}),\n        createdAt: now,\n        updatedAt: now,\n      };\n      await saveQueueJobRedis(record);\n    }\n  }\n}\n\nexport async function updateQueueJobStepInStore(options: {\n  queueJobId: string;\n  queueId?: string;\n  stepIndex: number;\n  workerId: string;\n  workerJobId: string;\n  status: 'running' | 'awaiting_approval' | 'completed' | 'failed';\n  input?: unknown;\n  output?: unknown;\n  error?: { message: string };\n}): Promise<void> {\n  const { queueJobId, stepIndex, status, input, output, error } = options;\n  const now = new Date().toISOString();\n\n  if (preferLocal()) {\n    await updateLocalQueueJobStep(options);\n    return;\n  }\n\n  if (preferMongo()) {\n    const coll = await getMongoQueueCollection();\n    const existing = await coll.findOne({ _id: queueJobId });\n    if (!existing) return;\n    const step = existing.steps[stepIndex];\n    if (!step) return;\n\n    const mergedStep: QueueJobStep = {\n      ...step,\n      status,\n      ...(input !== undefined && { input }),\n      ...(output !== undefined && { output }),\n      ...(error !== undefined && { error }),\n      startedAt: step.startedAt ?? (status === 'running' ? now : step.startedAt),\n      completedAt:\n        step.completedAt ??\n        (status === 'completed' || status === 'failed' ? now : step.completedAt),\n    };\n\n    const setDoc: Partial<QueueJobDoc> & { steps: QueueJobStep[] } = {\n      steps: existing.steps,\n      updatedAt: now,\n    };\n    setDoc.steps[stepIndex] = mergedStep;\n    if (status === 'failed') {\n      setDoc.status = 'failed';\n      if (!existing.completedAt) setDoc.completedAt = now;\n    } else if (status === 'completed' && stepIndex === existing.steps.length - 1) {\n      setDoc.status = 'completed';\n      if (!existing.completedAt) setDoc.completedAt = now;\n    }\n\n    await coll.updateOne(\n      { _id: queueJobId },\n      {\n        $set: setDoc,\n      }\n    );\n    return;\n  }\n\n  if (preferRedis()) {\n    const existing = await loadQueueJobRedis(queueJobId);\n    if (!existing) {\n      // No queue job; nothing to update\n      return;\n    }\n    const steps = existing.steps || [];\n    const step = steps[stepIndex];\n    if (!step) {\n      return;\n    }\n    step.status = status;\n    if (input !== undefined) step.input = input;\n    if (output !== undefined) step.output = output;\n    if (error !== undefined) step.error = error;\n    if (status === 'running') {\n      step.startedAt = step.startedAt ?? now;\n    }\n    if (status === 'completed' || status === 'failed') {\n      step.completedAt = step.completedAt ?? now;\n    }\n\n    existing.steps = steps;\n    existing.updatedAt = now;\n    if (status === 'failed') {\n      existing.status = 'failed';\n      existing.completedAt = existing.completedAt ?? now;\n    } else if (status === 'completed' && stepIndex === steps.length - 1) {\n      existing.status = 'completed';\n      existing.completedAt = existing.completedAt ?? now;\n    }\n    await saveQueueJobRedis(existing);\n  }\n}\n\nexport async function appendQueueJobStepInStore(options: {\n  queueJobId: string;\n  queueId?: string;\n  workerId: string;\n  workerJobId: string;\n}): Promise<void> {\n  const { queueJobId, workerId, workerJobId } = options;\n  const now = new Date().toISOString();\n\n  if (preferLocal()) {\n    await appendLocalQueueJobStep({ queueJobId, workerId, workerJobId });\n    return;\n  }\n\n  if (preferMongo()) {\n    const coll = await getMongoQueueCollection();\n    await coll.updateOne(\n      { _id: queueJobId },\n      {\n        $push: {\n          steps: {\n            workerId,\n            workerJobId,\n            status: 'queued',\n          } as QueueJobStep,\n        },\n        $set: { updatedAt: now },\n      }\n    );\n    return;\n  }\n\n  if (preferRedis()) {\n    const existing = await loadQueueJobRedis(queueJobId);\n    if (!existing) return;\n    const steps = existing.steps || [];\n    steps.push({\n      workerId,\n      workerJobId,\n      status: 'queued',\n    });\n    existing.steps = steps;\n    existing.updatedAt = now;\n    await saveQueueJobRedis(existing);\n  }\n}\n\n/**\n * Load a queue job by ID (for mapping context: previous step outputs).\n * Used by wrapHandlerForQueue for chain mapping and HITL resume (`previousOutputs`).\n */\nexport async function getQueueJob(queueJobId: string): Promise<{\n  id: string;\n  queueId: string;\n  status: string;\n  steps: Array<{ workerId: string; workerJobId: string; status: string; output?: unknown }>;\n} | null> {\n  if (preferLocal()) {\n    const record = await getLocalQueueJob(queueJobId);\n    if (!record) return null;\n    return {\n      id: record.id,\n      queueId: record.queueId,\n      status: record.status,\n      steps: (record.steps ?? []).map((s) => ({\n        workerId: s.workerId,\n        workerJobId: s.workerJobId,\n        status: s.status,\n        output: s.output,\n      })),\n    };\n  }\n  if (preferMongo()) {\n    const coll = await getMongoQueueCollection();\n    const doc = await coll.findOne({ _id: queueJobId });\n    if (!doc) return null;\n    return {\n      id: doc.id ?? queueJobId,\n      queueId: doc.queueId,\n      status: doc.status,\n      steps: (doc.steps ?? []).map((s: QueueJobStep) => ({\n        workerId: s.workerId,\n        workerJobId: s.workerJobId,\n        status: s.status,\n        output: s.output,\n      })),\n    };\n  }\n  if (preferRedis()) {\n    const record = await loadQueueJobRedis(queueJobId);\n    if (!record) return null;\n    return {\n      id: record.id,\n      queueId: record.queueId,\n      status: record.status,\n      steps: (record.steps ?? []).map((s) => ({\n        workerId: s.workerId,\n        workerJobId: s.workerJobId,\n        status: s.status,\n        output: s.output,\n      })),\n    };\n  }\n  return null;\n}\n\n","/**\n * Local job store (`WORKER_DATABASE_TYPE=local`) — in-memory Maps with debounced\n * JSON persistence, standing in for Upstash/Mongo when running `ai-worker dev`.\n *\n * Never a fallback: this store is only used when WORKER_DATABASE_TYPE is\n * explicitly 'local' (the dev server sets it; compile never writes it into a\n * deployed env.json unless the user set it themselves).\n *\n * State lives on `globalThis`, not module scope: tsup bundles each package\n * entry (index / handler / queueJobStore) separately, so module-level Maps\n * would be duplicated per bundle and the dev server would read different\n * state than the runtime writes. The global anchor makes every copy share\n * one store (same trick as the local dispatch bridge).\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport type { JobStore, JobStoreUpdate, JobRecord } from './handler.js';\n\n/** Mirrors the queue job doc shape used by the redis/mongo queue stores. */\nexport interface LocalQueueJobStep {\n  workerId: string;\n  workerJobId: string;\n  status: 'queued' | 'running' | 'awaiting_approval' | 'completed' | 'failed';\n  input?: unknown;\n  output?: unknown;\n  error?: { message: string };\n  startedAt?: string;\n  completedAt?: string;\n}\n\nexport interface LocalQueueJobRecord {\n  id: string;\n  queueId: string;\n  status: 'running' | 'completed' | 'failed' | 'partial';\n  steps: LocalQueueJobStep[];\n  metadata?: Record<string, unknown>;\n  userId?: string;\n  createdAt: string;\n  updatedAt: string;\n  completedAt?: string;\n}\n\ninterface LocalStoreState {\n  jobs: Map<string, JobRecord>;\n  queueJobs: Map<string, LocalQueueJobRecord>;\n  loadedFrom: string | null;\n  persistTimer: ReturnType<typeof setTimeout> | null;\n}\n\nconst STATE_GLOBAL_KEY = '__AI_WORKER_LOCAL_STORE_STATE__';\nconst PERSIST_DEBOUNCE_MS = 250;\n\nexport function isLocalJobStoreEnabled(): boolean {\n  return (process.env.WORKER_DATABASE_TYPE || '').toLowerCase() === 'local';\n}\n\nfunction getStatePath(): string {\n  return (\n    process.env.AI_WORKER_LOCAL_STATE_PATH ||\n    path.join(process.cwd(), '.microfox', 'dev-state.json')\n  );\n}\n\nfunction getState(): LocalStoreState {\n  const g = globalThis as Record<string, unknown>;\n  let state = g[STATE_GLOBAL_KEY] as LocalStoreState | undefined;\n  if (!state) {\n    state = { jobs: new Map(), queueJobs: new Map(), loadedFrom: null, persistTimer: null };\n    g[STATE_GLOBAL_KEY] = state;\n  }\n  // (Re)load from disk on first touch, or if the target path changed.\n  const statePath = getStatePath();\n  if (state.loadedFrom !== statePath) {\n    state.loadedFrom = statePath;\n    try {\n      if (fs.existsSync(statePath)) {\n        const raw = JSON.parse(fs.readFileSync(statePath, 'utf-8')) as {\n          jobs?: Record<string, JobRecord>;\n          queueJobs?: Record<string, LocalQueueJobRecord>;\n        };\n        state.jobs = new Map(Object.entries(raw.jobs ?? {}));\n        state.queueJobs = new Map(Object.entries(raw.queueJobs ?? {}));\n      }\n    } catch (e: any) {\n      console.warn('[localJobStore] Could not read persisted dev state (starting empty):', {\n        statePath,\n        error: e?.message ?? String(e),\n      });\n    }\n  }\n  return state;\n}\n\nfunction schedulePersist(): void {\n  const state = getState();\n  if (state.persistTimer) return;\n  state.persistTimer = setTimeout(() => {\n    state.persistTimer = null;\n    persistNow(state);\n  }, PERSIST_DEBOUNCE_MS);\n  // Never keep the process alive just to persist; flush handles shutdown.\n  if (typeof state.persistTimer.unref === 'function') state.persistTimer.unref();\n}\n\nfunction persistNow(state: LocalStoreState): void {\n  const statePath = getStatePath();\n  try {\n    fs.mkdirSync(path.dirname(statePath), { recursive: true });\n    const payload = {\n      jobs: Object.fromEntries(state.jobs),\n      queueJobs: Object.fromEntries(state.queueJobs),\n      savedAt: new Date().toISOString(),\n    };\n    fs.writeFileSync(statePath, JSON.stringify(payload, null, 2), 'utf-8');\n  } catch (e: any) {\n    console.warn('[localJobStore] Failed to persist dev state:', {\n      statePath,\n      error: e?.message ?? String(e),\n    });\n  }\n}\n\n/** Synchronously write pending state to disk (dev server calls this on shutdown). */\nexport function flushLocalJobStore(): void {\n  const g = globalThis as Record<string, unknown>;\n  const state = g[STATE_GLOBAL_KEY] as LocalStoreState | undefined;\n  if (!state) return;\n  if (state.persistTimer) {\n    clearTimeout(state.persistTimer);\n    state.persistTimer = null;\n  }\n  persistNow(state);\n}\n\n// === Worker job records (mirrors redisJobStore semantics) ===\n\nexport async function loadLocalJob(jobId: string): Promise<JobRecord | null> {\n  const record = getState().jobs.get(jobId);\n  return record ? structuredClone(record) : null;\n}\n\nexport async function upsertLocalJob(\n  jobId: string,\n  workerId: string,\n  input: any,\n  metadata: Record<string, any>,\n  userId?: string\n): Promise<void> {\n  const state = getState();\n  const now = new Date().toISOString();\n  const existing = state.jobs.get(jobId);\n  state.jobs.set(jobId, {\n    jobId,\n    workerId,\n    status: existing?.status ?? 'queued',\n    input: input ?? {},\n    metadata: metadata ?? {},\n    ...(existing?.output !== undefined ? { output: existing.output } : {}),\n    ...(existing?.error !== undefined ? { error: existing.error } : {}),\n    ...(existing?.internalJobs ? { internalJobs: existing.internalJobs } : {}),\n    ...(userId ? { userId } : existing?.userId ? { userId: existing.userId } : {}),\n    createdAt: existing?.createdAt ?? now,\n    updatedAt: now,\n    ...(existing?.completedAt ? { completedAt: existing.completedAt } : {}),\n  });\n  schedulePersist();\n}\n\nexport function createLocalJobStore(\n  workerId: string,\n  jobId: string,\n  input: any,\n  metadata: Record<string, any>,\n  userId?: string\n): JobStore {\n  void workerId;\n  void input;\n  void metadata;\n  void userId;\n  return {\n    update: async (update: JobStoreUpdate): Promise<void> => {\n      const state = getState();\n      const existing = state.jobs.get(jobId);\n      if (!existing) return;\n      const now = new Date().toISOString();\n\n      const mergedMeta: Record<string, any> = { ...(existing.metadata ?? {}) };\n      if (update.metadata) Object.assign(mergedMeta, update.metadata);\n      if (update.progress !== undefined || update.progressMessage !== undefined) {\n        mergedMeta.progress = update.progress;\n        mergedMeta.progressMessage = update.progressMessage;\n      }\n      existing.metadata = mergedMeta;\n\n      if (update.status !== undefined) {\n        existing.status = update.error ? 'failed' : update.status;\n        if (\n          (update.status === 'completed' || update.status === 'failed') &&\n          !existing.completedAt\n        ) {\n          existing.completedAt = now;\n        }\n      }\n      if (update.output !== undefined) existing.output = update.output;\n      if (update.error !== undefined) existing.error = update.error;\n      existing.updatedAt = now;\n      schedulePersist();\n    },\n    get: async () => loadLocalJob(jobId),\n    appendInternalJob: async (entry) => {\n      const state = getState();\n      const existing = state.jobs.get(jobId);\n      if (!existing) return;\n      existing.internalJobs = [...(existing.internalJobs ?? []), entry];\n      existing.updatedAt = new Date().toISOString();\n      schedulePersist();\n    },\n    getJob: async (otherJobId: string) => loadLocalJob(otherJobId),\n  };\n}\n\n/** All job records (dev server observability route). */\nexport function listLocalJobs(): JobRecord[] {\n  return Array.from(getState().jobs.values()).map((r) => structuredClone(r));\n}\n\n/** Jobs for one worker, newest first (dev server /dev-store API). */\nexport function listLocalJobsByWorker(workerId: string): JobRecord[] {\n  return listLocalJobs()\n    .filter((r) => r.workerId === workerId)\n    .sort((a, b) => (a.createdAt < b.createdAt ? 1 : -1));\n}\n\n/** Drop keys whose value is undefined so a partial merge never erases fields. */\nfunction definedEntries<T extends Record<string, unknown>>(obj: T): Partial<T> {\n  const out: Record<string, unknown> = {};\n  for (const [key, value] of Object.entries(obj)) {\n    if (value !== undefined) out[key] = value;\n  }\n  return out as Partial<T>;\n}\n\n/**\n * Shallow-merge a partial job record (upsert). Serves the dev server's\n * /dev-store API, which the app boilerplate's `local` adapter writes through\n * (setJob/updateJob) so console/webhook updates land in the same store the\n * workers use.\n */\nexport async function patchLocalJob(\n  jobId: string,\n  partial: Partial<JobRecord>\n): Promise<JobRecord> {\n  const state = getState();\n  const now = new Date().toISOString();\n  const existing = state.jobs.get(jobId);\n  const merged: JobRecord = {\n    status: 'queued',\n    input: {},\n    ...(existing ?? {}),\n    ...definedEntries(partial as Record<string, unknown>),\n    jobId,\n    workerId: partial.workerId ?? existing?.workerId ?? '',\n    createdAt: existing?.createdAt ?? partial.createdAt ?? now,\n    updatedAt: now,\n  } as JobRecord;\n  if (\n    (merged.status === 'completed' || merged.status === 'failed') &&\n    !merged.completedAt\n  ) {\n    merged.completedAt = now;\n  }\n  state.jobs.set(jobId, merged);\n  schedulePersist();\n  return structuredClone(merged);\n}\n\n/** Standalone appendInternalJob (dev server /dev-store API). */\nexport async function appendLocalInternalJob(\n  parentJobId: string,\n  entry: { jobId: string; workerId: string; awaited?: boolean; delaySeconds?: number }\n): Promise<void> {\n  const state = getState();\n  const existing = state.jobs.get(parentJobId);\n  if (!existing) return;\n  existing.internalJobs = [...(existing.internalJobs ?? []), entry];\n  existing.updatedAt = new Date().toISOString();\n  schedulePersist();\n}\n\n/**\n * Shallow-merge a partial queue job record (upsert). `steps`, when provided,\n * replaces the whole array — step-level merging is done by the dev server\n * route so this store stays a dumb record holder.\n */\nexport async function patchLocalQueueJob(\n  queueJobId: string,\n  partial: Partial<LocalQueueJobRecord>\n): Promise<LocalQueueJobRecord> {\n  const state = getState();\n  const now = new Date().toISOString();\n  const existing = state.queueJobs.get(queueJobId);\n  const merged: LocalQueueJobRecord = {\n    queueId: '',\n    status: 'running',\n    steps: [],\n    ...(existing ?? {}),\n    ...definedEntries(partial as Record<string, unknown>),\n    id: queueJobId,\n    createdAt: existing?.createdAt ?? partial.createdAt ?? now,\n    updatedAt: now,\n  } as LocalQueueJobRecord;\n  state.queueJobs.set(queueJobId, merged);\n  schedulePersist();\n  return structuredClone(merged);\n}\n\n// === Queue job docs (mirrors queueJobStore redis backend semantics) ===\n\nexport async function upsertInitialLocalQueueJob(options: {\n  queueJobId: string;\n  queueId: string;\n  firstWorkerId: string;\n  firstWorkerJobId: string;\n  metadata?: Record<string, any>;\n  userId?: string;\n}): Promise<void> {\n  const { queueJobId, queueId, firstWorkerId, firstWorkerJobId, metadata, userId } = options;\n  const state = getState();\n  const now = new Date().toISOString();\n  const existing = state.queueJobs.get(queueJobId);\n  if (existing) {\n    if (!existing.steps || existing.steps.length === 0) {\n      existing.steps = [\n        { workerId: firstWorkerId, workerJobId: firstWorkerJobId, status: 'queued' },\n      ];\n    }\n    existing.updatedAt = now;\n  } else {\n    state.queueJobs.set(queueJobId, {\n      id: queueJobId,\n      queueId,\n      status: 'running',\n      steps: [{ workerId: firstWorkerId, workerJobId: firstWorkerJobId, status: 'queued' }],\n      metadata: metadata ?? {},\n      ...(userId ? { userId } : {}),\n      createdAt: now,\n      updatedAt: now,\n    });\n  }\n  schedulePersist();\n}\n\nexport async function updateLocalQueueJobStep(options: {\n  queueJobId: string;\n  stepIndex: number;\n  workerId: string;\n  workerJobId: string;\n  status: 'running' | 'awaiting_approval' | 'completed' | 'failed';\n  input?: unknown;\n  output?: unknown;\n  error?: { message: string };\n}): Promise<void> {\n  const { queueJobId, stepIndex, status, input, output, error } = options;\n  const state = getState();\n  const existing = state.queueJobs.get(queueJobId);\n  if (!existing) return;\n  const step = existing.steps?.[stepIndex];\n  if (!step) return;\n  const now = new Date().toISOString();\n\n  step.status = status;\n  if (input !== undefined) step.input = input;\n  if (output !== undefined) step.output = output;\n  if (error !== undefined) step.error = error;\n  if (status === 'running') step.startedAt = step.startedAt ?? now;\n  if (status === 'completed' || status === 'failed') {\n    step.completedAt = step.completedAt ?? now;\n  }\n\n  existing.updatedAt = now;\n  if (status === 'failed') {\n    existing.status = 'failed';\n    existing.completedAt = existing.completedAt ?? now;\n  } else if (status === 'completed' && stepIndex === existing.steps.length - 1) {\n    existing.status = 'completed';\n    existing.completedAt = existing.completedAt ?? now;\n  }\n  schedulePersist();\n}\n\nexport async function appendLocalQueueJobStep(options: {\n  queueJobId: string;\n  workerId: string;\n  workerJobId: string;\n}): Promise<void> {\n  const { queueJobId, workerId, workerJobId } = options;\n  const state = getState();\n  const existing = state.queueJobs.get(queueJobId);\n  if (!existing) return;\n  existing.steps = existing.steps ?? [];\n  existing.steps.push({ workerId, workerJobId, status: 'queued' });\n  existing.updatedAt = new Date().toISOString();\n  schedulePersist();\n}\n\nexport async function getLocalQueueJob(\n  queueJobId: string\n): Promise<LocalQueueJobRecord | null> {\n  const record = getState().queueJobs.get(queueJobId);\n  return record ? structuredClone(record) : null;\n}\n\n/** All queue job docs (dev server observability route). */\nexport function listLocalQueueJobs(): LocalQueueJobRecord[] {\n  return Array.from(getState().queueJobs.values()).map((r) => structuredClone(r));\n}\n"],"mappings":"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","names":[]}