import type { ComponentId, QueryTerm } from '@ecsia/schema'; import type { Bitmask } from '../bitmask/index.js'; import type { Archetype, Signature } from '../storage/index.js'; import type { Buffers } from '../memory/index.js'; import type { CompileContext } from './compile.js'; import { LiveQuery } from './live-query.js'; import type { LiveQueryDeps, ReactivityQueryHooks } from './live-query.js'; export interface QueryEngineDeps extends LiveQueryDeps { readonly buffers: Buffers; readonly bitmask: Bitmask; readonly maxEntities: number; /** The dense archetype list (store.byId), walked once to seed a new query. */ readonly byId: Archetype[]; /** Subscribe to archetypeCreated so new archetypes join matching live queries. */ onArchetypeCreated(fn: (arch: Archetype) => void): void; /** Resolve a registered component's id (and the fixed bitmask bit count) for compilation. */ readonly compileContext: CompileContext; /** index → its CURRENT signature (resolveLocation → archetype.signature) for residual terms. */ signatureOf(index: number): Signature; /** Full handle (from a dense rows[] slot) → its entity index (low handle bits). */ indexOfHandle(handle: number): number; } export declare class QueryEngine { #private; constructor(deps: QueryEngineDeps); /** Late-bind the reactivity write-log hooks so the Changed flavor works (world wiring). */ setReactivity(hooks: ReactivityQueryHooks): void; /**: compile, dedup by canonical hash, seed on a miss. */ query(terms: readonly QueryTerm[]): LiveQuery; /** Exposed for the world facade / tests: iterate every live query (e.g. for frameReset). */ get liveQueries(): IterableIterator; /**: re-test ONE migrated entity against only the queries referencing the changed component. */ maintainEntity(index: number, componentId: ComponentId): void; /** *: a freshly spawned entity lands in the EMPTY archetype. It carries no component, so * the per-component `maintainEntity` path never fires for it — yet a constraint-less query (empty * withWords/notWords/residualWith) DOES match the empty signature and the seed already * includes such entities. To keep the incremental path symmetric with the seed (so a query created * BEFORE a plain spawn agrees with one created after), re-test the new index against every query * that matches the empty archetype and add it. */ onEntitySpawned(index: number, emptyArchetype: Archetype): void; /**: evict a despawned entity from EVERY live query (constraint-less queries included). */ dropEntity(index: number): void; /** * ROLLBACK-ONLY (@ecsia/rollback restore): rebuild every live query's `current` membership * from the RESTORED archetype tables. Iteration is archetype-driven and needs nothing here, but * `current` (query `.count` / membership) is incrementally maintained state the restore rewinds * underneath. The per-frame added/removed delta lists are frame-transient (rollback runs between * frames) and are deliberately left alone — reseeding through `addEntity` would forge deltas. */ rollbackResyncMembership(): void; /** Reset every live query's per-frame transient flavor lists (FRAME_RESET). */ frameReset(): void; } //# sourceMappingURL=engine.d.ts.map