export type JobStates = {
    created: 'created';
    retry: 'retry';
    active: 'active';
    completed: 'completed';
    cancelled: 'cancelled';
    failed: 'failed';
};
export type Events = {
    error: 'error';
    warning: 'warning';
    wip: 'wip';
    stopped: 'stopped';
    bam: 'bam';
    flow: 'flow';
};
export interface IDatabase {
    executeSql(text: string, values?: unknown[]): Promise<{
        rows: any[];
    }>;
    /**
     * Optional capability for LISTEN/NOTIFY support. When present, pg-boss can hold a
     * dedicated session-pinned connection to receive notifications. The built-in pool-based
     * Db implements this; custom adapters may implement it to enable `useListenNotify`.
     * Must invoke `onReconnect` after each successful (re)subscribe so missed notifications
     * can be recovered. Returns a handle whose `close()` tears down the listener.
     */
    listen?(channel: string, onNotification: (payload: string) => void, onReconnect: () => void): Promise<ListenHandle>;
    /**
     * Optional capability for pg-boss-owned transactions. When present, pg-boss can open a
     * transaction and settle it from a different call frame, which is what
     * `work(name, { transactional: true }, ...)` needs. The built-in pool-based Db implements it;
     * a custom adapter may implement it to enable transactional workers.
     */
    beginTransaction?(): Promise<TransactionHandle>;
    /**
     * Optional capability for per-session setup. pg-boss calls this during `start()`, before it
     * issues any statement, with the complete set of SQL statements that must have run on every
     * session the adapter executes pg-boss statements on. Each call replaces the previous set; an
     * empty array clears it.
     *
     * A pooled adapter runs them on every connection it opens, before handing it out. A
     * single-connection adapter (PGlite) runs them once. The requirement covers sessions that run
     * pg-boss statements, not literally every connection: a dedicated LISTEN connection that only
     * subscribes and never reads the clock is outside it.
     *
     * Only a `TestClock` populates this today - the schema clock is gated on a session setting, so
     * an adapter that cannot carry one would put some sessions on fake time and some on real time,
     * silently and differently on every checkout. `start()` refuses a TestClock on an adapter that
     * does not implement this.
     */
    setSessionStatements?(statements: string[]): Promise<void>;
}
export interface ListenHandle {
    close(): Promise<void>;
}
export interface TransactionHandle {
    /** Runs statements inside the transaction. Pass it as the `db` option on any pg-boss call. */
    db: IDatabase;
    /**
     * Commits and releases the underlying connection. Rejects if the commit fails, or if the
     * transaction has already been settled.
     */
    commit(): Promise<void>;
    /**
     * Rolls back and releases the underlying connection. Never rejects, and safe to call more than
     * once. Implementations must not wait indefinitely: a rollback that cannot get through has to
     * drop the connection instead, so the caller's error path always makes progress.
     */
    rollback(): Promise<void>;
}
export interface DatabaseOptions {
    application_name?: string;
    database?: string;
    user?: string;
    password?: string | (() => string | Promise<string>);
    host?: string;
    port?: number;
    schema?: string;
    ssl?: any;
    connectionString?: string;
    /**
     * Command-line options sent to the server on connect, e.g. `-c statement_timeout=5000`. Applied
     * to every connection in the pool. Passed through to `pg`.
     */
    options?: string;
    max?: number;
    db?: IDatabase;
    connectionTimeoutMillis?: number;
    /**
     * Interval in milliseconds between LISTEN/NOTIFY heartbeat checks on the dedicated
     * listener connection. Lower values detect silent connection drops faster at the cost
     * of more heartbeat queries. Defaults to 10000.
     */
    notifyHeartbeatIntervalMs?: number;
    /**
     * Timeout in milliseconds for each LISTEN/NOTIFY heartbeat query. If a heartbeat does
     * not complete within this window the listener is torn down and reconnected. Raise this
     * on a loaded database where the default is too aggressive. Defaults to 5000.
     */
    notifyHeartbeatTimeoutMs?: number;
    /**
     * TCP keepalive initial delay in milliseconds for the dedicated LISTEN/NOTIFY connection.
     * Defaults to 10000.
     */
    notifyKeepAliveInitialDelayMs?: number;
}
export interface SchedulingOptions {
    schedule?: boolean;
    clockMonitorIntervalSeconds?: number;
    cronWorkerIntervalSeconds?: number;
    cronMonitorIntervalSeconds?: number;
}
/**
 * A named database backend. Selecting a backend turns on the internal compatibility
 * behavior it needs (`noSkipLocked`, `noMultiMutationCte`, `noTablePartitioning`, etc.).
 * Those flags are derived from the backend and are not individually configurable.
 *
 * Backends fall into three kinds, standard, distributed, and embedded:
 * - `postgres` (default): standard PostgreSQL, all flags off.
 * - `cockroachdb`: distributed; enables `noSkipLocked`, `noMultiMutationCte`, `noListenNotify`, and all four `no*` schema gates.
 * - `yugabytedb`: distributed; enables `noAdvisoryLocks` and `noTablePartitioning`. Supports cluster-wide
 *   LISTEN/NOTIFY (early access, off by default, enable the `ysql_yb_enable_listen_notify` flag).
 * - `citus`: distributed; plain PostgreSQL behavior (Citus tables stay coordinator-local); LISTEN/NOTIFY works on the coordinator.
 * - `pglite`: embedded (NOT distributed) single-connection WASM PostgreSQL, all gates off; supports in-process LISTEN/NOTIFY.
 *
 * Spanner, Aurora DSQL, and other targets do not have a profile yet and are not
 * supported. @see https://pgboss.io/database-backends
 */
