/** * @module world/relations * * Relation resolution — both the pure cache-key/fork-key/error-message helpers * (originally extracted in B32) and the stateful `RelationResolver` collaborator * (B62) that owns the per-record relation pool cache and the * resolve-single / resolve-many / ensure-primary pipeline. * * What lives here: * - `RelationCacheKind` — the "single" vs "many" tag used as a discriminator * in the shared `resolveRelationPool` (B32-R1 / R2). * - `relationCacheKey(...)` — the cache-key string builder; the `":many"` * suffix on the many path keeps it disjoint from the single path * (B11-R3 / B11-R4 / B11-R7 — both caches are scoped per record). * - `relationForkKey(...)` — the per-relation PRNG fork-key builder * (D4 / D10 byte-identical fork-key shape; the `rel-many:` prefix on the * many path keeps its fork independent of the single path's `rel:` fork). * - `relationEmptyPoolMessage(...)` / `relationShortPoolMessage(...)` — the * B11-R6 error messages thrown when a `where`-filtered pool is empty or * undersupplied. * - `RelationResolver` (B62) — collaborator class owning `relationPools`, * constructed with the world's registry, primary-reg lookup, a * `generateAndStorePrimary` callback, and an `isStoreActive` getter. * Hosts the four entangled methods that previously lived on `WorldImpl`: * `resolveRelated`, `resolveRelatedMany`, `resolveRelationPool`, * `ensurePrimaryRecord`. Module-private collaborator — `WorldImpl` remains * the public face. */ import type { ZodTypeAny } from "zod"; import type { Prng, Registry } from "../types.js"; import type { createPrng } from "../prng.js"; import type { SchemaReg } from "./registration.js"; export type RelationCacheKind = "single" | "many"; /** * Per-record relation pool cache key. The single and many paths use disjoint * cache keys so a record reading the same relation through both APIs gets * independent snapshots. */ export declare function relationCacheKey(recordId: string, relName: string, kind: RelationCacheKind): string; /** * Per-relation PRNG fork key — derived from `recordPrng` so all fields in one * record pick the same related entity (single) or set (many). The `rel-many:` * prefix on the many path keeps its fork independent of the single path's * `rel:` fork — D4 / D10 byte-identical fork-key shape. */ export declare function relationForkKey(relName: string, kind: RelationCacheKind): string; /** * B11-R6 — error thrown when the `where`-filtered pool is empty on the single * path. Surfaced before any PRNG fork is taken so no state is consumed. */ export declare function relationEmptyPoolMessage(relName: string): string; /** * B11-R6 — error thrown when the `where`-filtered pool is undersupplied on * the many path (`items.length < count`). Surfaced before any PRNG fork is * taken so no state is consumed. */ export declare function relationShortPoolMessage(relName: string, requested: number, available: number): string; /** * Collaborator surface the `RelationResolver` needs from `WorldImpl`. The * registry and the relation pool cache it owns directly; the schema-registry * lookups (`findPrimaryReg`), the primary-record generator * (`generateAndStorePrimary`), and the live `effectiveStore` mode are exposed * as callbacks so the resolver does not need to reach back into private * `WorldImpl` state. `isStoreActive` is a function (not a boolean) because * `effectiveStore` mutates per outer `generate` call. */ export interface RelationResolverDeps { readonly registry: Registry; /** * B97-R15 — lazy accessor for the relation pool cache. The * `WorldImpl`-side helper allocates the map on first call and returns it; * a world that never resolves a relation never triggers allocation. */ getRelationPools(): Map; findPrimaryReg(schema: ZodTypeAny): SchemaReg | null; generateAndStorePrimary(schema: ZodTypeAny, reg: SchemaReg | null): unknown; isStoreActive(): boolean; } /** * B62 — owns the per-record relation pool cache and the four entangled methods * extracted from `WorldImpl` (`resolveRelated`, `resolveRelatedMany`, * `resolveRelationPool`, `ensurePrimaryRecord`). Behaviour-neutral with respect * to the previous in-engine implementation; collaborator surface narrowed to * the minimum the methods need so the class is independently unit-testable. */ export declare class RelationResolver { private readonly deps; constructor(deps: RelationResolverDeps); resolveRelated>(reg: SchemaReg, recordPrng: ReturnType, recordId: string, relName: string): T; resolveRelatedMany(reg: SchemaReg, recordPrng: ReturnType, recordId: string, relName: string, count: number): T[]; /** * Shared snapshot+fork pipeline for `ctx.related` (kind="single") and * `ctx.related.many` (kind="many"). Builds the per-record candidate pool — * applying `where` once before caching (B11-R3 / B11-R4 / B11-R7) — and * returns it alongside a per-relation PRNG fork. * * Diverges by `kind`: * - cache key suffix (`""` vs `":many"`), * - auto-provision: single calls `ensurePrimaryRecord` when the registry is * empty; many runs an explicit shortfall loop up to `count` (and skips * under `where`, since auto-provision cannot guarantee the predicate), * - PRNG fork key (`rel:` vs `rel-many:`), * - empty-pool throw threshold (`< 1` vs `< count`). * * Self-referential relations are exempt from auto-provision (would recurse) * and from the empty-pool throw (B5-R6 / B11-R6); callers handle the empty * pool themselves. */ resolveRelationPool(reg: SchemaReg, recordPrng: ReturnType, recordId: string, relName: string, kind: RelationCacheKind, count?: number): { items: unknown[]; prng: Prng; }; ensurePrimaryRecord(schema: ZodTypeAny): unknown | undefined; } //# sourceMappingURL=relations.d.ts.map