import type { StandardSchemaV1 } from '@standard-schema/spec'; import type { DbFor } from '../db.js'; import type { EmailFacade } from '../email.js'; import type { StorageFacade } from '../index.js'; import { type CatchUp } from './slots.js'; export declare const DEFAULT_RETRIES = 3; export declare const DEFAULT_TIMEOUT_MS = 60000; export type EnqueueOptions = { /** Collapse duplicate enqueues while the queue row is non-terminal. */ dedupeKey?: string; /** Milliseconds from now until the job becomes claimable. */ delay?: number; /** Absolute time the job becomes claimable; wins over `delay`. */ runAt?: Date | number; }; export type TickResult = { /** Rows moved from pending to running this tick. */ claimed: number; /** Handlers that completed successfully. */ ran: number; /** Handlers that threw, whether or not they will be retried. */ failed: number; }; /** * The untyped runtime facade. Job handlers and API context expose this shape; * `app.jobs` narrows `enqueue` to the declared job names/payloads. */ export type JobsRuntimeFacade = { enqueue(name: string, input?: unknown, opts?: EnqueueOptions): Promise<{ id: string; }>; /** Run one poll cycle deterministically (tests). `now` defaults to Date.now(). */ tick(now?: number): Promise; }; import type { RealtimeFacade } from '../realtime/facade.js'; export type JobContext = Record, TEnvResult = Record> = { db: DbFor; env: TEnvResult; email: EmailFacade; storage: StorageFacade; jobs: JobsRuntimeFacade; realtime: RealtimeFacade; }; export type BunderstackJobContext = Record, TEnvResult = Record> = JobContext; export type QueueJobDefinition = Record, TEnvResult = Record> = { kind: 'job'; /** Standard Schema payload; parsed at enqueue AND before the handler runs. */ input?: StandardSchemaV1; /** Attempts after the first failure. Default 3 (so 4 total attempts). */ retries?: number; /** Delay before retry N (1-based). Default exponential: 1s, 2s, 4s, … */ backoff?: ((attempt: number) => number) | { baseMs?: number; factor?: number; }; /** Max simultaneous `running` rows of this type, enforced per worker. */ concurrency?: number; /** Lease duration in ms; an expired lease sends the job back to pending. */ timeout?: number; handler: (input: TInput, ctx: JobContext) => Promise | void; /** Fires once, after the final attempt fails. Errors here are logged, never retried. */ onFailed?: (input: TInput, error: Error, ctx: JobContext) => Promise | void; }; export type CronInvocation = { scheduledFor: Date; }; export type CronDefinition = Record, TEnvResult = Record, TSchedule extends string = string> = { kind: 'cron'; schedule: TSchedule; /** Attempts after the first failure. Default 3 (so 4 total attempts). */ retries?: number; /** Delay before retry N (1-based). Default exponential: 1s, 2s, 4s, … */ backoff?: ((attempt: number) => number) | { baseMs?: number; factor?: number; }; /** Lease duration in ms; an expired lease sends the slot back to pending. */ timeout?: number; /** How missed slots are handled on wake. Default 'latest'. */ catchUp?: CatchUp; /** How far back catch-up looks, in ms. Default 1 hour. */ catchUpWindow?: number; handler: (invocation: CronInvocation, ctx: JobContext) => Promise | void; /** Fires once, after the final attempt fails. Errors here are logged, never retried. */ onFailed?: (invocation: CronInvocation, error: Error, ctx: JobContext) => Promise | void; }; export type BackgroundDefinition = QueueJobDefinition | CronDefinition; export type BackgroundDefs = Record; /** @deprecated Use QueueJobDefinition. */ export type JobDefinition = Record, TEnvResult = Record> = QueueJobDefinition; export type AnyJobDefinition = QueueJobDefinition; export type AnyBackgroundDefinition = QueueJobDefinition | CronDefinition; export type JobsDefs = BackgroundDefs; export type QueueJobKeys = { [K in keyof TDefs & string]: TDefs[K] extends QueueJobDefinition ? K : never; }[keyof TDefs & string]; /** Throws when a definition is unusable. Safe to call more than once. */ export declare function validateBackgroundDefs(defs: BackgroundDefs): void; /** @deprecated Use validateBackgroundDefs. */ export declare const validateJobsDefs: typeof validateBackgroundDefs; /** * Delay in ms before retry `attempt` (1-based = the attempt that just failed). * Jittered by ±20% so a shared outage does not retry every job in lockstep. * A caller-supplied backoff function is returned verbatim — the caller owns it. */ export declare function backoffMs(def: AnyBackgroundDefinition, attempt: number): number; /** * Build the `j` instance bunderstack hands to the config's `jobs` builder * callback (and exports for multi-file job setups). */ export declare function createJobsBuilder, TEnvResult = Record>(): { /** Identity with inference: pins TInput from the schema output. */ job(def: Omit, "kind">): QueueJobDefinition; cron(def: Omit, "kind">): CronDefinition; /** Identity with validation: returns the defs map, typed. */ define(defs: TDefs): TDefs; }; /** Type of the `j` instance — for builder callbacks declared in separate files. */ export type BunderstackJobsBuilder, TEnvResult = Record> = ReturnType>; type JobInputOf = TDef extends QueueJobDefinition ? TInput : undefined; /** * `app.jobs`: `enqueue` narrowed to declared names + payloads. `Omit`s the * runtime facade's loose `enqueue` first — intersecting two same-named * methods instead would make TS treat them as overloaded, so the loose * `(name: string, ...)` signature would still accept any name. */ export type JobsFacade = Omit & { enqueue>(name: K, ...rest: JobInputOf extends undefined ? [input?: undefined, opts?: EnqueueOptions] : [input: JobInputOf, opts?: EnqueueOptions]): Promise<{ id: string; }>; }; export {}; //# sourceMappingURL=define.d.ts.map