export type BackendProfile = 'postgres' | 'cockroachdb' | 'yugabytedb' | 'citus' | 'pglite';
export interface MaintenanceOptions {
    supervise?: boolean;
    migrate?: boolean;
    createSchema?: boolean;
    /**
     * Skips the startup check that refuses to install into `schema` when another schema differing
     * from it only by case already holds a pg-boss installation.
     *
     * That check exists because `schema: 'MySchema'` and `schema: '"MySchema"'` name two different
     * schemas. PostgreSQL folds the unquoted form to `myschema` and stores the quoted one verbatim,
     * so mis-spelling the quoting installs an empty second schema and every existing job appears to
     * vanish. Set this only if you genuinely intend two installations whose names differ by case.
     * @default false
     */
    allowSchemaCaseVariant?: boolean;
    warningSlowQuerySeconds?: number;
    warningQueueSize?: number;
    superviseIntervalSeconds?: number;
    maintenanceIntervalSeconds?: number;
    queueCacheIntervalSeconds?: number;
    monitorIntervalSeconds?: number;
    persistWarnings?: boolean;
    warningRetentionDays?: number;
    persistQueueStats?: boolean;
    queueStatRetentionDays?: number;
    bamIntervalSeconds?: number;
    flowIntervalSeconds?: number;
    /**
     * Rebuild bloated job indexes with `REINDEX INDEX CONCURRENTLY` during maintenance.
     *
     * Autovacuum reclaims heap space but never shrinks a btree, so a job index stays at the size of
     * the largest backlog its queue has ever held. Every later vacuum then walks all of those pages,
     * which is the dominant cost on a drained queue. Rebuilds are gated on a density check, so a
     * healthy installation never runs one.
     *
     * Set `false` to disable rebuilds entirely. Bloat detection and the `index_bloat` warning are
     * unaffected, use `getReindexCommands()` to run the statements yourself.
     * @default true
     */
    reindex?: boolean | ReindexOptions;
    /**
     * How often the bloat check runs. One instance per interval performs it, coordinated through
     * `version.reindex_on`. Must be >=1 second and cannot exceed 24 hours.
     * @default 86400
     */
    reindexIntervalSeconds?: number;
    /**
     * Whether to check that vacuum is keeping up with the queues. Covers two warnings, because the
     * fixes are opposite: `xmin_horizon` when vacuum runs and reclaims nothing (something is pinning
     * the MVCC horizon. An idle-in-transaction backend, a lagging replication slot, a standby with
     * `hot_standby_feedback`, a prepared transaction), and `autovacuum_disabled` when nothing is
     * vacuuming the table at all. Either way dead tuples and index bloat accumulate without bound,
     * which is the precondition for every documented Postgres-queue collapse.
     *
     * There is no threshold to set. Both fire on measured evidence: a job table past the point
     * Postgres itself would vacuum it, plus what two consecutive passes show about whether a vacuum
     * ran and whether it reclaimed anything. Sensitivity is tuned with Postgres's own
     * `autovacuum_vacuum_threshold` / `autovacuum_vacuum_scale_factor`, per table if wanted.
     * @default true
     */
    monitorVacuum?: boolean;
}
/** Thresholds for the index-bloat density check. */
export interface IndexBloatOptions {
    /**
     * Ignore indexes smaller than this many 8 kB pages.
     * @default 128
     */
    minPages?: number;
    /**
     * Live index entries per 8 kB page below which an index is considered bloated.
     * @default 5
     */
    maxEntriesPerPage?: number;
    /**
     * How many times larger than its live entries need an index must be before it counts as bloated.
     * The size those entries need is estimated from `pg_stats`, so a legitimately sparse index. A
     * long `singletonKey` packs fewer than five entries per page while perfectly packed, is not
     * mistaken for a bloated one.
     * @default 4
     */
    minSizeRatio?: number;
}
export interface ReindexOptions extends IndexBloatOptions {
    /**
     * Rebuild every job index in scope instead of only the bloated ones, and ignore the interval
     * claim so the pass runs immediately.
     * @default false
     */
    force?: boolean;
    /**
     * Never rebuild an index larger than this many bytes. A large index that still passes the density
     * gate carries a genuinely expensive rebuild, so it is left to an operator.
     * @default 2147483648
     */
    maxIndexBytes?: number;
}
export interface SuperviseOptions {
    /**
     * Overrides the constructor's `reindex` setting for this pass only.
     */
    reindex?: boolean | ReindexOptions;
}
/** A bloated index found by the maintenance density check. */
export interface IndexBloat {
    /** Index name, unqualified. */
    name: string;
    /** The job table the index belongs to. */
    table: string;
    /** Index size in 8 kB pages. */
    pages: number;
    /** Live index entries, as of the last VACUUM/ANALYZE. */
    entries: number;
    /** Index size on disk. */
    bytes: number;
    /** Whether the connected role can `REINDEX` it. */
    owned: boolean;
}
export interface QueueStats {
    name: string;
    deferredCount: number;
    queuedCount: number;
    readyCount: number;
    activeCount: number;
    failedCount: number;
    totalCount: number;
    capturedOn: Date;
}
export interface QueueStatsOptions {
    /** persistQueueStats on: only return snapshots captured at or after this time. */
    from?: Date;
    /** persistQueueStats on: only return snapshots captured at or before this time. */
    to?: Date;
    /** persistQueueStats on: maximum number of snapshots to return (1–100000, default 1000). */
    limit?: number;
    /**
     * persistQueueStats on: downsample the recorded series into fixed-width time buckets this many
     * seconds wide, returning one aggregated snapshot per bucket instead of raw rows. Each bucket
     * collapses its count columns via {@link aggregate}. Buckets align to the Unix epoch, so their
     * boundaries are deterministic and stable across calls. Must be a positive integer. Omitted →
     * raw snapshots (current behavior). Size it so the bucket count stays within `limit`, otherwise
     * only the newest `limit` buckets are returned and the oldest part of the window is dropped.
     */
    bucketSeconds?: number;
    /**
     * persistQueueStats on: auto-downsample. Derive {@link bucketSeconds} so the series fits in
     * roughly this many points, e.g. a chart's pixel width. Must be a positive integer. The window
     * spanned is `from`/`to` when supplied (so an explicit x-axis range yields stable buckets even
     * with sparse data), falling back to the data's own `min`/`max` captured timestamps for any
     * open side. Ignored when `bucketSeconds` is set (explicit resolution wins).
     */
    maxDataPoints?: number;
    /**
     * persistQueueStats on: how each count column is collapsed within a bucket when `bucketSeconds`
     * or `maxDataPoints` is set. `'max'` surfaces peak depth (best for backlog alerting), `'min'`
     * the trough, `'avg'` the rounded mean. Ignored when neither bucket option is set.
     * @default 'max'
     */
    aggregate?: 'max' | 'min' | 'avg';
    /**
     * persistQueueStats off: return a fresh reading. Recomputes the counts from the job table and
     * refreshes the queue-table cache rather than serving the regular (up to ~1h) cache, but still
     * reuses anything computed in the last minute so repeated forced calls don't each re-aggregate.
     */
    force?: boolean;
}
/**
 * Options for running pg-boss against a specific database backend.
 *
 * `backend` is the only knob. It expands to the correct internal compatibility flags
 * for that database (fetch strategy, mutation strategy, schema shape). Those flags are
 * derived from the backend and are not individually configurable, so a deployment can't
 * end up with an inconsistent combination.
 *
 * @see https://pgboss.io/database-backends#backend-profiles
 */
