/**
 * Async job runner for long-running submission actions (0.2.0).
 *
 * Why this exists: the previous synchronous handlers (`registerForDustGeneration`,
 * `sendNight`, `deployContract`, ...) awaited multi-minute-to-hours work
 * inline. That kept the OData request's `req.tx` open for the duration,
 * holding a pool connection and blocking unrelated DB ops (notably the
 * periodic wallet-sync-state save, which deadlocked on the first SELECT). The
 * fix: insert a `BackgroundJobs` row on the request's tx, return
 * `{ jobId, status: 'pending' }` in milliseconds, and detach the actual work
 * to `cds.spawn`. Clients poll `getJobStatus(jobId)` for results.
 *
 * Tx isolation: each row mutation inside the spawn uses an explicit
 * `db.tx(async tx => tx.run(...))` short transaction, so the spawn's
 * top-level tx never acquires a connection. Net effect: the spawn callback
 * holds no pool resources while the long work is in flight — only the
 * per-mutation short txs (milliseconds each) consume connections.
 *
 * Concurrency: a per-`kind` in-process semaphore caps how many jobs of a
 * given kind can run at once. Heavy kinds (full ZK proof + chain submit)
 * default to 4, light kinds (sync-bound only) to 16. Tunable via
 * `cds.requires.nightgate.jobs.concurrency.{heavy,light}`.
 *
 * Idempotency: an optional `idempotencyKey` lets the caller dedupe retries.
 * If a non-failed row exists for the same `(sessionId, kind, idempotencyKey)`,
 * `startJob` returns that row's jobId and result (if any) without starting a
 * new spawn. Failed rows do NOT block a retry — that's the intended path for
 * flaky-network recovery.
 *
 * Error classification: failures are run through `classifySubmissionError`
 * (shared with TransactionSubmitter), so the same Substrate / SDK error
 * codes (`1014`, `1016`, `TxFailed`, `WalletSigningNotAvailable`, ...) appear
 * in the job row as the synchronous path used to expose them.
 */
export interface StartJobArgs<TIn, TOut> {
    /** Discriminator; must match one of the kinds the consumer cares about. */
    kind: string;
    /** Owner scope. Job rows are SELECTed by `sessionId` in `getJobStatus`. */
    sessionId: string;
    /** Optional dedupe key; see module docs for semantics. */
    idempotencyKey?: string | null;
    /** Inbound action args — JSON-stringified into `request`. Strip secrets first. */
    request: TIn;
    /** The actual long-running work. Should NOT touch the CAP DB on the main thread. */
    work: () => Promise<TOut>;
}
export interface StartJobResult<TOut = unknown> {
    jobId: string;
    status: 'pending' | 'succeeded';
    /** Only present when an idempotent retry hit an already-succeeded row. */
    result?: TOut;
}
export interface BackgroundJobRow {
    ID: string;
    kind: string;
    sessionId: string | null;
    status: 'pending' | 'running' | 'succeeded' | 'failed';
    idempotencyKey: string | null;
    request: string | null;
    result: string | null;
    errorCode: string | null;
    errorMessage: string | null;
    startedAt: string | null;
    finishedAt: string | null;
    createdAt: string;
    modifiedAt: string;
}
/**
 * Insert a `BackgroundJobs` row on the caller's tx and detach the long work
 * to `cds.spawn`. Returns the `jobId` immediately so the OData handler can
 * respond in milliseconds.
 */
export declare function startJob<TIn, TOut>(args: StartJobArgs<TIn, TOut>): Promise<StartJobResult<TOut>>;
/**
 * Look up a job by ID. Returns null when not found.
 */
export declare function getJobById(jobId: string): Promise<BackgroundJobRow | null>;
/**
 * Flip every still-`pending` or `running` row to `failed:PROCESS_RESTART`.
 * Called once at plugin init (`cds.on('served')`) so jobs interrupted by a
 * crash don't linger forever. Idempotent.
 *
 * Returns the count of rows updated for logging.
 */
export declare function recoverInterruptedJobs(): Promise<number>;
/** Test-only reset of the in-memory caches. */
export declare function __resetForTests(): void;
