/**
 * @fileoverview Canvas lifecycle registry. Keys canvases by (tenantId, canvasId),
 * generates crypto-secure 10-char URL-safe IDs, enforces a sliding 24h TTL
 * with a 7-day absolute cap, runs a periodic sweeper, and caps active canvases
 * per tenant (default 100). Also tracks per-table TTLs; the sweep loop drops
 * expired tables before evaluating canvas-level expiry. Public access is gated
 * by {@link DataCanvas}.
 * @module src/services/canvas/core/CanvasRegistry
 */
import { type RequestContextLike } from '../../../utils/internal/requestContext.js';
import type { TableInfo } from '../types.js';
import type { IDataCanvasProvider } from './IDataCanvasProvider.js';
/** Tunable lifecycle constants for the registry. */
export interface CanvasRegistryOptions {
    /** Absolute cap from creation in milliseconds. Default 7d. */
    absoluteCapMs: number;
    /** Maximum active canvases per tenant. Default 100. */
    maxCanvasesPerTenant: number;
    /** Sweeper interval in milliseconds. Default 60s. Set to 0 to disable. */
    sweeperIntervalMs: number;
    /** Sliding TTL in milliseconds. Default 24h. */
    ttlMs: number;
}
/**
 * Default lifecycle constants. Mirrored in the config schema; exported so
 * tests and downstream tooling can reference the same numbers.
 */
export declare const DEFAULT_CANVAS_REGISTRY_OPTIONS: CanvasRegistryOptions;
/** Result of {@link CanvasRegistry.acquire}. */
export interface AcquireResult {
    canvasId: string;
    /** Wall-clock expiry as ISO 8601, after the sliding extension. */
    expiresAt: string;
    /** True when the registry created the canvas during this acquire call. */
    isNew: boolean;
    tenantId: string;
}
/**
 * Tracks active canvases for a single process. Not multi-process safe — tokens
 * issued by one process are not portable to another.
 */
export declare class CanvasRegistry {
    private readonly provider;
    private readonly options;
    /** Injected for tests. Defaults to `Date.now`. */
    private readonly clock;
    private readonly idGenerator;
    private readonly canvases;
    /** Per-tenant index for cap enforcement and listing. */
    private readonly byTenant;
    private sweeperTimer;
    private isShuttingDown;
    constructor(provider: IDataCanvasProvider, options?: CanvasRegistryOptions, 
    /** Injected for tests. Defaults to `Date.now`. */
    clock?: () => number);
    /**
     * Resolve an existing canvas or create a new one when `maybeId` is omitted
     * or the supplied id is unknown for the caller's tenant.
     *
     * - Omitted id → create fresh, return `isNew: true`.
     * - Unknown id → throw `NotFound` (`reason: 'canvas_not_found'` + recovery hint).
     * - Known id under wrong tenant → throw `NotFound` (uniform with unknown
     *   to avoid leaking existence across tenants).
     * - Known + own tenant → touch (extend TTL), return `isNew: false`.
     */
    acquire(maybeId: string | undefined, tenantId: string, context: RequestContextLike): Promise<AcquireResult>;
    /**
     * Validate that `canvasId` belongs to `tenantId` and is not expired, then
     * extend its TTL and return the resolved expiry. Used by {@link CanvasInstance}
     * before every op so individual operations slide the canvas window.
     */
    touchOrThrow(canvasId: string, tenantId: string): string;
    /**
     * Slide the canvas TTL **and** the per-table TTL for `tableName` (if it has
     * one). Throws `NotFound` when the canvas is gone or expired. Used by
     * {@link CanvasInstance} on table-scoped ops (`registerTable`, `query`).
     */
    touchWithTable(canvasId: string, tenantId: string, tableName: string): string;
    /**
     * Slide per-table TTLs for every table name that appears as a word-boundary
     * match in `sqlText`, in addition to the canvas-level touch and an explicit
     * `primaryTable` slide. Used by `query()` to slide all tables referenced in
     * the SQL, not just the `registerAs` target.
     */
    touchWithSqlTables(canvasId: string, tenantId: string, primaryTable: string | undefined, sqlText: string): string;
    /**
     * Register (or replace) a per-table TTL entry. Called by {@link CanvasInstance}
     * after a successful `registerTable` with `ttlMs` set.
     */
    registerTableTtl(canvasId: string, tenantId: string, tableName: string, ttlMs: number): void;
    /**
     * Remove per-table TTL bookkeeping for `tableName`. Called when a table is
     * explicitly dropped via {@link CanvasInstance.drop} so the sweep loop does
     * not attempt to drop a table that no longer exists.
     */
    dropTableBookkeeping(canvasId: string, tenantId: string, tableName: string): void;
    /**
     * Clear all per-table TTL bookkeeping for a canvas. Called when
     * {@link CanvasInstance.clear} drops all tables so stale entries don't
     * accumulate in the map.
     */
    clearTableBookkeeping(canvasId: string, tenantId: string): void;
    /**
     * Merge per-table `expiresAt` annotations into a `TableInfo[]` array
     * returned by the provider's `describe()`. Tables without a per-table TTL
     * are returned as-is; tables with one get an `expiresAt` field injected.
     */
    annotateDescribeResult(canvasId: string, tenantId: string, tables: TableInfo[]): TableInfo[];
    /**
     * Drop a canvas explicitly (e.g. tenant-initiated cleanup). Returns true
     * when the canvas existed and was destroyed.
     */
    drop(canvasId: string, tenantId: string, context: RequestContextLike): Promise<boolean>;
    /** Active canvas count for a tenant (used by tests and metrics surfaces). */
    countForTenant(tenantId: string): number;
    /** Total active canvases (used by tests and metrics surfaces). */
    totalActive(): number;
    /** Stop the sweeper and tear down every active canvas. Idempotent. */
    shutdown(context: RequestContextLike): Promise<void>;
    /**
     * Alias for {@link shutdown} with a synthesized sweep context. Enables
     * `await using registry = new CanvasRegistry(...)` with TypeScript's explicit
     * resource management (ES2022 `await using` declarations).
     */
    [Symbol.asyncDispose](): Promise<void>;
    /**
     * Run one sweep pass. Per-table expiry is checked first: expired tables are
     * dropped via `provider.drop()` and their bookkeeping cleared. Then the
     * existing canvas-level check runs — the two clocks are fully independent;
     * a canvas survives a table drop as long as its own window is still live.
     *
     * @internal Test/diagnostic hook — also called by the periodic sweeper timer.
     */
    sweep(): Promise<void>;
    private lookup;
    private touch;
    private touchTableRecord;
    private enforceTenantCap;
    private mintId;
    private indexByTenant;
    private destroy;
}
//# sourceMappingURL=CanvasRegistry.d.ts.map