export interface BackendOptions {
    /**
     * Selects the database backend pg-boss is running against, expanding to the right
     * preset of internal compatibility flags. Databases without a profile (e.g. Aurora
     * DSQL, Spanner) are not yet supported.
     * @see BackendProfile
     * @default 'postgres'
     */
    backend?: BackendProfile;
}
export interface Migration {
    release: string;
    version: number;
    previous: number;
    install: string[];
    async?: Array<string | AsyncMigrationCommand>;
    uninstall?: string[];
}
export interface AsyncMigrationCommand {
    name: string;
    command: string;
    partitionPolicy?: QueuePolicy;
}
export interface MigrationPartition {
    tableName: string;
    policy: QueuePolicy;
}
export interface PlanOptions {
    /**
     * The backend the SQL is meant to run against, named the way the constructor names it. Exported
     * SQL is run by hand, so it has to be the SQL that engine accepts: without this, plans are stock
     * PostgreSQL and a distributed backend rejects them partway through, table partitioning,
     * advisory locks, covering indexes, a column written in the transaction that added it.
     * `pglite` is stock PostgreSQL and needs nothing here.
     * @default 'postgres'
     */
    backend?: BackendProfile;
}
export interface ConstructionPlanOptions extends PlanOptions {
    /**
     * Include `CREATE SCHEMA`. Turn it off where the schema already exists or is created by
     * something else.
     * @default true
     */
    createSchema?: boolean;
}
export interface MigrationPlanOptions extends PlanOptions {
    /**
     * The partitioned job tables the migration should fan its index builds out across, as
     * `getQueues()` reports them. Only a caller holding a live connection can enumerate these;
     * without them a migration builds indexes on the shared table alone.
     */
    partitionTables?: MigrationPartition[];
}
/**
 * Source of time and timers. pg-boss reads the wall clock and schedules every poll, heartbeat and
 * timeout through this interface so a test can substitute a controllable clock.
 */
export interface Clock {
    /** epoch milliseconds */
    now(): number;
    setTimeout(fn: () => void, ms: number): ClockTimer;
    clearTimeout(handle: ClockTimer): void;
    setInterval(fn: () => void, ms: number): ClockTimer;
    clearInterval(handle: ClockTimer): void;
}
/**
 * Opaque handle returned by a Clock's setTimeout/setInterval and accepted by its clear methods.
 * The system clock returns NodeJS.Timeout; a test clock returns whatever it uses to track timers.
 */
export type ClockTimer = unknown;
/**
 * A Clock that also owns the Postgres-side clock. PgBoss attaches it on start(), after the schema
 * is installed, and disposes the returned handle on stop(). The handle is the only attachment state.
 */
export interface AttachableClock extends Clock {
    attach(target: {
        db: IDatabase;
        schema: string;
    }): Promise<AsyncDisposable>;
}
export interface ConstructorOptions extends DatabaseOptions, SchedulingOptions, MaintenanceOptions, BackendOptions {
    /**
     * Source of time and timers for this instance. Defaults to the system clock (`Date.now` and the
     * global timer functions).
     * @default systemClock
     */
    clock?: Clock;
    /**
     * Enables the LISTEN/NOTIFY listener so workers on notify-enabled queues are woken
     * the moment a job is created, instead of waiting out their polling interval. This
     * holds one dedicated database connection for listening. Polling always remains active
     * as a correctness floor. Requires a pg-boss-owned pool (or an adapter that supports
     * `listen`) and a session-pinned connection. It will not work through PgBouncer in
     * transaction pooling mode. When it can't be established, pg-boss emits a `warning` and
     * continues polling only. Opt in per queue via the queue's `notify` option.
     * @default false
     */
    useListenNotify?: boolean;
    /**
     * Enables job spies for deterministic testing (see `getSpy`). Adds per-transition
     * tracking overhead, **NOT for production.**
     * @default false
     */
    __test__enableSpies?: boolean;
}
/**
 * Options for a queue. All retry, expiration, and retention options set on a
 * queue will be inherited by each job in the queue unless they are overridden.
 */
export interface QueueOptions {
    /**
     * How many seconds a job may be in active state before being retried or
     * failed. Must be >=1. The default is 15 minutes.
     * @default 900
     */
    expireInSeconds?: number;
    /**
     * How many seconds a job may be in created or retry state before it's
     * deleted. Must be >=1. The default is 14 days.
     * @default 1209600
     */
    retentionSeconds?: number;
    /**
     * How long a job should be retained in the database after it's completed. Set
     * to `0` to never delete completed jobs. The default is 7 days.
     * @default 604800
     */
    deleteAfterSeconds?: number;
    /**
     * Number of times a job is allowed to be retried before it is marked as
     * failed.
     * @default 2
     */
    retryLimit?: number;
    /**
     * Delay between retries of failed jobs, in seconds.
     * @default 0
     */
    retryDelay?: number;
    /**
     * Enables exponential backoff retries based on `retryDelay` instead of a
     * fixed delay. Sets initial `retryDelay` to 1 if not set.
     *
     * A simplified function to get the delay between runs is: `retryDelay * 2 ^ retryCount`
     * with some jitter.
     *
     * The function used to determine the backoff delay is:
     * ```js
     * Math.min(retryDelayMax, retryDelay * (2 ** Math.Min(16, retryCount) / 2 + 2 Math.Min(16, retryCount) / 2 * Math.random()))
     * ```
     * @default false
     */
    retryBackoff?: boolean;
    /**
     * Maximum delay between retries of failed jobs, in seconds. Only used when
     * `retryBackoff` is `true`. The default is no limit.
     */
    retryDelayMax?: number;
    /**
     * Expected heartbeat interval in seconds. When set, workers must send periodic
     * heartbeats. If no heartbeat is received within this interval, the monitor will
     * fail/retry the job. Must be >= 10. NULL = heartbeat disabled (default).
     */
    heartbeatSeconds?: number;
}
export interface GroupOptions {
    id: string;
    tier?: string;
}
export interface DependencyRef {
    name: string;
    id: string;
}
export interface GroupConcurrencyConfig {
    default: number;
    tiers?: Record<string, number>;
}
export interface JobOptions {
    id?: string;
    priority?: number;
    startAfter?: number | string | Date;
    singletonKey?: string;
    singletonSeconds?: number;
    singletonNextSlot?: boolean;
    group?: GroupOptions;
    deadLetter?: string;
}
export interface FlowJob {
    ref: string;
    name: string;
    data?: object;
    options?: Omit<JobInsert, 'data'>;
    dependsOn?: string[];
}
export interface ConnectionOptions {
    db?: IDatabase;
}
export interface CompleteOptions extends ConnectionOptions {
    includeQueued?: boolean;
}
export interface FindJobsOptions extends ConnectionOptions {
    id?: string;
    key?: string;
    data?: object;
    queued?: boolean;
}
/**
 * Which dead-lettered jobs a redrive is about, and where they go. Shared by
 * `redrive()` and `previewRedrive()`, so a preview counts exactly what the
 * redrive would move.
 */
