/**
 * Trellis Server — Realtime Subscription Engine
 *
 * InstantDB-style reactive queries over WebSocket.
 *
 * Clients subscribe to an EQL-S query string. When any op lands that touches
 * an entity type in that query's result set, the server re-runs the query
 * and pushes the full updated result (plus a diff) to subscribed clients.
 *
 * Protocol (JSON over WebSocket):
 *
 *   Client → Server:
 *     { type: "subscribe", id: "sub_1", query: "find Post where ...",
 *       entityType?: "Post", resolve?: { author: true }, tenantId?: "t1" }
 *     { type: "unsubscribe", id: "sub_1" }
 *     { type: "ping" }
 *
 *   Server → Client:
 *     { type: "subscribed",  id: "sub_1" }
 *     { type: "data",        id: "sub_1", result: [...], diff: { added, updated, removed },
 *       resolved?: true }
 *     { type: "error",       id: "sub_1", message: "..." }
 *     { type: "pong" }
 *
 * @module trellis/server
 */
import type { ResolveSpec } from '../schema/resolve.js';
import type { TenantPool } from './tenancy.js';
import type { UsageMeter } from './usage-meter.js';
import type { AuthContext } from './auth.js';
import type { PermissionRegistry } from './permissions.js';
export interface Subscription {
    id: string;
    query: string;
    tenantId: string | null;
    auth: AuthContext;
    lastResult: Record<string, unknown>[];
    /** Entity type name — enables server-side `resolve` expansion. */
    entityType?: string;
    resolve?: ResolveSpec;
}
export interface WsClient {
    id: string;
    ws: {
        send(data: string): void;
        readyState: number;
    };
    subscriptions: Map<string, Subscription>;
    auth: AuthContext;
    tenantId: string | null;
}
export type RealtimeMessage = {
    type: 'subscribe';
    id: string;
    query: string;
    tenantId?: string;
    entityType?: string;
    resolve?: ResolveSpec;
} | {
    type: 'unsubscribe';
    id: string;
} | {
    type: 'ping';
};
/**
 * Manages WebSocket clients and their query subscriptions.
 * Call `notify(tenantId)` after any mutation to fan out updates.
 */
export declare class SubscriptionManager {
    private clients;
    private pool;
    private permissions;
    private meter;
    constructor(pool: TenantPool, permissions?: PermissionRegistry | null, meter?: UsageMeter | null);
    addClient(clientId: string, ws: WsClient['ws'], auth: AuthContext, tenantId: string | null): void;
    removeClient(clientId: string): void;
    handleMessage(clientId: string, raw: string): Promise<void>;
    /**
     * Re-evaluate all subscriptions for a given tenant and push diffs.
     * Called after every write op lands.
     */
    notify(tenantId: string | null): Promise<void>;
    get clientCount(): number;
    private _handleSubscribe;
    private _pushUpdate;
    private _recordGraphIo;
    private _send;
}
//# sourceMappingURL=realtime.d.ts.map