/** * Portable request-deadline mechanics owned by core. * * A wire deadline is an absolute wall-clock instant so every hop shares one end time. Once admitted, * remaining time is measured against a monotonic clock so NTP or manual wall-clock changes cannot * add time back to an in-flight request. Policy stays out of this primitive. */ /** Canonical wire header carrying an absolute Unix epoch deadline in milliseconds. */ export declare const NIFRA_DEADLINE_HEADER = "x-nifra-deadline"; /** The only clocks deadline mechanics need. Inject both for deterministic tests. */ export interface BudgetClock { /** Monotonic milliseconds; must never move backwards during the process lifetime. */ monotonic(): number; /** Unix epoch milliseconds; used only to translate an absolute wire deadline on admission. */ wall(): number; } /** A time budget shared by one request and every downstream hop it initiates. */ export interface RequestBudget { /** Absolute Unix epoch deadline for wire propagation. */ readonly deadline: number; /** The request cancellation signal. Nifra drives this when its effective deadline elapses. */ readonly signal: AbortSignal; /** Non-negative milliseconds remaining, measured with the monotonic clock. */ remaining(): number; /** A view that finishes `reserveMs` before this budget, preserving time for response cleanup. */ child(reserveMs: number): RequestBudget; } export type DeadlineHeaderResult = { readonly ok: true; readonly deadline: number; } | { readonly ok: false; readonly reason: "missing" | "malformed"; }; /** DOM-lib-independent subset accepted by the Web `Headers` constructor. */ export type DeadlineHeadersInit = Headers | Readonly> | [string, string][] | undefined; export interface CreateRequestBudgetOptions { /** Absolute Unix epoch deadline. */ readonly deadline: number; readonly signal: AbortSignal; readonly clock?: BudgetClock; } export interface DeadlineAdmissionOptions { /** Local request timeout. `0` keeps requests without a wire deadline unbounded. */ readonly localTimeoutMs?: number; /** Hard cap for a request carrying the wire header. Default 30 seconds. */ readonly maxInboundDeadlineMs?: number; /** Injected wall clock for deterministic admission tests. */ readonly wallNow?: () => number; } export type DeadlineAdmission = { readonly ok: true; readonly inherited: boolean; readonly timeoutMs: number; /** Absent only for the unbounded no-header/no-local-timeout case. */ readonly deadline?: number; } | { readonly ok: false; readonly status: 400 | 408; readonly reason: "malformed_deadline" | "deadline_exceeded"; }; /** Sentinel used only for an unbounded local budget. It is never written to the wire. */ export declare const UNBOUNDED_DEADLINE: number; export declare class DeadlineExceededError extends Error { readonly remainingMs: number; readonly requiredMs: number; readonly code: "NIFRA_DEADLINE_EXCEEDED"; readonly status: 504; constructor(remainingMs: number, requiredMs: number); } /** * Create a budget from an admitted absolute deadline. Wall time is sampled once; every subsequent * `remaining()` call is monotonic. This function does not arm a timer-the owner of `signal` does. */ export declare function createRequestBudget(options: CreateRequestBudgetOptions): RequestBudget; /** Create a local no-deadline view. Outbound header propagation deliberately omits it. */ export declare function createUnboundedRequestBudget(signal: AbortSignal): RequestBudget; /** Parse the canonical deadline header without trusting or clamping it. */ export declare function parseDeadlineHeader(headers: Headers): DeadlineHeaderResult; /** * Validate and clamp an inbound absolute deadline. This is pure admission mechanics: callers supply * local policy, then own the timer that drives their existing cancellation signal. */ export declare function admitDeadline(headers: Headers, options?: DeadlineAdmissionOptions): DeadlineAdmission; /** Add this budget's absolute deadline to an outbound request. */ export declare function withDeadlineHeader(input: DeadlineHeadersInit, budget: RequestBudget, reserveMs?: number): Headers; /** Fail before starting work that cannot fit inside the remaining time. */ export declare function assertBudgetRemaining(budget: RequestBudget, requiredMs?: number): void; /** True only when a new attempt plus a caller-owned reserve can still fit. */ export declare function canAttempt(budget: RequestBudget, estimatedAttemptMs: number, reserveMs?: number): boolean; //# sourceMappingURL=budget.d.ts.map