export interface RedriveFilter extends ConnectionOptions {
    /**
     * Override queue to move jobs into. Defaults to each job's original source
     * queue (`sourceName`). Jobs with no recorded source queue are only
     * moved when this is supplied.
     */
    destination?: string;
    /**
     * Only redrive jobs that originated from this source queue. Useful when a
     * single dead letter queue collects from multiple sources.
     */
    sourceName?: string;
    /** Only redrive jobs whose payload contains this object, matched the same way as `findJobs()`. */
    data?: object;
    /**
     * Only redrive jobs that arrived in the dead letter queue before this time. Also the way to
     * drain a fixed set in several calls: jobs dead-lettered after it are never swept in.
     */
    createdBefore?: Date;
    /** Only redrive these jobs, by their id in the dead letter queue. */
    ids?: string[];
}
export interface RedriveOptions extends RedriveFilter {
    /**
     * Maximum number of jobs to move in this call, oldest first. Loop or schedule
     * repeated calls to drain at a controlled rate.
     * @default 1000
     */
    limit?: number;
}
export interface RedrivePreview {
    /** Every job the filter matches, routable or not. */
    total: number;
    /** Where the routable jobs would go, most first. */
    destinations: {
        name: string;
        count: number;
    }[];
    /**
     * Matching jobs a redrive would leave in place: no recorded source queue and no `destination`,
     * or a source queue that no longer exists.
     */
    unroutable: number;
}
export type InsertOptions = ConnectionOptions & {
    returnId?: boolean;
};
export type SendOptions = JobOptions & QueueOptions & ConnectionOptions;
/**
 * When `update()`/`upsert()` targets jobs by `singletonKey` and more than one
 * pre-active (created or retry) job shares that key (possible under
 * throttle/debounce or a manually-set key on a `standard` queue), this selects
 * which match(es) to overwrite, ordered by `createdOn`:
 * - `newest` (default) overwrites the most recently enqueued match
 * - `oldest` overwrites the earliest enqueued match
 * - `all` overwrites every match
 */
export type JobMatchStrategy = 'newest' | 'oldest' | 'all';
/**
 * Options for `update()` and `upsert()`. Target a job with exactly one of `id`
 * or `singletonKey` (`upsert()` requires `singletonKey`). Only the fields you
 * supply are changed; any option you omit is left at the job's current value
 * (this is a partial edit, not a re-`send()`). `match` is only valid when
 * targeting by `singletonKey`.
 *
 * This is a curated subset of `SendOptions`: the throttle/debounce options
 * (`singletonSeconds`, `singletonNextSlot`) are intentionally excluded because
 * `update`/`upsert` do not act on them (a job's throttle slot is preserved).
 */
export type UpdateOptions = Pick<JobOptions, 'id' | 'priority' | 'startAfter' | 'singletonKey' | 'group' | 'deadLetter'> & QueueOptions & ConnectionOptions & {
    match?: JobMatchStrategy;
};
/**
 * The object form accepted by the single-argument overload of `update()` and
 * `upsert()`, mirroring {@link Request} for `send()`. `data` is optional
 * (omit or pass `undefined` to edit only options; pass `null` to clear the
 * payload) and `options` carries the target (`id` or `singletonKey`).
 */
export interface UpdateRequest {
    name: string;
    data?: object | null;
    options?: UpdateOptions;
}
/**
 * The queue policy dictates how jobs are allowed to be queued and processed.
 *
 * - `standard` supports all standard features such as deferral, priority, and
 *   throttling.
 *
 * - `short` only allows 1 job to be queued, unlimited active. Can be extended
 *   with `singletonKey`.
 *
 * - `singleton` only allows 1 job to be active, unlimited queued. Can be
 *   extended with `singletonKey`.
 *
 * - `stately` offers a combination of `short` and `singleton`; only allows 1
 *   job per state, queued and/or active. Can be extended with `singletonKey`.
 *
 * - `exclusive` only allows 1 job to be queued or active. Can be extended with
 *   singletonKey`.
 *
 * - `key_strict_fifo` ensures FIFO ordering per `singletonKey`. Requires
 *   `singletonKey` on every job. A job that is active, in retry, or failed only
 *   holds back successors with the same key; other keys remain fetchable.
 *   Priority cannot reorder jobs within a key. A job that is not yet fetchable
 *   is skipped when choosing a key's head, so deferred jobs join the ordering
 *   when their `startAfter` is reached, and flow-blocked jobs when their
 *   dependencies complete.
 */
