/**
 * @fileoverview Per-canvas handle returned by {@link DataCanvas.acquire}. Holds
 * `(canvasId, tenantId)` and routes each operation through the registry's
 * TTL-touch + tenant validation gate before delegating to the provider.
 * @module src/services/canvas/core/CanvasInstance
 */
/** Handle bound to a single canvas. Returned from {@link DataCanvas.acquire}. */
export class CanvasInstance {
    canvasId;
    tenantId;
    registry;
    provider;
    context;
    /** True when {@link DataCanvas.acquire} created this canvas during the current call. */
    isNew;
    /** ISO 8601 expiry after the most recent operation extended the sliding TTL. */
    expiresAt;
    constructor(
    /** Opaque canvas token. Surface this to callers; share it across agents. */
    canvasId, 
    /** Tenant the canvas is bound to. Resolved by the registry from the request context. */
    tenantId, isNew, expiresAt, registry, provider, context) {
        this.canvasId = canvasId;
        this.tenantId = tenantId;
        this.registry = registry;
        this.provider = provider;
        this.context = context;
        this.isNew = isNew;
        this.expiresAt = expiresAt;
    }
    /** Register a table on the canvas. */
    async registerTable(name, rows, options) {
        this.expiresAt = this.registry.touchWithTable(this.canvasId, this.tenantId, name);
        const result = await this.provider.registerTable(this.canvasId, name, rows, this.context, options);
        if (options?.ttlMs !== undefined) {
            this.registry.registerTableTtl(this.canvasId, this.tenantId, name, options.ttlMs);
        }
        else {
            // The provider replaces an existing table — the new registration's options
            // fully describe its lifecycle, so a stale per-table TTL must not survive.
            this.registry.dropTableBookkeeping(this.canvasId, this.tenantId, name);
        }
        return result;
    }
    /**
     * Register a SQL view on the canvas. `selectSql` runs through the same
     * read-only gate `query()` uses; queries against the view inherit normal
     * gate enforcement at execution time.
     */
    async registerView(name, selectSql, options) {
        this.expiresAt = this.registry.touchOrThrow(this.canvasId, this.tenantId);
        return await this.provider.registerView(this.canvasId, name, selectSql, this.context, options);
    }
    /**
     * Copy a table from another canvas the caller controls. The source canvas
     * must belong to the caller's tenant — the registry validates that before
     * the provider sees either id. Defaults `asName` to the source name.
     */
    async importFrom(sourceCanvasId, sourceTableName, options) {
        this.expiresAt = this.registry.touchOrThrow(this.canvasId, this.tenantId);
        this.registry.touchWithTable(sourceCanvasId, this.tenantId, sourceTableName);
        const asName = options?.asName ?? sourceTableName;
        const result = await this.provider.importFrom(this.canvasId, sourceCanvasId, sourceTableName, asName, this.context, options);
        // The provider replaces an existing destination table; the imported copy
        // carries no per-table TTL, so clear any stale entry under that name.
        this.registry.dropTableBookkeeping(this.canvasId, this.tenantId, asName);
        return result;
    }
    /** Run a SQL query against the canvas. */
    async query(sql, options) {
        this.expiresAt = this.registry.touchWithSqlTables(this.canvasId, this.tenantId, options?.registerAs, sql);
        const result = await this.provider.query(this.canvasId, sql, this.context, options);
        if (options?.registerAs !== undefined && options.ttlMs !== undefined) {
            this.registry.registerTableTtl(this.canvasId, this.tenantId, options.registerAs, options.ttlMs);
        }
        return result;
    }
    /** Export a canvas table to a path or stream target. */
    async export(tableName, target, options) {
        this.expiresAt = this.registry.touchWithTable(this.canvasId, this.tenantId, tableName);
        return await this.provider.export(this.canvasId, tableName, target, this.context, options);
    }
    /** Describe one or all canvas tables. Per-table `expiresAt` is injected for tables with a TTL. */
    async describe(options) {
        this.expiresAt = this.registry.touchOrThrow(this.canvasId, this.tenantId);
        const result = await this.provider.describe(this.canvasId, this.context, options);
        return this.registry.annotateDescribeResult(this.canvasId, this.tenantId, result);
    }
    /** Drop a single canvas table. Returns `true` when found and removed. */
    async drop(name) {
        this.expiresAt = this.registry.touchOrThrow(this.canvasId, this.tenantId);
        const result = await this.provider.drop(this.canvasId, name, this.context);
        if (result) {
            this.registry.dropTableBookkeeping(this.canvasId, this.tenantId, name);
        }
        return result;
    }
    /** Drop every table on the canvas. Returns the number dropped. */
    async clear() {
        this.expiresAt = this.registry.touchOrThrow(this.canvasId, this.tenantId);
        const count = await this.provider.clear(this.canvasId, this.context);
        this.registry.clearTableBookkeeping(this.canvasId, this.tenantId);
        return count;
    }
}
//# sourceMappingURL=CanvasInstance.js.map