import type { RedisClient } from '../session/session-store.js'; export interface MediaJobBinding { jobId: string; userId: string; projectKey: string; tenant: string; profile: string; folderId: string; createdAt: number; /** Whether concurrent-slot was already released after terminal status. */ concurrentReleased?: boolean; /** * Last successful pipeline status payload (JSON-serializable). Used when the * pipeline briefly 404s after we already observed real status. */ lastStatus?: unknown; lastStatusAt?: number; } export declare class MediaPipelineJobStore { private readonly redis; private readonly bindingTtlSeconds; constructor(redis: RedisClient, bindingTtlSeconds?: number); private jobKey; private rateKey; private concurrentKey; assertPrepareRateLimit(userId: string, maxPerHour: number): Promise; assertConcurrentSlot(userId: string, maxConcurrent: number): Promise; reserveConcurrentSlot(userId: string): Promise; releaseConcurrentSlot(userId: string): Promise; saveBinding(binding: MediaJobBinding): Promise; getBinding(jobId: string): Promise; assertOwned(jobId: string, userId: string): Promise; markConcurrentReleased(jobId: string, userId: string): Promise; /** Persist last good pipeline status on the ownership binding (overwrite OK). */ saveLastStatus(jobId: string, userId: string, status: unknown): Promise; } export declare class MediaJobStoreError extends Error { readonly code: string; readonly status: number; constructor(message: string, code: string, status: number); } /** In-memory RedisClient subset for unit tests and local CLI without Upstash. */ export declare function createMemoryRedis(): RedisClient & { store: Map; }; //# sourceMappingURL=job-store.d.ts.map