export type QueuePolicy = 'standard' | 'short' | 'singleton' | 'stately' | 'exclusive' | 'key_strict_fifo' | (string & {});
export interface Queue extends QueueOptions {
    /**
     * The name of the queue.
     */
    name: string;
    /**
     * The policy for the queue.
     * @default 'standard'
     */
    policy?: QueuePolicy;
    /**
     * If set to true, a dedicated table will be created in the partition scheme.
     * This is more useful for a large queue in order to keep it from being a
     * "noisy neighbor".
     * @default false
     */
    partition?: boolean;
    /**
     * The name of the queue's dead letter queue. When a job fails after all
     * retries, the job's payload will be copied into said queue, copying the same
     * retention and retry configuration as the original job.
     */
    deadLetter?: string;
    /**
     * The number of jobs allowed to exist in the created or retry state before
     * emitting a warning event.
     */
    warningQueueSize?: number;
    /**
     * Expected heartbeat interval in seconds for jobs in this queue.
     * When set, workers must send periodic heartbeats. NULL = heartbeat disabled (default).
     */
    heartbeatSeconds?: number;
    /**
     * When `true`, creating a job on this queue emits a Postgres NOTIFY so workers wake
     * immediately rather than waiting for their next poll. Requires the instance-level
     * `useListenNotify` option to be enabled for the listener to act on it. Polling still
     * runs as a fallback.
     * @default false
     */
    notify?: boolean;
}
export interface QueueResult extends Queue {
    deferredCount: number;
    queuedCount: number;
    /**
     * Jobs ready to be processed now: `queuedCount - deferredCount` (clamped at 0). This is the
     * true backlog, `queuedCount` includes deferred (future-dated) jobs that are not yet runnable.
     */
    readyCount: number;
    activeCount: number;
    /**
     * Failed jobs still retained in the table. Bounded by the queue's retention/deletion policy,
     * so this is a rolling count of recent failures, not an all-time total.
     */
    failedCount: number;
    totalCount: number;
    table: string;
    createdOn: Date;
    updatedOn: Date;
    singletonsActive: string[] | null;
}
export type ScheduleOptions = SendOptions & {
    tz?: string;
    key?: string;
    /**
     * What to do about occurrences that came due while no cron pass ran, which is what a deployment
     * being down, or between deploys, leaves behind.
     *
     * `skip` sends nothing for them. `once` sends a single job for the most recent one, however many
     * were missed.
     * @default 'skip'
     */
    missed?: ScheduleMissedPolicy;
};
export interface PreviewScheduleOptions {
    /**
     * Time zone the expression is evaluated in.
     * @default 'UTC'
     */
    tz?: string;
    /**
     * Reference point the walk starts from. Occurrences are strictly after it, so passing the last
     * occurrence of one page back in yields the next page.
     *
     * The default is database time, the instance clock plus the skew cached against the database.
     * Skew is only cached by an instance started with scheduling enabled; on any other instance it is
     * zero and the default reduces to this process's local clock.
     * @default database time (the instance clock plus the cached skew)
     */
    from?: Date;
    /**
     * How many occurrences to return. Must be an integer between 1 and 1000. A finite rule answers
     * with fewer, and one whose last occurrence has passed answers with none.
     *
     * A walk that has not produced them within a second gives up, since occurrences of a sparse
     * expression are expensive to find and the walk holds the event loop while it runs.
     * @default 5
     */
    count?: number;
}
/**
 * How long a worker waits between fetches. The delay before each fetch is chosen by
 * precedence, **burst → notify → base**:
 *
 * 1. **burst** (fetch continuously): a `burstWhen*` trigger is active and the last fetch
 *    came back full, so there is clearly more work to pull.
 * 2. **notify** (`notifyPollingIntervalSeconds`): NOTIFY is active for the queue, so polling
 *    is just a relaxed backstop.
 * 3. **base** (`pollingIntervalSeconds`): the normal idle poll.
 */
export interface JobPollingOptions {
    /**
     * Base interval to check for new jobs, in seconds. Must be >= `0.5` (500 ms).
     *
     * Used when no faster/slower mode applies: queues without `notify`, or notify-enabled
     * queues when the LISTEN/NOTIFY listener is unavailable (e.g. the adapter doesn't support
     * it or the connection dropped).
     * @default 2
     */
    pollingIntervalSeconds?: number;
    /**
     * Interval to check for new jobs, in seconds, used only while NOTIFY is active for the
     * queue, i.e. the queue has `notify: true` and the instance-level LISTEN/NOTIFY
     * listener is established. Since NOTIFY wakes workers immediately, polling only needs to
     * run as a slow backstop, so this can be much larger than `pollingIntervalSeconds`. When
     * notify is off or unavailable, `pollingIntervalSeconds` is used instead. Must be >= `0.5`.
     * @default 30
     */
    notifyPollingIntervalSeconds?: number;
    /**
     * Burst trigger. When the queue's cached `readyCount` (the runnable backlog) exceeds this
     * value, the worker fetches continuously with no delay until it catches up (a fetch that
     * comes back short ends burst mode). Takes precedence over `notifyPollingIntervalSeconds` and
     * `pollingIntervalSeconds`. Must be an integer >= 1.
     *
     * The ready count is read from the stats cache, so reaction latency is bounded by the
     * instance-level stats pipeline (`monitorIntervalSeconds` / `superviseIntervalSeconds` /
     * `queueCacheIntervalSeconds`, all default 60s).
     */
    burstWhenReadyExceeds?: number;
    /**
     * Burst trigger. While each fetch returns a full `batchSize` batch there is clearly more
     * work, so the worker keeps fetching continuously with no delay; the first short fetch ends
     * burst mode. Unlike `burstWhenReadyExceeds` this is instant and needs no cached
     * stats. Ignored when `batchSize` is 1 (every successful fetch would otherwise be "full").
     * @default false
     */
    burstWhenBatchFull?: boolean;
}
export interface JobFetchOptions {
    /**
     * If `true`, all job metadata will be included in the returned job object.
     * @default false
     */
    includeMetadata?: boolean;
    /**
     * @deprecated Ignored since 12.30.0, and removed in the next major. Jobs are always fetched in
     * priority order.
     *
     * This existed to skip the priority sort for throughput, but the fetch index is now ordered to
     * match the fetch, so there is no sort to skip, setting it `false` was measured ~180x *slower*
     * than leaving it alone, since no index leads with `created_on`.
     */
    priority?: boolean;
    /**
     * @deprecated Ignored since 12.30.0, and removed in the next major. Jobs are always fetched in
     * creation order.
     *
     * This existed to skip the `created_on` sort for throughput. The fetch index now provides that
     * order directly, so disabling it saved nothing measurable.
     */
    orderByCreatedOn?: boolean;
    /**
     * The number of jobs to fetch.
     * @default 1
     */
    batchSize?: number;
    /**
     * Fetch jobs even if they have a `startAfter` timestamp in the future.
     * @default false
     */
    ignoreStartAfter?: boolean;
    /**
     * Only fetch jobs with a priority greater than or equal to this value.
     * Useful for reserving worker capacity exclusively for higher-priority jobs.
     * Must be an integer. If both `minPriority` and `maxPriority` are set,
     * `minPriority` must be less than or equal to `maxPriority`.
     */
    minPriority?: number;
    /**
     * Only fetch jobs with a priority less than or equal to this value.
     * Useful for workers dedicated to lower-priority background work.
     * Must be an integer. If both `minPriority` and `maxPriority` are set,
     * `minPriority` must be less than or equal to `maxPriority`.
     */
    maxPriority?: number;
}
export interface WorkConcurrencyOptions {
    /**
     * Number of workers to spawn for this queue (per-node).
     * Each worker polls and processes jobs independently.
     */
    localConcurrency?: number;
    /**
     * Limit concurrent jobs per group within this node (in-memory tracking).
     * No database overhead. Does not coordinate across nodes.
     */
    localGroupConcurrency?: number | GroupConcurrencyConfig;
    /**
     * Limit concurrent jobs per group globally across all nodes (database tracking).
     * Coordinates across distributed deployments via database queries.
     */
    groupConcurrency?: number | GroupConcurrencyConfig;
}
export type WorkOptions = JobFetchOptions & JobPollingOptions & WorkConcurrencyOptions & {
    /**
     * Custom heartbeat refresh interval in seconds. Defaults to `heartbeatSeconds / 2`.
     * Must be strictly less than `heartbeatSeconds`.
     */
    heartbeatRefreshSeconds?: number;
    /**
     * Opt in to per-job settlement for batch handlers. When true, the handler must resolve with a
     * `JobResult[]` describing the outcome (`completed`, `failed`, or `deadletter`, with optional
     * per-job `output`) of each job in the batch. pg-boss settles each job individually, preserving
     * its own output. Any job omitted from the result is failed (and retried) with a descriptive
     * error. Throwing from the handler still fails the whole batch. Defaults to false.
     */
    perJobResults?: boolean;
    /**
     * Run the handler and the job's completion inside one database transaction.
     *
     * The handler receives a second argument, a `db` for that transaction. Anything written through
     * it commits atomically with the job's completion, so a handler cannot leave its side effects
     * committed and the job unfinished, or the reverse. Throwing rolls back the handler's writes and
     * the completion, and the job is then failed on a pooled connection, so retry counts, retry
     * delays, and dead lettering work exactly as they do without this option.
     *
     * The job is claimed before the transaction opens, so it stays `active` for as long as the
     * handler runs and every supervision path (`expireInSeconds`, heartbeats, another instance's
     * monitor) sees it.
     *
     * Requires a database connection pg-boss can open a transaction on: the built-in pool, or a `db`
     * adapter implementing `beginTransaction`. Cannot be combined with `perJobResults`, which
     * settles each job in a batch separately while one transaction has a single outcome.
     *
     * Each handler in flight holds a connection for its own duration, so the pool needs room for
     * `localConcurrency` connections on top of what the rest of pg-boss uses. Long transactions also
     * hold back vacuum, so this suits handlers that finish in seconds.
     * @default false
     */
    transactional?: boolean;
    /**
     * How long the database gives the handler's transaction before it kills the connection under it,
     * in seconds. Only valid with `transactional`. `0` removes the bound.
     *
     * Backstop for the case the in-process timers cannot cover: not a handler that hangs, which
     * `expireInSeconds` already ends, but the process failing under it, where an open transaction
     * goes on holding vacuum off the whole database. Applied as `transaction_timeout` where the
     * server has it (PostgreSQL 17+, CockroachDB) and `idle_in_transaction_session_timeout`
     * otherwise, which bounds the gaps between the handler's statements instead of the whole
     * transaction.
     *
     * Defaults to `expireInSeconds` plus the 5 seconds pg-boss allows its own rollback, so the
     * handler's own timeout and clean rollback always land first and this only fires when they did
     * not run at all.
     */
    transactionTimeoutSeconds?: number;
};
export interface FetchGroupConcurrencyOptions {
    groupConcurrency?: number | GroupConcurrencyConfig;
    ignoreGroups?: string[] | null;
}
export type FetchOptions = JobFetchOptions & ConnectionOptions & FetchGroupConcurrencyOptions;
export interface ResolvedWorkOptions extends WorkOptions {
    pollingInterval: number;
    notifyPollingInterval: number;
}
export interface WorkHandler<ReqData, ResData = any> {
    (job: Job<ReqData>[]): Promise<ResData>;
}
export interface WorkWithMetadataHandler<ReqData, ResData = any> {
    (job: JobWithMetadata<ReqData>[]): Promise<ResData>;
}
export type JobResultStatus = 'completed' | 'failed' | 'deadletter';
/**
 * Per-job outcome returned by a `perJobResults` batch handler. `id` must match a job from the
 * batch; `output` is stored on that job (the completion result, or the failure detail).
 *
 * `deadletter` fails the job terminally and routes it straight to the queue's configured dead
 * letter queue, bypassing any remaining retries. If the queue has no dead letter queue, it simply
 * fails terminally (same as a `failed` job whose retries are exhausted).
 */
