import type { ComponentDef, ComponentId, EntityHandle, Schema } from '@ecsia/schema'; import type { AccessorWorld, ColumnSet } from '../component/index.js'; import type { Bitmask } from '../bitmask/index.js'; import { ArchetypeStore } from './store.js'; import type { RecordSurface, StorageDeps } from './store.js'; import type { Archetype } from './archetype.js'; export interface DefRegistry { idOf(def: ComponentDef): ComponentId | undefined; defOf(id: ComponentId): ComponentDef | undefined; } export interface StorageConfig { readonly buffers: StorageDeps['buffers']; readonly accessorWorld: AccessorWorld; readonly bitmask: Bitmask; readonly record: RecordSurface; readonly registry: DefRegistry; readonly maxHotArchetypes: number; readonly stride: number; readonly maxEntities: number; enqueueRemoveLog(index: number, c: ComponentId): void; /** *: does any observer subscribe to `c`'s removal? When true for any held component, despawn * defers the dying row's column reclaim (swap-pop) so an onRemove handler can read the last value. * Optional so a query-less harness can construct storage without reactivity. */ hasRemoveObserver?(c: ComponentId): boolean; /** Shape-log hook: structural entry at the commit point. Wired by the world to reactivity. */ trackShape?(index: number, c: ComponentId, kind: number): void; /** Single-entity incremental query maintenance; wired by the world to the engine. */ maintainEntity(index: number, c: ComponentId): void; /** * Spawn-time maintenance: a component-less entity lands in EMPTY and never drives * `maintainEntity`, so constraint-less queries are told about it here (keeps the incremental path * symmetric with the despawn path). No-op for component-constrained queries. */ onEntitySpawned(index: number): void; /** Despawn eviction: remove the index from EVERY live query unconditionally. */ dropEntity(index: number): void; tick(): number; handleIndex(handle: EntityHandle): number; /** A held deferred-dead row moved (allocRow eviction) — update the observer-window location stash. */ relocateHeld?(handle: number, archId: number, newRow: number): void; } export declare class Storage { #private; readonly archetypes: ArchetypeStore; constructor(cfg: StorageConfig); /** Release every archetype's held deferred-dead rows (flushPending, after the observer drain). */ releaseHeldRows(): void; /** Subscribe to archetypeCreated; forwarded from the ArchetypeStore. */ onArchetypeCreated(fn: (arch: Archetype) => void): void; /** Entity indices currently resident in cold archetype `archetypeId` (O(rows in that archetype)). */ coldResidentsOf(archetypeId: number): Iterable; /** The per-TYPE cold ColumnSet for `componentId` (cold blocks are keyed by component, not archetype). */ coldColumnSet(componentId: ComponentId): ColumnSet | undefined; /** The cold-block row holding `componentId`'s fields for entity `index`, or -1 if absent. */ coldRowOf(index: number, componentId: ComponentId): number; onSpawn(handle: EntityHandle): void; onDespawn(handle: EntityHandle): void; add(handle: EntityHandle, def: ComponentDef): void; remove(handle: EntityHandle, def: ComponentDef): void; spawnWith(handle: EntityHandle, defs: readonly ComponentDef[]): void; /** Atomic multi-id add — ONE migration to a single target signature (relations path). */ addMany(handle: EntityHandle, defs: readonly ComponentDef[]): void; /** Atomic multi-id remove — symmetric to addMany. */ removeMany(handle: EntityHandle, defs: readonly ComponentDef[]): void; warm(defs: readonly ComponentDef[]): void; /** * (has() never reads the * bitmask for a dead handle); this asserts world.phase === 'serial' inside bitmaskHas. */ has(handle: EntityHandle, def: ComponentDef): boolean; resolveRead(handle: EntityHandle, archetypeId: number, row: number, def: unknown, lenient?: boolean): unknown; resolveWrite(handle: EntityHandle, archetypeId: number, row: number, def: unknown, lenient?: boolean): unknown; } //# sourceMappingURL=storage.d.ts.map