export interface JobResult<ResData = any> {
    id: string;
    status: JobResultStatus;
    output?: ResData;
}
export interface PerJobWorkHandler<ReqData> {
    (job: Job<ReqData>[]): Promise<JobResult[]>;
}
export interface PerJobWorkWithMetadataHandler<ReqData> {
    (job: JobWithMetadata<ReqData>[]): Promise<JobResult[]>;
}
/**
 * Handler for a `transactional: true` worker. `tx` runs statements inside the transaction pg-boss
 * commits the batch in, so pass it as the `db` option on any pg-boss call, or hand it to your own
 * SQL, to have that work commit with the job's completion.
 */
export interface TransactionalWorkHandler<ReqData, ResData = any> {
    (jobs: Job<ReqData>[], tx: IDatabase): Promise<ResData>;
}
export interface TransactionalWorkWithMetadataHandler<ReqData, ResData = any> {
    (jobs: JobWithMetadata<ReqData>[], tx: IDatabase): Promise<ResData>;
}
/**
 * Resolves the handler signature a `work` call must satisfy from the *inferred* options type `O`.
 * A literal `transactional: true` adds the transaction `db` as a second parameter. A literal
 * `perJobResults: true` (optionally with `includeMetadata: true`) demands a per-job handler that
 * resolves with a `JobResult[]`; anything else keeps the permissive single-output handler.
 *
 * Because each branch is driven by `O extends { flag: true }`, only a statically-known `true`
 * selects the stricter handler. Options whose flag is a plain `boolean` (e.g. a value typed as
 * `WorkOptions`, or `{ perJobResults: someFlag }`) do not match the literal and fall through to the
 * permissive handler, so dynamically-built options keep compiling exactly as before.
 */
export type WorkHandlerFor<O extends WorkOptions, ReqData, ResData = any> = O extends {
    transactional: true;
} ? (O extends {
    includeMetadata: true;
} ? TransactionalWorkWithMetadataHandler<ReqData, ResData> : TransactionalWorkHandler<ReqData, ResData>) : O extends {
    perJobResults: true;
} ? (O extends {
    includeMetadata: true;
} ? PerJobWorkWithMetadataHandler<ReqData> : PerJobWorkHandler<ReqData>) : (O extends {
    includeMetadata: true;
} ? WorkWithMetadataHandler<ReqData, ResData> : WorkHandler<ReqData, ResData>);
export interface Request {
    name: string;
    data?: object;
    options?: SendOptions;
}
/** Which format a schedule's expression is in. */
export type ScheduleKind = 'cron' | 'rrule';
/** What a schedule does about occurrences that came due while no cron pass ran. */
export type ScheduleMissedPolicy = 'skip' | 'once';
export interface Schedule {
    name: string;
    key: string;
    /** Which of the two formats `cron` holds, decided by `schedule()` and stored on the row. */
    kind: ScheduleKind;
    /** The cron expression or recurrence rule this schedule recurs on. */
    cron: string;
    timezone: string;
    data?: object;
    /**
     * The options blob `schedule()` stored, which is every option it was given: the `send()` options
     * each job is created with, and `tz`, `key` and `missed` beside them.
     */
    options?: ScheduleOptions;
    createdOn: Date;
    updatedOn: Date;
    /**
     * Id of the job this schedule most recently created.
     *
     * Recorded on a best-effort basis, in a separate statement once the job exists, so `null` does
     * not mean the schedule never fired. It also reads `null` for a schedule that last fired before
     * the upgrade that added the column, and for one whose annotating statement lost its connection
     * between creating the job and recording it.
     *
     * Not a foreign key: the job is subject to the queue's retention policy and will eventually be
     * deleted, so an id here does not guarantee the job still exists.
     */
    lastJobId: string | null;
}
export interface Job<T = object> {
    id: string;
    name: string;
    data: T;
    expireInSeconds: number;
    heartbeatSeconds: number | null;
    signal: AbortSignal;
    groupId?: string | null;
    groupTier?: string | null;
}
export interface JobWithMetadata<T = object> extends Job<T> {
    priority: number;
    state: 'created' | 'retry' | 'active' | 'completed' | 'cancelled' | 'failed';
    retryLimit: number;
    retryCount: number;
    retryDelay: number;
    retryBackoff: boolean;
    retryDelayMax?: number;
    startAfter: Date;
    startedOn: Date;
    singletonKey: string | null;
    singletonOn: Date | null;
    expireInSeconds: number;
    deleteAfterSeconds: number;
    createdOn: Date;
    completedOn: Date | null;
    keepUntil: Date;
    policy: QueuePolicy;
    heartbeatOn: Date | null;
    heartbeatSeconds: number | null;
    blocked: boolean;
    blocking: boolean;
    pendingDependencies: number;
    deadLetter: string;
    output: object;
    /**
     * For a job that was moved into a dead letter queue, the name of the queue it
     * originally failed on. `null` for jobs that were not dead-lettered.
     */
    sourceName: string | null;
    /**
     * For a dead-lettered job, the id of the original job that failed. `null`
     * otherwise.
     */
    sourceId: string | null;
    /**
     * For a dead-lettered job, the `createdOn` of the original job, preserving its
     * true age in the system across the move. `null` otherwise.
     */
    sourceCreatedOn: Date | null;
    /**
     * For a dead-lettered job, the number of retries the original job consumed
     * before it was dead-lettered. `null` otherwise.
     */
    sourceRetryCount: number | null;
}
export interface JobInsert<T = object> {
    id?: string;
    data?: T;
    priority?: number;
    retryLimit?: number;
    retryDelay?: number;
    retryBackoff?: boolean;
    retryDelayMax?: number;
    startAfter?: number | string | Date;
    singletonKey?: string;
    singletonSeconds?: number;
    expireInSeconds?: number;
    deleteAfterSeconds?: number;
    retentionSeconds?: number;
    heartbeatSeconds?: number;
    group?: GroupOptions;
    deadLetter?: string;
}
export type WorkerState = 'created' | 'active' | 'stopping' | 'stopped';
export interface WipData {
    id: string;
    workId: string;
    name: string;
    options: WorkOptions;
    state: WorkerState;
    count: number;
    createdOn: number;
    lastFetchedOn: number | null;
    lastJobStartedOn: number | null;
    lastJobEndedOn: number | null;
    lastJobDuration: number | null;
    lastError: object | null;
    lastErrorOn: number | null;
}
export interface StopOptions {
    close?: boolean;
    graceful?: boolean;
    timeout?: number;
}
export interface OffWorkOptions {
    id?: string;
    wait?: boolean;
}
export interface EventsMixin extends NodeJS.EventEmitter {
    events: Record<string, string>;
}
export interface FunctionsMixin {
    functions: Function[];
}
export type UpdateQueueOptions = Omit<Queue, 'name' | 'partition' | 'policy' | 'deadLetter' | 'retryDelayMax' | 'heartbeatSeconds'> & {
    /**
     * The name of the queue's dead letter queue, or `null` to clear it.
     */
    deadLetter?: string | null;
    /**
     * Maximum delay between retries of failed jobs, in seconds, or `null` for no limit.
     */
    retryDelayMax?: number | null;
    /**
     * Expected heartbeat interval in seconds, or `null` to disable heartbeats.
     */
    heartbeatSeconds?: number | null;
};
export interface Warning {
    message: string;
    data: object;
}
export type WarningType = 'slow_query' | 'queue_backlog' | 'clock_skew' | 'listen_notify_unavailable' | 'invalid_schedule' | 'index_bloat' | 'xmin_horizon' | 'autovacuum_disabled' | 'monitor_backoff' | 'transactional_pool_headroom' | 'transaction_timeout_probe';
export interface PersistedWarning {
    id: number;
    type: WarningType;
    message: string;
    data: object;
    createdOn: Date;
}
export interface CommandResponse {
}
/**
 * The result of `update()`. Unlike the target-a-list mutators
 * (`cancel`/`resume`/etc.), `update()` discovers how many jobs a target
 * resolves to. `update()` never inserts, so there is no `inserted` count,
 * see {@link UpsertResponse} for `upsert()`.
 */
export interface UpdateResponse {
    /** Ids of the jobs updated in place. */
    jobs: string[];
    /** Number of existing jobs updated in place (equals `jobs.length`). */
    updated: number;
}
/**
 * The result of `upsert()`. Extends {@link UpdateResponse} with the
 * update-vs-insert discriminator: a single `upsert()` either edits the
 * matching job(s) in place (`updated`) or inserts one new job (`inserted`),
 * so exactly one of the two counts is non-zero.
 */
export interface UpsertResponse extends UpdateResponse {
    /** Number of jobs newly inserted (mutually exclusive with `updated`). */
    inserted: number;
}
export interface BamEntry {
    id: string;
    name: string;
    version: number;
    status: 'pending' | 'in_progress' | 'completed' | 'failed';
    queue?: string;
    table: string;
    command: string;
    error?: string;
    createdOn: Date;
    startedOn?: Date;
    completedOn?: Date;
    reattempt?: boolean;
}
export interface BamStatusSummary {
    status: 'pending' | 'in_progress' | 'completed' | 'failed';
    count: number;
    lastCreatedOn: Date;
}
/** One managed index pg-boss expects to exist, and the table it belongs to. */
export interface ManagedIndex {
    name: string;
    table: string;
    /** Readable expected key-column list (ordered), for definition-diff. Absent if not derivable. */
    keys?: string;
    /** Readable expected INCLUDE payload column list, '' for an index with no INCLUDE clause. */
    include?: string;
    /** Readable expected partial-index predicate (the WHERE clause), '' for a non-partial index. */
    predicate?: string;
    /** The full expected `CREATE INDEX` statement (schema-qualified), ready to run to recreate it. */
    definition?: string;
}
/**
 * A managed index that is present in the catalog but marked INVALID. Its definition is correct (an
 * interrupted build, not a wrong shape), so only the expected `definition` is carried. There is no
 * meaningful actual-vs-expected diff to show.
 */
export interface InvalidIndex extends ManagedIndex {
    /** True when a pending/in_progress/failed BAM row is (re)building it, so it may heal itself. */
    building: boolean;
}
/** A present index whose key columns/order or predicate differ from what the code expects. */
export interface MismatchedIndex extends ManagedIndex {
    /** Readable key-column list the code expects. */
    expectedKeys: string;
    /** Readable key-column list actually in the catalog (from pg_get_indexdef). */
    actualKeys: string;
    /** Readable INCLUDE payload list the code expects ('' when it expects no INCLUDE clause). */
    expectedInclude: string;
    /** Readable INCLUDE payload list actually in the catalog ('' when the live index has none). */
    actualInclude: string;
    /** Readable predicate the code expects ('' for a non-partial index). */
    expectedPredicate: string;
    /** Readable predicate actually in the catalog, from pg_get_indexdef ('' for a non-partial index). */
    actualPredicate: string;
    /** The index's current definition from pg_get_indexdef, for side-by-side comparison with `definition`. */
    actualDefinition: string;
    /** Which parts differ, any of 'keys', 'include', 'predicate'. */
    differs: Array<'keys' | 'include' | 'predicate'>;
}
/** One managed plpgsql/sql function pg-boss expects to exist, with its normalised body for diffing. */
export interface ManagedFunction {
    name: string;
    /** Whitespace-normalised expected function body (the text between the outer `$$` dollar quotes). */
    expectedBody: string;
    /** The full expected `CREATE FUNCTION` statement (schema-qualified), ready to run to recreate it. */
    definition: string;
}
/** A present managed function whose body differs from what the code expects. */
export interface MismatchedFunction extends ManagedFunction {
    /** Whitespace-normalised body actually stored in the catalog (from pg_get_functiondef). */
    actualBody: string;
    /** The function's current definition from pg_get_functiondef, for side-by-side comparison. */
    actualDefinition: string;
}
/** Column drift for a managed table: columns the code expects that are absent, columns present in the
 *  catalog that the code does not expect, and (fixed tables only) columns whose default, data type, or
 *  nullability differs from the code's DDL. */
export interface TableColumnDrift {
    /** The (unqualified) table name. */
    table: string;
    /** Expected columns with no matching catalog column. */
    missingColumns: string[];
    /** Catalog columns the expected set does not account for. */
    unexpectedColumns: string[];
    /** Columns whose live default expression differs from the code's expected default (fixed tables only). */
    defaultMismatches: Array<{
        column: string;
        expected: string;
        actual: string;
    }>;
    /** Columns whose live data type differs from the code's expected type (fixed tables only). */
    typeMismatches: Array<{
        column: string;
        expected: string;
        actual: string;
    }>;
    /** Columns whose live NOT NULL flag differs from the code's expectation (fixed tables only). */
    nullabilityMismatches: Array<{
        column: string;
        expected: boolean;
        actual: boolean;
    }>;
}
/** Constraint-set drift for a managed table: expected constraints absent from the catalog, and catalog
 *  constraints the code does not expect. Compared on normalised pg_get_constraintdef strings. */
export interface ConstraintDrift {
    /** The (unqualified) table name. */
    table: string;
    /** Expected constraints with no matching catalog constraint. */
    missingConstraints: string[];
    /** Catalog constraint definitions the expected set does not account for. */
    unexpectedConstraints: string[];
}
/** Drift in an enum type's value set or ordering (pg-boss's `job_state`). */
export interface EnumDrift {
    /** The enum type's name (e.g. `job_state`). */
    name: string;
    /** Ordered enum labels the code expects. */
    expectedValues: string[];
    /** Ordered enum labels actually in the catalog. */
    actualValues: string[];
}
/**
 * Result of a schema drift scan: managed indexes, functions, and enums that should exist per the
 * code's expected shape vs. what the live catalog actually holds. Covers presence (missing / invalid
 * / unexpected) and definition-level drift (a present index, function body, or enum whose shape
 * differs from what the code emits).
 */
export interface SchemaDriftReport {
    /** True when nothing is missing, invalid, mismatched, or drifted (tables, columns, defaults, types,
     *  constraints, enum). `extraIndexes` is informational and does NOT affect this. */
    ok: boolean;
    /** Expected managed tables with no matching catalog table. */
    missingTables: string[];
    /** Expected indexes with no matching catalog entry (excludes ones a BAM row is still building). */
    missing: ManagedIndex[];
    /** Expected indexes still being built by a pending/in_progress/failed BAM row, not yet drift. */
    building: ManagedIndex[];
    /** Present indexes marked INVALID (interrupted CREATE INDEX CONCURRENTLY). */
    invalid: InvalidIndex[];
    /**
     * Standalone (non-constraint-backing) indexes present on a managed table that the expected set does
     * not account for. A stale pg-boss index or one a user added. Informational only: an extra index is
     * harmless, so this is surfaced as a warning and does not make the schema "not ok".
     */
    extraIndexes: Array<{
        name: string;
        table: string;
    }>;
    /** Present indexes whose key columns/order differ from the expected definition. */
    mismatched: MismatchedIndex[];
    /** Expected functions with no matching catalog entry. */
    missingFunctions: ManagedFunction[];
    /** Present functions whose body differs from the code's expected definition. */
    mismatchedFunctions: MismatchedFunction[];
    /** Managed tables with missing/unexpected columns or column-default drift (only differing tables). */
    columnDrift: TableColumnDrift[];
    /** Managed tables with missing or unexpected constraints (only tables that differ are listed). */
    constraintDrift: ConstraintDrift[];
    /** Enum drift when the live `job_state` value set/order differs from the code; null when it matches. */
    enumDrift: EnumDrift | null;
}
export interface FlowEvent {
    table: string;
    resolved: number;
}
export interface BamEvent {
    id: string;
    name: string;
    status: string;
    queue?: string;
    table: string;
    error?: string;
}
export type PgBossEventMap = {
    error: [error: Error];
    warning: [warning: Warning];
    wip: [data: WipData[]];
    stopped: [];
    bam: [data: BamEvent];
    flow: [data: FlowEvent];
};
//# sourceMappingURL=types.d.ts.map