doxum 0.1.32 → 0.1.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform-RghG_Qxs.js","names":[],"sources":["../core/src/profile.ts","../core/src/projection/definition.ts","../core/src/projection/collection/view.ts","../core/src/projection/dependency.ts","../core/src/projection/keyed/invalidation.ts","../core/src/projection/contract.ts","../core/src/projection/graph/scheduler.ts","../core/src/value/array.ts","../core/src/projection/keyed/relation.ts","../core/src/projection/keyed/dependency.ts","../core/src/projection/collection/change.ts","../core/src/projection/keyed/transform.ts"],"sourcesContent":["const counters = () => ({\n projection: {\n sourceEvents: 0,\n scheduledNodes: 0,\n processedNodes: 0,\n touchedKeys: 0,\n changedKeys: 0,\n publishedNodes: 0,\n flushes: 0,\n },\n copy: { structures: 0, treeNodes: 0, shallowRecordItems: 0 },\n equality: { calls: 0, containers: 0 },\n recorder: {\n facts: 0,\n groups: 0,\n transitions: 0,\n absorbed: 0,\n orderSnapshots: 0,\n orderCaptures: 0,\n orderItems: 0,\n publishedOrderItems: 0,\n treeNodes: 0,\n sealed: 0,\n indexedGroups: 0,\n },\n access: { scopes: 0, proxies: 0, snapshots: 0, addresses: 0, resolutions: 0 },\n address: {\n schemaSteps: 0,\n documentSteps: 0,\n prefixComparisons: 0,\n segmentsCompared: 0,\n listIndexes: 0,\n listItems: 0,\n },\n impact: { affectsChecks: 0, indexes: 0 },\n dependency: { comparisons: 0, segmentsCompared: 0 },\n collectionIndex: { nodes: 0, builds: 0, builtItems: 0 },\n collectionView: { mappedItems: 0, idsScanned: 0, arraysCopied: 0 },\n materialized: { updated: 0, rebuilt: 0, notifications: 0 },\n});\ntype Counters = ReturnType<typeof counters>;\ntype DeepReadonly<T> = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K] };\nexport type ProfileSnapshot = DeepReadonly<Counters>;\nlet active: Counters | undefined;\nconst freeze = <T extends object>(value: T): DeepReadonly<T> => {\n Object.values(value).forEach(child => {\n if (child && typeof child === 'object') freeze(child);\n });\n return Object.freeze(value) as DeepReadonly<T>;\n};\nexport const profile = {\n projection: (key: keyof Counters['projection'], amount = 1) => {\n if (active) active.projection[key] += amount;\n },\n recorder: (key: keyof Counters['recorder'], amount = 1) => {\n if (active) active.recorder[key] += amount;\n },\n access: (key: keyof Counters['access']) => {\n if (active) active.access[key]++;\n },\n copy: {\n structure: () => {\n if (active) active.copy.structures++;\n },\n treeNode: () => {\n if (active) active.copy.treeNodes++;\n },\n shallowRecord: (items: number) => {\n if (active) active.copy.shallowRecordItems += items;\n },\n },\n equality: {\n call: () => {\n if (active) active.equality.calls++;\n },\n container: () => {\n if (active) active.equality.containers++;\n },\n },\n address: {\n listIndex: (items: number) => {\n if (active) {\n active.address.listIndexes++;\n active.address.listItems += items;\n }\n },\n schemaStep: () => {\n if (active) active.address.schemaSteps++;\n },\n documentStep: () => {\n if (active) active.address.documentSteps++;\n },\n prefixComparison: () => {\n if (active) active.address.prefixComparisons++;\n },\n segmentCompared: () => {\n if (active) active.address.segmentsCompared++;\n },\n },\n impact: {\n index: () => {\n if (active) active.impact.indexes++;\n },\n affects: () => {\n if (active) active.impact.affectsChecks++;\n },\n },\n dependency: {\n comparison: () => {\n if (active) active.dependency.comparisons++;\n },\n segmentCompared: () => {\n if (active) active.dependency.segmentsCompared++;\n },\n },\n collectionIndex: {\n node: () => {\n if (active) active.collectionIndex.nodes++;\n },\n build: (items: number) => {\n if (active) {\n active.collectionIndex.builds++;\n active.collectionIndex.builtItems += items;\n }\n },\n },\n collectionView: {\n mapped: () => {\n if (active) active.collectionView.mappedItems++;\n },\n idsScanned: (amount = 1) => {\n if (active) active.collectionView.idsScanned += amount;\n },\n arrayCopied: () => {\n if (active) active.collectionView.arraysCopied++;\n },\n },\n materialized: {\n updated: () => {\n if (active) active.materialized.updated++;\n },\n rebuilt: () => {\n if (active) active.materialized.rebuilt++;\n },\n notification: () => {\n if (active) active.materialized.notifications++;\n },\n },\n};\nexport type ProfileSession = { snapshot(): ProfileSnapshot; stop(): ProfileSnapshot };\nexport const startProfile = (): ProfileSession => {\n if (active) throw new Error('A document profile session is already active.');\n const value = counters();\n active = value;\n const snapshot = () => freeze(structuredClone(value));\n return {\n snapshot,\n stop: () => {\n if (active === value) active = undefined;\n return snapshot();\n },\n };\n};\nexport const measureProfile = <T>(run: () => T): { value: T; profile: ProfileSnapshot } => {\n const session = startProfile();\n try {\n return { value: run(), profile: session.stop() };\n } finally {\n session.stop();\n }\n};\n","import type { ReadonlyDocument } from '@/runtime/contract';\nimport type { ObjectSchema } from '@/schema/model';\nimport type { CollectionSelector, ValueSelector } from '@/schema/path';\nimport type {\n CollectionChange,\n CollectionDraft,\n CollectionRead,\n ExternalCollectionSource,\n ExternalValueSource,\n SourceContext,\n} from './contract';\nimport type { Readable } from '@/readable';\n\ndeclare const projectionDefinition: unique symbol;\ndeclare const keyedProjection: unique symbol;\ndeclare const writableInput: unique symbol;\ndeclare const writableCollectionInput: unique symbol;\n\n/** A lazy output reference with no materialized Runtime state. */\nexport type Projection<T> = {\n readonly [projectionDefinition]: T;\n};\n\n/** A projection whose output is a keyed collection with per-key change semantics. */\nexport type KeyedProjection<K extends string, V> = Projection<ReadonlyMap<K, V>> & {\n readonly [keyedProjection]: { readonly key: K; readonly value: V };\n};\n\n/** A writable source projection. */\nexport type Input<T> = Projection<T> & { readonly [writableInput]: true };\n\n/** A writable keyed collection source projection. */\nexport type CollectionInput<K extends string, V> = KeyedProjection<K, V> & {\n readonly [writableCollectionInput]: { readonly key: K; readonly value: V };\n};\n\nexport type CollectionInputDraft<K extends string, V> = {\n get(key: K): V | undefined;\n has(key: K): boolean;\n set(key: K, value: V): void;\n remove(key: K): void;\n};\n\nexport type ProjectionChange<P> =\n P extends KeyedProjection<infer K, infer V> ? CollectionChange<K, V> : undefined;\n\nexport type Equality = (a: unknown, b: unknown) => boolean;\n\nexport type OutputDefinition =\n | {\n readonly kind: 'value';\n readonly equality: Equality;\n readonly path?: readonly string[];\n }\n | {\n readonly kind: 'collection';\n readonly equality: Equality;\n readonly path?: readonly string[];\n };\n\nexport type ValueOutputEvaluation = {\n readonly kind: 'value';\n readonly previous: unknown;\n readonly next: () => unknown;\n readonly output: { set(value: unknown): void };\n};\n\nexport type CollectionOutputEvaluation = {\n readonly kind: 'collection';\n readonly previous: CollectionRead<string, unknown>;\n readonly next: CollectionRead<string, unknown>;\n readonly output: CollectionDraft<string, unknown>;\n};\n\nexport type OutputEvaluation = ValueOutputEvaluation | CollectionOutputEvaluation;\n\nexport type ProcessorEvaluation = {\n readonly reset: boolean;\n readonly cause: unknown;\n readonly sources: readonly SourceContext[];\n readonly outputs: readonly OutputEvaluation[];\n};\n\nexport type ProcessorInstance = {\n evaluate(input: ProcessorEvaluation): void;\n release?(): void;\n};\n\nexport type SourceAdapter =\n | {\n readonly kind: 'value-input';\n readonly initial: unknown;\n readonly equality: Equality;\n }\n | {\n readonly kind: 'collection-input';\n readonly initial: ReadonlyMap<string, unknown>;\n readonly equality: Equality;\n }\n | {\n readonly kind: 'readable';\n readonly readable: Readable<unknown>;\n readonly equality: Equality;\n }\n | {\n readonly kind: 'external-value';\n readonly source: ExternalValueSource<unknown>;\n readonly equality: Equality;\n }\n | {\n readonly kind: 'external-collection';\n readonly source: ExternalCollectionSource<string, unknown>;\n }\n | {\n readonly kind: 'document';\n readonly document: ReadonlyDocument<ObjectSchema<object>>;\n readonly selector: ValueSelector | CollectionSelector;\n };\n\nexport type SourceDefinition = {\n readonly kind: 'source';\n readonly source: SourceAdapter;\n readonly output: OutputDefinition;\n owner?: object;\n materialized?: true;\n};\n\nexport type ProcessorDefinition = {\n readonly kind: 'processor';\n readonly dependencies: readonly Projection<unknown>[];\n readonly outputs: readonly OutputDefinition[];\n readonly create: () => ProcessorInstance;\n readonly name?: string;\n owner?: object;\n materialized?: true;\n};\n\nexport type ProducerDefinition = SourceDefinition | ProcessorDefinition;\n\nexport type ProjectionRef = {\n readonly producer: ProducerDefinition;\n readonly output: number;\n};\n\nconst projections = new WeakMap<object, ProjectionRef>();\n\nconst defineRef = <T>(producer: ProducerDefinition, output: number): Projection<T> => {\n const handle = Object.freeze({}) as Projection<T>;\n projections.set(handle, Object.freeze({ producer, output }));\n return handle;\n};\n\nexport const projectionRef = (projection: Projection<unknown>): ProjectionRef => {\n const ref = projections.get(projection);\n if (!ref) throw new TypeError('Unknown projection definition.');\n return ref;\n};\n\nexport const producerOf = (projection: Projection<unknown>): ProducerDefinition =>\n projectionRef(projection).producer;\n\n/** Resolves the immutable output description owned by a projection definition. */\nexport const outputDefinitionOf = (projection: Projection<unknown>): OutputDefinition => {\n const ref = projectionRef(projection);\n const producer = ref.producer;\n const output = producer.kind === 'source' ? producer.output : producer.outputs[ref.output];\n if (!output) throw new TypeError('Projection output does not exist.');\n return output;\n};\n\nexport const isProjection = (value: unknown): value is Projection<unknown> =>\n value !== null && typeof value === 'object' && projections.has(value);\n\nexport const ownProjections = (\n projections: readonly Projection<unknown>[],\n owner: object\n): void => {\n const producers = new Set(projections.map(producerOf));\n for (const producer of producers) {\n if (producer.owner !== undefined && producer.owner !== owner)\n throw new TypeError('Projection producer already belongs to another scope.');\n if (producer.owner === undefined && producer.materialized)\n throw new TypeError('A materialized root projection cannot become scope-owned.');\n if (producer.kind !== 'processor') continue;\n for (const dependency of producer.dependencies) {\n const dependencyOwner = producerOf(dependency).owner;\n if (dependencyOwner !== undefined && dependencyOwner !== owner)\n throw new TypeError('A scope cannot depend on another scope.');\n }\n }\n for (const producer of producers) producer.owner = owner;\n};\n\nconst freezeOutput = (output: OutputDefinition): OutputDefinition =>\n Object.freeze({\n kind: output.kind,\n equality: output.equality,\n ...(output.path ? { path: Object.freeze([...output.path]) } : {}),\n });\n\nexport const defineProcessor = (definition: {\n readonly dependencies: readonly Projection<unknown>[];\n readonly outputs: readonly OutputDefinition[];\n readonly create: () => ProcessorInstance;\n readonly name?: string;\n}): readonly Projection<unknown>[] => {\n if (!Array.isArray(definition.dependencies))\n throw new TypeError('Projection dependencies must be an array.');\n definition.dependencies.forEach(projectionRef);\n if (!definition.outputs.length) throw new TypeError('Projection processor requires an output.');\n const producer: ProcessorDefinition = {\n kind: 'processor',\n dependencies: Object.freeze([...definition.dependencies]),\n outputs: Object.freeze(definition.outputs.map(freezeOutput)),\n create: definition.create,\n ...(definition.name ? { name: definition.name } : {}),\n };\n return Object.freeze(producer.outputs.map((_, output) => defineRef<unknown>(producer, output)));\n};\n\nexport const defineSource = <T>(source: SourceAdapter, output: OutputDefinition): Projection<T> => {\n const producer: SourceDefinition = {\n kind: 'source',\n source,\n output: freezeOutput(output),\n };\n return defineRef<T>(producer, 0);\n};\n","import type { CollectionRead } from '@/projection/contract';\n\nexport const mapRead = <K extends string, V>(value: ReadonlyMap<K, V>): CollectionRead<K, V> => {\n let ids: readonly K[] | undefined;\n return {\n get: key => value.get(key),\n has: key => value.has(key),\n ids: () => (ids ??= Object.freeze([...value.keys()])),\n };\n};\n\n/** Immutable map-like view over a CollectionRead. */\nexport const collectionView = <K extends string, V>(\n read: CollectionRead<K, V>,\n knownIds?: readonly K[]\n): ReadonlyMap<K, V> => {\n const ids = knownIds ?? read.ids();\n const iterate = <T>(select: (key: K) => T): IterableIterator<T> => {\n read.ids();\n let index = 0;\n return {\n next() {\n read.ids();\n if (index === ids.length) return { done: true, value: undefined };\n return { done: false, value: select(ids[index++]) };\n },\n [Symbol.iterator]() {\n return this;\n },\n };\n };\n const entries = (): IterableIterator<[K, V]> => iterate(key => [key, read.get(key) as V]);\n const values = (): IterableIterator<V> => iterate(key => read.get(key) as V);\n const view: ReadonlyMap<K, V> = {\n get: key => read.get(key),\n has: key => read.has(key),\n get size() {\n read.ids();\n return ids.length;\n },\n keys: () => iterate(key => key),\n values,\n entries,\n forEach: (callback, thisArg) => {\n read.ids();\n for (const key of ids) callback.call(thisArg, read.get(key) as V, key, view);\n },\n [Symbol.iterator]: entries,\n };\n return Object.freeze(view);\n};\n\n/** Eager durable view used when a processor result may retain its dependency value. */\nexport const snapshotCollectionView = <K extends string, V>(\n read: CollectionRead<K, V>\n): ReadonlyMap<K, V> => {\n const ids = read.ids();\n const values = new Map<K, V>();\n for (const key of ids) values.set(key, read.get(key) as V);\n return collectionView(mapRead(values), ids);\n};\n","import { isPlainObject } from '@/value/record';\nimport { snapshotCollectionView } from '@/projection/collection/view';\nimport type { SourceContext } from './contract';\nimport { isProjection, projectionRef, type Projection } from './definition';\n\nexport type CompiledProjectionDependencies = {\n readonly names: readonly string[];\n readonly projections: readonly Projection<unknown>[];\n};\n\nexport type NamedDependencyEntry = {\n readonly name: string;\n readonly value: unknown;\n};\n\n/** Owns validation of the shared named dependency object shape. */\nexport const readNamedDependencyEntries = (\n dependencies: unknown,\n label: string\n): readonly NamedDependencyEntry[] => {\n if (!isPlainObject(dependencies) || isProjection(dependencies))\n throw new TypeError(`${label} dependencies must be a plain object.`);\n const entries: NamedDependencyEntry[] = [];\n for (const name of Reflect.ownKeys(dependencies)) {\n if (typeof name !== 'string') throw new TypeError(`${label} dependency names must be strings.`);\n const descriptor = Object.getOwnPropertyDescriptor(dependencies, name);\n if (!descriptor?.enumerable || !('value' in descriptor))\n throw new TypeError(`${label} dependencies must be enumerable data properties.`);\n entries.push(Object.freeze({ name, value: descriptor.value }));\n }\n return Object.freeze(entries);\n};\n\n/** Creates the durable dependency value exposed to pure derive callbacks. */\nexport const snapshotDependencyValue = (source: SourceContext): unknown =>\n source.kind === 'value' ? source.value : snapshotCollectionView(source.read);\n\n/** Compiles the shared named Projection dependency declaration contract. */\nexport const compileProjectionDependencies = (\n dependencies: unknown,\n label: string\n): CompiledProjectionDependencies => {\n const names: string[] = [];\n const projections: Projection<unknown>[] = [];\n for (const { name, value } of readNamedDependencyEntries(dependencies, label)) {\n const projection = value as Projection<unknown>;\n projectionRef(projection);\n names.push(name);\n projections.push(projection);\n }\n return Object.freeze({\n names: Object.freeze(names),\n projections: Object.freeze(projections),\n });\n};\n","import type { CollectionContext, SourceContext } from '@/projection/contract';\nimport type { KeyedDependencyRuntime } from './dependency';\n\ntype KeyedInvalidation = {\n readonly rebuild: boolean;\n readonly keys: Iterable<string>;\n readonly removed: readonly { readonly key: string }[];\n readonly structural: boolean;\n};\n\n/** Shared driver/dependency invalidation policy; owns no revisions or member cache. */\nexport const collectKeyedInvalidation = (\n driver: CollectionContext<string, unknown>,\n sources: readonly SourceContext[],\n dependencies: KeyedDependencyRuntime,\n reset: boolean\n): KeyedInvalidation => {\n const changed = dependencies.driverChanged(driver);\n const change = changed ? driver.change : undefined;\n if (reset || (changed && (!change || change.kind === 'reset')))\n return { rebuild: true, keys: driver.read.ids(), removed: [], structural: true };\n\n const dirty = new Set<string>();\n let removed: readonly { readonly key: string }[] = [];\n let structural = false;\n if (change?.kind === 'incremental') {\n removed = change.removed;\n for (const entry of change.added) dirty.add(entry.key);\n for (const entry of change.updated) dirty.add(entry.key);\n structural = Boolean(change.added.length || change.removed.length || change.order);\n }\n const all = dependencies.collectInvalidated(sources, dirty);\n if (!all) for (const key of dirty) if (!driver.read.has(key)) dirty.delete(key);\n return { rebuild: false, keys: all ? driver.read.ids() : dirty, removed, structural };\n};\n","import type { CollectionImpact } from '@/impact';\nimport type { Unsubscribe } from '@/runtime/contract';\n\n/** Scheduler-owned metadata for one Runtime batch. */\nexport type BatchContext = {\n readonly id: number;\n readonly cause?: unknown;\n};\n\n/** The one processor-facing collection transition protocol. */\nexport type CollectionChange<K extends string, V> =\n | { readonly kind: 'reset' }\n | {\n readonly kind: 'incremental';\n readonly added: readonly { readonly key: K; readonly after: V }[];\n readonly updated: readonly {\n readonly key: K;\n readonly before: V;\n readonly after: V;\n }[];\n readonly removed: readonly { readonly key: K; readonly before: V }[];\n readonly order?: {\n readonly before: readonly K[];\n readonly after: readonly K[];\n };\n };\n\nexport type ValueContext<T> = {\n readonly kind: 'value';\n readonly value: T;\n readonly revision: number;\n readonly reset: boolean;\n readonly cause?: unknown;\n};\n\nexport type CollectionRead<K extends string, V> = {\n get(key: K): V | undefined;\n has(key: K): boolean;\n ids(): readonly K[];\n};\n\nexport type ExternalCollectionRead<K extends string, V> = {\n readonly get: (key: K) => V | undefined;\n readonly has: (key: K) => boolean;\n readonly ids: () => readonly K[];\n};\n\nexport type CollectionContext<K extends string, V> = {\n readonly kind: 'collection';\n readonly read: CollectionRead<K, V>;\n readonly change: CollectionChange<K, V> | undefined;\n readonly revision: number;\n readonly reset: boolean;\n readonly cause?: unknown;\n};\n\nexport type SourceContext = ValueContext<unknown> | CollectionContext<string, unknown>;\n\nexport type ExternalValueSource<T> = {\n readonly kind: 'value';\n current(): T;\n revision(): number;\n subscribe(listener: (event: ExternalValueEvent<T>) => void): Unsubscribe;\n};\n\nexport type ExternalCollectionSource<K extends string, V> = {\n readonly kind: 'collection';\n current(): ExternalCollectionRead<K, V>;\n revision(): number;\n subscribe(listener: (event: ExternalCollectionEvent<K, V>) => void): Unsubscribe;\n};\n\nexport type ExternalValueEvent<T> = {\n readonly value: T;\n readonly revision: number;\n readonly reset?: boolean;\n readonly cause?: unknown;\n};\n\nexport type ExternalCollectionEvent<K extends string, V> = {\n /** Stable read from the source before this event or external batch. */\n readonly previous: ExternalCollectionRead<K, V>;\n readonly revision: number;\n /** Optional document-style hint; the adapter resolves the canonical change. */\n readonly impact?: CollectionImpact<K>;\n readonly cause?: unknown;\n};\n\nexport type CollectionDraft<K extends string, V> = {\n set(key: K, value: V): void;\n remove(key: K): void;\n order(ids: readonly K[]): void;\n};\n\nexport class ProjectionError extends Error {\n readonly cause: unknown;\n\n constructor(\n readonly phase: 'processor' | 'listener' | 'source' | 'blocked',\n cause: unknown\n ) {\n super(`Projection ${phase} failed.`, { cause });\n this.name = 'ProjectionError';\n this.cause = cause;\n }\n}\n\nexport class ProjectionDisposedError extends Error {\n constructor() {\n super('Projection has been disposed.');\n this.name = 'ProjectionDisposedError';\n }\n}\n","import { profile } from '@/profile';\nimport type { ObserverError, Unsubscribe } from '@/runtime/contract';\nimport type { BatchContext, CollectionChange, SourceContext } from '@/projection/contract';\nimport { ProjectionDisposedError, ProjectionError } from '@/projection/contract';\n\ntype BatchOptions = { readonly cause?: unknown };\n\ntype ProducerBase = {\n readonly name: string;\n readonly outputs: readonly OutputRecord[];\n fault: ProjectionError | undefined;\n disposed: boolean;\n clear(): void;\n release(): void;\n};\n\nexport type OutputListener = (change?: CollectionChange<string, unknown>) => void;\n\nexport type OutputRecord = {\n readonly kind: 'value' | 'collection';\n readonly owner: ProducerRecord;\n context(active: () => boolean, consumer?: ProcessorRecord): SourceContext;\n acknowledge(consumer: ProcessorRecord): void;\n pending(consumer: ProcessorRecord): boolean;\n current(): unknown;\n revision(): number;\n reset(consumer?: ProcessorRecord): boolean;\n subscribe(listener: OutputListener): Unsubscribe;\n observe(listener: OutputListener): Unsubscribe;\n emit(\n call: (listener: OutputListener, change?: CollectionChange<string, unknown>) => void,\n force?: boolean\n ): void;\n finish(): void;\n hasConsumers(): boolean;\n forEachConsumer(run: (consumer: ProcessorRecord) => void): void;\n attachConsumer(consumer: ProcessorRecord): void;\n detachConsumer(consumer: ProcessorRecord): void;\n clear(): void;\n release(): void;\n};\n\nexport type SourceBoundaryRecord = ProducerBase & {\n readonly kind: 'source';\n readonly outputs: readonly [OutputRecord];\n pendingCause(): unknown;\n recovering(): boolean;\n prepare(cause: unknown): { readonly changed: boolean; readonly force: boolean };\n publish(): void;\n};\n\nexport type ProcessorRecord = ProducerBase & {\n readonly kind: 'processor';\n readonly dependencies: readonly OutputRecord[];\n evaluate(reset: boolean, cause: unknown, recreate?: boolean): readonly OutputRecord[];\n publish(): void;\n};\n\nexport type ProducerRecord = SourceBoundaryRecord | ProcessorRecord;\n\nexport const createScheduler = (onError: (error: ProjectionError) => void) => {\n let disposed = false;\n let depth = 0;\n let batchSequence = 0;\n let activeBatch: BatchContext | undefined;\n let phase: 'idle' | 'input' | 'compute' | 'notify' = 'idle';\n let sequence = 0;\n const sources = new Set<SourceBoundaryRecord>();\n const processors = new Set<ProcessorRecord>();\n const pendingSources = new Set<SourceBoundaryRecord>();\n const dirty = new Set<ProducerRecord>();\n const queued = new Set<ProcessorRecord>();\n const completed = new Set<ProcessorRecord>();\n const emissions = new Set<OutputRecord>();\n const forced = new Set<OutputRecord>();\n const errors: ProjectionError[] = [];\n let reportingFailures: unknown[] = [];\n const guards = new Set<(locked: boolean) => void>();\n\n const assertActive = () => {\n if (disposed) throw new ProjectionDisposedError();\n };\n const assertIdle = () => {\n assertActive();\n if (phase !== 'idle')\n throw new Error(\n 'Projection cannot be re-entered during input callbacks, processing or notification.'\n );\n };\n const lock = (value: boolean) => guards.forEach(guard => guard(value));\n\n const markDirty = (producer: ProducerRecord): void => {\n const pending = [producer];\n for (let index = 0; index < pending.length; index++) {\n const current = pending[index];\n if (current.disposed || dirty.has(current)) continue;\n dirty.add(current);\n for (const output of current.outputs)\n output.forEachConsumer(consumer => pending.push(consumer));\n }\n };\n const enqueue = (processor: ProcessorRecord): void => {\n if (processor.disposed || queued.has(processor)) return;\n queued.add(processor);\n profile.projection('scheduledNodes');\n };\n\n const errorFor = (\n producer: ProducerRecord,\n cause: unknown,\n kind: ProjectionError['phase'] = producer.kind === 'source' ? 'source' : 'processor'\n ) => new ProjectionError(kind, cause);\n\n const capture = (source: SourceBoundaryRecord) => {\n if (disposed) return;\n if (phase !== 'idle') {\n source.fault = errorFor(\n source,\n new Error('Source changed while projection was running.'),\n 'source'\n );\n errors.push(source.fault);\n throw source.fault;\n }\n pendingSources.add(source);\n markDirty(source);\n profile.projection('sourceEvents');\n if (source.fault) errors.push(source.fault);\n };\n\n const settleCause = (): unknown => {\n if (activeBatch?.cause !== undefined) return activeBatch.cause;\n for (const source of pendingSources) {\n const cause = source.pendingCause();\n if (cause !== undefined) return cause;\n }\n return undefined;\n };\n\n const propagate = (output: OutputRecord, force = false): void => {\n emissions.add(output);\n if (force) forced.add(output);\n output.forEachConsumer(enqueue);\n };\n\n const advanceSource = (source: SourceBoundaryRecord, cause: unknown): void => {\n pendingSources.delete(source);\n const wasFaulted = source.fault !== undefined;\n let changed = false;\n let force = false;\n if (!source.fault || source.recovering()) {\n try {\n // A fresh attempt may read the last valid source snapshot internally.\n // Public re-entry remains forbidden until this compute phase completes.\n source.fault = undefined;\n const prepared = source.prepare(cause);\n changed = prepared.changed;\n force = prepared.force;\n source.fault = undefined;\n } catch (failure) {\n source.fault = errorFor(source, failure, 'source');\n errors.push(source.fault);\n }\n }\n if (changed || force) source.publish();\n if (source.fault || changed || force || wasFaulted) propagate(source.outputs[0], force);\n source.clear();\n };\n\n const advanceProcessor = (processor: ProcessorRecord, cause: unknown): void => {\n queued.delete(processor);\n const wasFaulted = processor.fault !== undefined;\n profile.projection('processedNodes');\n let changedOutputs: readonly OutputRecord[] = [];\n const blocked = processor.dependencies.find(\n output => output.owner.fault || output.owner.disposed\n );\n if (blocked) {\n processor.fault = errorFor(\n processor,\n blocked.owner.fault ?? new ProjectionDisposedError(),\n 'blocked'\n );\n } else {\n const reset = wasFaulted || processor.dependencies.some(output => output.reset(processor));\n try {\n changedOutputs = processor.evaluate(reset, cause, wasFaulted);\n const failure = processor.dependencies.find(output => output.owner.fault)?.owner.fault;\n if (failure) throw failure;\n processor.fault = undefined;\n } catch (failure) {\n const error = errorFor(processor, failure);\n processor.fault = error;\n if (!reset) {\n try {\n changedOutputs = processor.evaluate(true, cause, true);\n const dependencyFailure = processor.dependencies.find(output => output.owner.fault)\n ?.owner.fault;\n if (dependencyFailure) throw dependencyFailure;\n processor.fault = undefined;\n errors.push(error);\n } catch (rebuildFailure) {\n processor.fault = errorFor(processor, rebuildFailure);\n errors.push(processor.fault);\n }\n } else errors.push(error);\n }\n }\n completed.add(processor);\n if (processor.fault) {\n processor.outputs.forEach(output => propagate(output));\n } else {\n if (changedOutputs.length) processor.publish();\n const recovered = wasFaulted && !processor.fault;\n (recovered ? processor.outputs : changedOutputs).forEach(output => propagate(output));\n }\n if (processor.fault || changedOutputs.length) profile.projection('publishedNodes');\n };\n\n // Iterative dependency-first traversal also supports deep projection chains.\n const advance = (target: ProducerRecord, cause: unknown): void => {\n const stack = [{ producer: target, dependency: 0 }];\n while (stack.length) {\n const frame = stack[stack.length - 1];\n const { producer } = frame;\n if (producer.disposed || !dirty.has(producer)) {\n dirty.delete(producer);\n stack.pop();\n continue;\n }\n if (producer.kind === 'processor') {\n let dependency: ProducerRecord | undefined;\n while (frame.dependency < producer.dependencies.length) {\n const candidate = producer.dependencies[frame.dependency++].owner;\n if (dirty.has(candidate)) {\n dependency = candidate;\n break;\n }\n }\n if (dependency) {\n stack.push({ producer: dependency, dependency: 0 });\n continue;\n }\n }\n stack.pop();\n dirty.delete(producer);\n if (producer.kind === 'source') advanceSource(producer, cause);\n else if (queued.has(producer)) {\n if (\n producer.fault ||\n producer.dependencies.some(output => output.owner.fault || output.pending(producer))\n )\n advanceProcessor(producer, cause);\n else {\n queued.delete(producer);\n producer.dependencies.forEach(output => output.acknowledge(producer));\n }\n }\n }\n };\n\n const compute = <T>(run: () => T): T => {\n phase = 'compute';\n lock(true);\n try {\n return run();\n } finally {\n lock(false);\n phase = 'idle';\n }\n };\n const settle = () => {\n if (disposed || depth || phase !== 'idle') return;\n const cause = settleCause();\n compute(() => {\n for (const producer of dirty) advance(producer, cause);\n });\n };\n const ensureCurrent = (output: OutputRecord): void => {\n assertActive();\n // Listener reads are safe after settlement; compute/input callbacks may not\n // use public reads to bypass dependency declarations or acceptance isolation.\n if (phase === 'notify') return;\n assertIdle();\n if (dirty.has(output.owner)) {\n const cause = settleCause();\n compute(() => advance(output.owner, cause));\n }\n };\n\n const flush = (): readonly ObserverError[] => {\n if (disposed || depth) return [];\n if (emissions.size || completed.size) profile.projection('flushes');\n phase = 'notify';\n lock(true);\n const reportFailures: unknown[] = [];\n try {\n emissions.forEach(output =>\n output.emit(\n (listener, change) => {\n try {\n listener(change);\n } catch (cause) {\n errors.push(errorFor(output.owner, cause, 'listener'));\n }\n },\n forced.has(output) || Boolean(output.owner.fault)\n )\n );\n for (const error of errors.slice()) {\n try {\n onError(error);\n } catch (cause) {\n reportFailures.push(cause);\n }\n }\n return Object.freeze([\n ...errors.map(error =>\n Object.freeze({\n phase: error.phase === 'listener' ? ('listener' as const) : ('processor' as const),\n error,\n })\n ),\n ...reportFailures.map(error => Object.freeze({ phase: 'listener' as const, error })),\n ]);\n } finally {\n emissions.forEach(output => output.finish());\n completed.forEach(processor => processor.clear());\n pendingSources.clear();\n queued.clear();\n completed.clear();\n emissions.clear();\n forced.clear();\n errors.length = 0;\n reportingFailures = reportFailures;\n lock(false);\n phase = 'idle';\n }\n };\n\n const run = () => {\n settle();\n const result = flush();\n const failures = reportingFailures;\n reportingFailures = [];\n if (failures.length) throw new AggregateError(failures, 'Projection error reporter failed.');\n return result;\n };\n\n const batch = <T>(callback: () => T, options?: BatchOptions): T => {\n assertIdle();\n const outer = depth === 0;\n if (outer)\n activeBatch = Object.freeze({\n id: ++batchSequence,\n ...(options?.cause === undefined ? {} : { cause: options.cause }),\n });\n depth++;\n let failed = false;\n try {\n const value = callback();\n assertSynchronous(value);\n return value;\n } catch (error) {\n failed = true;\n throw error;\n } finally {\n depth--;\n if (!depth) {\n try {\n if (failed) {\n try {\n run();\n } catch {\n /* The original application error retains priority. */\n }\n } else run();\n } finally {\n activeBatch = undefined;\n }\n }\n }\n };\n\n const releaseProducer = (producer: ProducerRecord) => {\n assertIdle();\n if (producer.outputs.some(output => output.hasConsumers()))\n throw new Error('Projection producer is still used by another processor.');\n producer.disposed = true;\n dirty.delete(producer);\n if (producer.kind === 'processor') {\n producer.dependencies.forEach(output => output.detachConsumer(producer));\n processors.delete(producer);\n queued.delete(producer);\n completed.delete(producer);\n } else {\n sources.delete(producer);\n pendingSources.delete(producer);\n }\n const failures: unknown[] = [];\n try {\n producer.release();\n } catch (error) {\n failures.push(error);\n }\n try {\n producer.clear();\n } catch (error) {\n failures.push(error);\n }\n producer.outputs.forEach(output => emissions.delete(output));\n if (failures.length) throw failures[0];\n };\n\n return {\n assertActive,\n assertIdle,\n capture,\n settle,\n ensureCurrent,\n flush,\n run,\n registerGuard(guard: (locked: boolean) => void): Unsubscribe {\n assertActive();\n guards.add(guard);\n let registered = true;\n return () => {\n if (!registered) return;\n registered = false;\n guards.delete(guard);\n };\n },\n get active() {\n return !disposed;\n },\n addSource(source: SourceBoundaryRecord) {\n assertIdle();\n sources.add(source);\n },\n addProcessor(processor: ProcessorRecord) {\n assertIdle();\n processors.add(processor);\n processor.dependencies.forEach(output => output.attachConsumer(processor));\n },\n releaseProducer,\n nextId: () => sequence++,\n acceptInput<T>(callback: () => T): T {\n assertIdle();\n phase = 'input';\n lock(true);\n try {\n return callback();\n } finally {\n lock(false);\n phase = 'idle';\n }\n },\n initialize<T>(callback: () => T): T {\n assertIdle();\n return compute(callback);\n },\n batch,\n batchContext: () => activeBatch,\n dispose() {\n if (disposed) return;\n assertIdle();\n disposed = true;\n const failures: unknown[] = [];\n processors.forEach(processor => {\n processor.disposed = true;\n try {\n processor.release();\n } catch (error) {\n failures.push(error);\n }\n });\n sources.forEach(source => {\n source.disposed = true;\n try {\n source.release();\n } catch (error) {\n failures.push(error);\n }\n });\n processors.clear();\n sources.clear();\n pendingSources.clear();\n dirty.clear();\n queued.clear();\n completed.clear();\n emissions.clear();\n forced.clear();\n guards.clear();\n errors.length = 0;\n reportingFailures = [];\n if (failures.length) throw new AggregateError(failures, 'Projection cleanup failed.');\n },\n };\n};\n\nexport type Scheduler = ReturnType<typeof createScheduler>;\n\nexport const assertSynchronous = (value: unknown): void => {\n if (\n value != null &&\n (typeof value === 'object' || typeof value === 'function') &&\n 'then' in value &&\n typeof value.then === 'function'\n )\n throw new TypeError('Projection callbacks must be synchronous.');\n};\n\nexport const assertScope = (active: () => boolean) => {\n if (!active()) throw new Error('Projection reader or writer is no longer active.');\n};\n","/** Allocation-free strict equality for ordered readonly arrays. */\nexport const sameArray = <T>(left: readonly T[], right: readonly T[]): boolean => {\n if (left === right) return true;\n if (left.length !== right.length) return false;\n for (let index = 0; index < left.length; index++) if (left[index] !== right[index]) return false;\n return true;\n};\n\n/** Owns an immutable shallow snapshot while reusing arrays that are already frozen. */\nexport const snapshotArray = <T>(values: readonly T[]): readonly T[] =>\n Object.isFrozen(values) ? values : Object.freeze([...values]);\n\n/** Compares an iterable with an ordered array without materializing the iterable. */\nexport const iterableMatchesArray = <T>(values: Iterable<T>, expected: readonly T[]): boolean => {\n let index = 0;\n for (const value of values) {\n if (index >= expected.length || value !== expected[index]) return false;\n index++;\n }\n return index === expected.length;\n};\n","import { sameArray, snapshotArray } from '@/value/array';\n\nexport type KeyRelation = {\n replaceOne(left: string, right: string | undefined): boolean;\n replace(left: string, right: readonly string[]): boolean;\n delete(left: string): boolean;\n forward(left: string): readonly string[] | undefined;\n reverse(right: string): ReadonlySet<string> | undefined;\n lefts(): IterableIterator<string>;\n rights(): IterableIterator<string>;\n clear(): void;\n};\n\n/** Runtime-local domain-neutral many-to-many keyed relation. */\nexport const createKeyRelation = (): KeyRelation => {\n const forward = new Map<string, readonly string[]>();\n const reverse = new Map<string, Set<string>>();\n\n const detach = (left: string, right: readonly string[]): void => {\n for (const key of right) {\n const dependents = reverse.get(key);\n dependents?.delete(left);\n if (dependents?.size === 0) reverse.delete(key);\n }\n };\n\n const attach = (left: string, right: readonly string[]): void => {\n for (const key of right) {\n const dependents = reverse.get(key);\n if (dependents) dependents.add(left);\n else reverse.set(key, new Set([left]));\n }\n };\n\n return {\n replaceOne(left, right) {\n const previous = forward.get(left);\n if (right === undefined) {\n if (!previous) return false;\n detach(left, previous);\n forward.delete(left);\n return true;\n }\n if (previous?.length === 1 && previous[0] === right) return false;\n if (previous) detach(left, previous);\n const next = Object.freeze([right]);\n forward.set(left, next);\n attach(left, next);\n return true;\n },\n replace(left, right) {\n const previous = forward.get(left);\n if (previous ? sameArray(previous, right) : right.length === 0) return false;\n if (previous) detach(left, previous);\n if (!right.length) {\n forward.delete(left);\n return true;\n }\n const next = snapshotArray(right);\n forward.set(left, next);\n attach(left, next);\n return true;\n },\n delete(left) {\n const previous = forward.get(left);\n if (!previous) return false;\n detach(left, previous);\n forward.delete(left);\n return true;\n },\n forward: left => forward.get(left),\n reverse: right => reverse.get(right),\n lefts: () => forward.keys(),\n rights: () => reverse.keys(),\n clear() {\n forward.clear();\n reverse.clear();\n },\n };\n};\n","import type { Synchronous } from '@/runtime/contract';\nimport { isPlainObject } from '@/value/record';\nimport { collectionView, mapRead } from '@/projection/collection/view';\nimport type { SourceContext } from '@/projection/contract';\nimport { readNamedDependencyEntries, snapshotDependencyValue } from '@/projection/dependency';\nimport {\n isProjection,\n outputDefinitionOf,\n type KeyedProjection,\n type Projection,\n} from '@/projection/definition';\nimport { assertSynchronous } from '@/projection/graph/scheduler';\nimport { createKeyRelation, type KeyRelation } from './relation';\n\nexport type SingularKeyedDependency<\n DriverKey extends string,\n DriverValue,\n SourceKey extends string,\n SourceValue,\n> = {\n readonly source: KeyedProjection<SourceKey, SourceValue>;\n readonly key: (value: DriverValue, key: DriverKey) => Synchronous<SourceKey | undefined>;\n readonly keys?: never;\n};\n\nexport type SameKeyedDependency<SourceKey extends string, SourceValue> = {\n readonly source: KeyedProjection<SourceKey, SourceValue>;\n readonly key?: never;\n readonly keys?: never;\n};\n\nexport type PluralKeyedDependency<\n DriverKey extends string,\n DriverValue,\n SourceKey extends string,\n SourceValue,\n> = {\n readonly source: KeyedProjection<SourceKey, SourceValue>;\n readonly keys: (value: DriverValue, key: DriverKey) => Synchronous<readonly SourceKey[]>;\n readonly key?: never;\n};\n\nexport type KeyedDependency<DriverKey extends string, DriverValue> =\n | (Projection<unknown> & {\n readonly source?: never;\n readonly key?: never;\n readonly keys?: never;\n })\n | SameKeyedDependency<string, unknown>\n | SingularKeyedDependency<DriverKey, DriverValue, string, unknown>\n | PluralKeyedDependency<DriverKey, DriverValue, string, unknown>;\n\nexport type KeyedDependencyRecord<DriverKey extends string, DriverValue> = Readonly<\n Record<string, KeyedDependency<DriverKey, DriverValue>>\n>;\n\ntype SameKeyConstraint<DriverKey extends string, Dependency> = Dependency extends {\n readonly source: KeyedProjection<infer SourceKey extends string, unknown>;\n}\n ? Dependency extends { readonly key: unknown } | { readonly keys: unknown }\n ? unknown\n : [DriverKey] extends [SourceKey]\n ? unknown\n : never\n : unknown;\n\nexport type KeyedDependencies<DriverKey extends string, DriverValue, D extends object> = {\n readonly [P in keyof D]: P extends string\n ? KeyedDependency<DriverKey, DriverValue> & SameKeyConstraint<DriverKey, D[P]>\n : never;\n};\n\nexport type KeyedDependencyValues<D extends object> = {\n readonly [P in keyof D]: D[P] extends {\n readonly source: KeyedProjection<infer K extends string, infer V>;\n readonly keys: (...args: never[]) => unknown;\n }\n ? ReadonlyMap<K, V>\n : D[P] extends {\n readonly source: KeyedProjection<infer _K extends string, infer V>;\n }\n ? V | undefined\n : D[P] extends Projection<infer T>\n ? T\n : never;\n};\n\ntype CompiledDynamicKeyedDependency =\n | {\n readonly kind: 'same';\n readonly projection: Projection<unknown>;\n }\n | {\n readonly kind: 'one';\n readonly projection: Projection<unknown>;\n readonly select: (value: unknown, key: string) => unknown;\n }\n | {\n readonly kind: 'many';\n readonly projection: Projection<unknown>;\n readonly select: (value: unknown, key: string) => unknown;\n };\n\ntype CompiledKeyedDependency =\n | {\n readonly name: string;\n readonly kind: 'global';\n readonly projection: Projection<unknown>;\n }\n | ({ readonly name: string } & CompiledDynamicKeyedDependency);\n\nexport type CompiledKeyedDependencies = {\n readonly entries: readonly CompiledKeyedDependency[];\n readonly projections: readonly Projection<unknown>[];\n};\n\nexport const outputKind = (projection: Projection<unknown>): 'value' | 'collection' =>\n outputDefinitionOf(projection).kind;\n\nexport const assertKeyedProjection = (projection: Projection<unknown>, role: string): void => {\n if (outputKind(projection) !== 'collection')\n throw new TypeError(`${role} must be a keyed collection projection.`);\n};\n\nconst compileDynamicDependency = (\n value: unknown,\n label: string\n): CompiledDynamicKeyedDependency => {\n if (!isPlainObject(value) || isProjection(value))\n throw new TypeError(`${label} dependencies must be projections or keyed lookups.`);\n const candidate: { source?: unknown; key?: unknown; keys?: unknown } = {};\n const allowed = new Set(['source', 'key', 'keys']);\n let hasKey = false;\n let hasKeys = false;\n for (const name of Reflect.ownKeys(value)) {\n if (typeof name !== 'string' || !allowed.has(name))\n throw new TypeError(`${label} dynamic keyed dependency contains an unknown property.`);\n const descriptor = Object.getOwnPropertyDescriptor(value, name);\n if (!descriptor?.enumerable || !('value' in descriptor))\n throw new TypeError(`${label} dynamic keyed dependency must use enumerable data properties.`);\n candidate[name as 'source' | 'key' | 'keys'] = descriptor.value;\n if (name === 'key') hasKey = true;\n if (name === 'keys') hasKeys = true;\n }\n if (!isProjection(candidate.source))\n throw new TypeError(`${label} dynamic keyed dependency source must be a projection.`);\n if (hasKey && hasKeys)\n throw new TypeError(`${label} dynamic keyed dependency must not declare both key and keys.`);\n assertKeyedProjection(candidate.source, `${label} dynamic keyed dependency source`);\n if (!hasKey && !hasKeys)\n return {\n kind: 'same',\n projection: candidate.source,\n };\n const singular = hasKey;\n const selector = singular ? candidate.key : candidate.keys;\n if (typeof selector !== 'function')\n throw new TypeError(`${label} dynamic keyed dependency selector must be a function.`);\n return singular\n ? {\n kind: 'one',\n projection: candidate.source,\n select: selector as (value: unknown, key: string) => unknown,\n }\n : {\n kind: 'many',\n projection: candidate.source,\n select: selector as (value: unknown, key: string) => unknown,\n };\n};\n\nexport const compileKeyedDependencies = (\n driver: Projection<unknown>,\n dependencySpecs: KeyedDependencyRecord<string, unknown> | undefined,\n label: string\n): CompiledKeyedDependencies => {\n const entries: CompiledKeyedDependency[] = [];\n const projections: Projection<unknown>[] = [driver];\n if (dependencySpecs === undefined)\n return Object.freeze({\n entries: Object.freeze(entries),\n projections: Object.freeze(projections),\n });\n for (const { name, value: dependency } of readNamedDependencyEntries(dependencySpecs, label)) {\n if (isProjection(dependency)) {\n entries.push(Object.freeze({ name, kind: 'global' as const, projection: dependency }));\n projections.push(dependency);\n continue;\n }\n const dynamic = compileDynamicDependency(dependency, label);\n entries.push(Object.freeze({ name, ...dynamic }));\n projections.push(dynamic.projection);\n }\n return Object.freeze({\n entries: Object.freeze(entries),\n projections: Object.freeze(projections),\n });\n};\n\nconst selectedKey = (\n dependency: Extract<CompiledDynamicKeyedDependency, { readonly kind: 'one' }>,\n value: unknown,\n key: string\n): string | undefined => {\n const result = dependency.select(value, key);\n assertSynchronous(result);\n if (result === undefined) return undefined;\n if (typeof result !== 'string')\n throw new TypeError('Dynamic keyed dependency key must be a string or undefined.');\n return result;\n};\n\nconst selectedKeys = (\n dependency: Extract<CompiledDynamicKeyedDependency, { readonly kind: 'many' }>,\n value: unknown,\n key: string\n): readonly string[] => {\n const result = dependency.select(value, key);\n assertSynchronous(result);\n if (!Array.isArray(result))\n throw new TypeError('Dynamic keyed dependency keys must be an array of strings.');\n const seen = new Set<string>();\n for (const selected of result) {\n if (typeof selected !== 'string')\n throw new TypeError('Dynamic keyed dependency keys must contain only strings.');\n if (seen.has(selected))\n throw new TypeError('Dynamic keyed dependency keys must not contain duplicates.');\n seen.add(selected);\n }\n return result as readonly string[];\n};\n\nexport type KeyedDependencyRuntime = {\n prepare(sources: readonly SourceContext[], reset: boolean): void;\n resolve(\n driverValue: unknown,\n driverKey: string,\n sources: readonly SourceContext[]\n ): Readonly<Record<string, unknown>>;\n driverChanged(source: SourceContext): boolean;\n collectInvalidated(sources: readonly SourceContext[], dirty: Set<string>): boolean;\n remove(driverKey: string): void;\n clearBindings(): void;\n remember(sources: readonly SourceContext[]): void;\n release(): void;\n};\n\nconst emptyValues: Readonly<Record<string, unknown>> = Object.freeze(\n Object.create(null) as Record<string, unknown>\n);\n\nexport const createKeyedDependencyRuntime = (\n compiled: CompiledKeyedDependencies\n): KeyedDependencyRuntime => {\n type GlobalDependencyState = {\n readonly kind: 'global';\n readonly entry: Extract<CompiledKeyedDependency, { readonly kind: 'global' }>;\n readonly sourceIndex: number;\n revision: number;\n globalValue: unknown;\n };\n type SameDependencyState = {\n readonly kind: 'same';\n readonly entry: Extract<CompiledKeyedDependency, { readonly kind: 'same' }>;\n readonly sourceIndex: number;\n revision: number;\n };\n type DynamicDependencyState = {\n readonly kind: 'dynamic';\n readonly entry: Extract<CompiledKeyedDependency, { readonly kind: 'one' | 'many' }>;\n readonly sourceIndex: number;\n readonly relation: KeyRelation;\n revision: number;\n };\n type DependencyState = GlobalDependencyState | SameDependencyState | DynamicDependencyState;\n const states: DependencyState[] = compiled.entries.map((entry, index) => {\n const sourceIndex = index + 1;\n if (entry.kind === 'global')\n return { kind: 'global', entry, sourceIndex, revision: -1, globalValue: undefined };\n if (entry.kind === 'same') return { kind: 'same', entry, sourceIndex, revision: -1 };\n return {\n kind: 'dynamic',\n entry,\n sourceIndex,\n relation: createKeyRelation(),\n revision: -1,\n };\n });\n let driverRevision = -1;\n\n return {\n prepare(sources, reset) {\n for (const state of states) {\n if (state.kind !== 'global') continue;\n const source = sources[state.sourceIndex];\n if (reset || state.revision !== source.revision)\n state.globalValue = snapshotDependencyValue(source);\n }\n },\n resolve(driverValue, driverKey, sources) {\n if (!states.length) return emptyValues;\n const values = Object.create(null) as Record<string, unknown>;\n for (const state of states) {\n if (state.kind === 'global') {\n values[state.entry.name] = state.globalValue;\n continue;\n }\n const source = sources[state.sourceIndex];\n if (source.kind !== 'collection')\n throw new TypeError('Dynamic keyed dependency resolved to a non-collection source.');\n if (state.kind === 'same') {\n values[state.entry.name] = source.read.get(driverKey);\n continue;\n }\n const dependency = state.entry;\n if (dependency.kind === 'one') {\n const selected = selectedKey(dependency, driverValue, driverKey);\n state.relation.replaceOne(driverKey, selected);\n values[dependency.name] = selected === undefined ? undefined : source.read.get(selected);\n continue;\n }\n const keys = selectedKeys(dependency, driverValue, driverKey);\n state.relation.replace(driverKey, keys);\n const selected = new Map<string, unknown>();\n for (const key of keys) if (source.read.has(key)) selected.set(key, source.read.get(key));\n values[dependency.name] = collectionView(mapRead(selected));\n }\n return Object.freeze(values);\n },\n driverChanged(source) {\n return driverRevision !== source.revision;\n },\n collectInvalidated(sources, dirty) {\n let all = false;\n for (const state of states) {\n const source = sources[state.sourceIndex];\n if (state.revision === source.revision) continue;\n if (state.kind === 'global') {\n all = true;\n continue;\n }\n if (source.kind !== 'collection' || !source.change || source.change.kind === 'reset') {\n all = true;\n continue;\n }\n if (state.kind === 'same') {\n for (const entry of source.change.added) dirty.add(entry.key);\n for (const entry of source.change.updated) dirty.add(entry.key);\n for (const entry of source.change.removed) dirty.add(entry.key);\n continue;\n }\n for (const entry of source.change.added)\n for (const dependent of state.relation.reverse(entry.key) ?? []) dirty.add(dependent);\n for (const entry of source.change.updated)\n for (const dependent of state.relation.reverse(entry.key) ?? []) dirty.add(dependent);\n for (const entry of source.change.removed)\n for (const dependent of state.relation.reverse(entry.key) ?? []) dirty.add(dependent);\n }\n return all;\n },\n remove(driverKey) {\n for (const state of states) if (state.kind === 'dynamic') state.relation.delete(driverKey);\n },\n clearBindings() {\n for (const state of states) if (state.kind === 'dynamic') state.relation.clear();\n },\n remember(sources) {\n driverRevision = sources[0]?.revision ?? -1;\n for (const state of states) state.revision = sources[state.sourceIndex].revision;\n },\n release() {\n for (const state of states) {\n state.revision = -1;\n if (state.kind === 'global') state.globalValue = undefined;\n else if (state.kind === 'dynamic') state.relation.clear();\n }\n driverRevision = -1;\n },\n };\n};\n","import type { CollectionChange } from '@/projection/contract';\nimport { sameArray, snapshotArray } from '@/value/array';\n\ntype Added<K extends string, V> = { readonly key: K; readonly after: V };\ntype Updated<K extends string, V> = {\n readonly key: K;\n readonly before: V;\n readonly after: V;\n};\ntype Removed<K extends string, V> = { readonly key: K; readonly before: V };\n\nconst transitionContains = <K extends string>(\n entries: readonly { readonly key: K }[],\n key: K\n): boolean => {\n for (const entry of entries) if (entry.key === key) return true;\n return false;\n};\n\nconst transitionSet = <K extends string>(\n entries: readonly { readonly key: K }[]\n): ReadonlySet<K> | undefined => {\n // Small net membership changes are overwhelmingly common. Linear lookup avoids\n // allocating a Set while keeping large batches O(n).\n if (entries.length <= 4) return undefined;\n const keys = new Set<K>();\n for (const entry of entries) keys.add(entry.key);\n return keys;\n};\n\nconst nextExcluding = <K extends string>(\n iterator: Iterator<K>,\n excluded: readonly { readonly key: K }[],\n index: ReadonlySet<K> | undefined\n): IteratorResult<K> => {\n while (true) {\n const next = iterator.next();\n if (next.done || !(index ? index.has(next.value) : transitionContains(excluded, next.value)))\n return next;\n }\n};\n\n/** Compares common-member order from known transitions without materializing common arrays. */\nconst transitionOrderChanged = <K extends string>(\n before: Iterable<K>,\n after: Iterable<K>,\n removed: readonly { readonly key: K }[],\n added: readonly { readonly key: K }[]\n): boolean => {\n const removedKeys = transitionSet(removed);\n const addedKeys = transitionSet(added);\n const beforeIterator = before[Symbol.iterator]();\n const afterIterator = after[Symbol.iterator]();\n while (true) {\n const left = nextExcluding(beforeIterator, removed, removedKeys);\n const right = nextExcluding(afterIterator, added, addedKeys);\n if (left.done || right.done) return left.done !== right.done;\n if (left.value !== right.value) return true;\n }\n};\n\nconst nextPresentIn = <K, V>(\n iterator: Iterator<K>,\n membership: ReadonlyMap<K, V>\n): IteratorResult<K> => {\n while (true) {\n const next = iterator.next();\n if (next.done || membership.has(next.value)) return next;\n }\n};\n\n/** Compares common-member order between two map snapshots without key snapshots or closures. */\nconst mapOrderChanged = <K, V>(before: ReadonlyMap<K, V>, after: ReadonlyMap<K, V>): boolean => {\n const beforeIterator = before.keys();\n const afterIterator = after.keys();\n while (true) {\n const left = nextPresentIn(beforeIterator, after);\n const right = nextPresentIn(afterIterator, before);\n if (left.done || right.done) return left.done !== right.done;\n if (left.value !== right.value) return true;\n }\n};\n\nconst sealIncrementalChange = <K extends string, V>(\n added: Added<K, V>[],\n updated: Updated<K, V>[],\n removed: Removed<K, V>[],\n order?: { readonly before: readonly K[]; readonly after: readonly K[] }\n): CollectionChange<K, V> | undefined => {\n if (!added.length && !updated.length && !removed.length && !order) return undefined;\n return Object.freeze({\n kind: 'incremental' as const,\n added: Object.freeze(added),\n updated: Object.freeze(updated),\n removed: Object.freeze(removed),\n ...(order\n ? {\n order: Object.freeze({\n before: snapshotArray(order.before),\n after: snapshotArray(order.after),\n }),\n }\n : {}),\n });\n};\n\n/** Builds the canonical incremental CollectionChange from already-known net transitions. */\nexport const createCollectionChange = <K extends string, V>(input: {\n readonly added: Added<K, V>[];\n readonly updated: Updated<K, V>[];\n readonly removed: Removed<K, V>[];\n readonly beforeOrder: readonly K[];\n readonly afterOrder: readonly K[];\n}): CollectionChange<K, V> | undefined => {\n let orderChanged = false;\n if (input.beforeOrder !== input.afterOrder) {\n if (!input.added.length && !input.removed.length)\n orderChanged = !sameArray(input.beforeOrder, input.afterOrder);\n else\n orderChanged = transitionOrderChanged(\n input.beforeOrder,\n input.afterOrder,\n input.removed,\n input.added\n );\n }\n return sealIncrementalChange(\n input.added,\n input.updated,\n input.removed,\n orderChanged ? { before: input.beforeOrder, after: input.afterOrder } : undefined\n );\n};\n\n/** Exact fallback diff between two published map-like snapshots. */\nexport const diffCollection = <K extends string, V>(\n previous: ReadonlyMap<K, V>,\n current: ReadonlyMap<K, V>,\n isEqual: (previous: V, next: V) => boolean = Object.is\n): CollectionChange<K, V> | undefined => {\n const added: Added<K, V>[] = [];\n const updated: Updated<K, V>[] = [];\n const removed: Removed<K, V>[] = [];\n for (const [key, before] of previous) {\n if (!current.has(key)) removed.push({ key, before });\n else {\n const after = current.get(key) as V;\n if (!isEqual(before, after)) updated.push({ key, before, after });\n }\n }\n for (const [key, after] of current) if (!previous.has(key)) added.push({ key, after });\n const orderChanged = mapOrderChanged(previous, current);\n return sealIncrementalChange(\n added,\n updated,\n removed,\n orderChanged\n ? {\n before: Object.freeze([...previous.keys()]),\n after: Object.freeze([...current.keys()]),\n }\n : undefined\n );\n};\n\nconst changedKeys = function* <K extends string, V>(\n change: Extract<CollectionChange<K, V>, { readonly kind: 'incremental' }>\n): IterableIterator<K> {\n if ((change as CollectionChange<K, V>).kind !== 'incremental')\n throw new TypeError('collectionChange.keys requires an incremental CollectionChange.');\n for (const entry of change.added) yield entry.key;\n for (const entry of change.updated) yield entry.key;\n for (const entry of change.removed) yield entry.key;\n};\n\nexport const collectionChange: {\n readonly keys: <K extends string, V>(\n change: Extract<CollectionChange<K, V>, { readonly kind: 'incremental' }>\n ) => Iterable<K>;\n} = Object.freeze({ keys: changedKeys });\n\nexport const collectionHasStructuralChange = <K extends string, V>(\n change: CollectionChange<K, V>\n): boolean =>\n change.kind === 'reset' || Boolean(change.added.length || change.removed.length || change.order);\n\nexport const collectionChangeTouchesKey = <K extends string, V>(\n change: Extract<CollectionChange<K, V>, { readonly kind: 'incremental' }>,\n key: K\n): boolean => {\n for (const entry of change.added) if (entry.key === key) return true;\n for (const entry of change.updated) if (entry.key === key) return true;\n for (const entry of change.removed) if (entry.key === key) return true;\n return false;\n};\n\nexport const collectionChangeIntersects = <K extends string, V>(\n change: Extract<CollectionChange<K, V>, { readonly kind: 'incremental' }>,\n keys: ReadonlySet<K>\n): boolean => {\n for (const entry of change.added) if (keys.has(entry.key)) return true;\n for (const entry of change.updated) if (keys.has(entry.key)) return true;\n for (const entry of change.removed) if (keys.has(entry.key)) return true;\n return false;\n};\n","import { collectKeyedInvalidation } from './invalidation';\nimport { defineProcessor, type KeyedProjection } from '@/projection/definition';\nimport { assertSynchronous } from '@/projection/graph/scheduler';\nimport {\n assertKeyedProjection,\n compileKeyedDependencies,\n createKeyedDependencyRuntime,\n type KeyedDependencyRecord,\n} from './dependency';\n\nexport const keyedAbsent = Symbol('keyed-transform-absent');\nexport type KeyedTransformResult<T> = T | typeof keyedAbsent;\n\nexport type KeyedTransformContext<K extends string, V, State> = {\n readonly key: K;\n readonly value: V;\n readonly dependencies: Readonly<Record<string, unknown>>;\n readonly state: State;\n readonly reset: boolean;\n readonly cause: unknown;\n};\n\nexport type KeyedTransformDefinition<K extends string, V, T, State> = {\n readonly source: KeyedProjection<K, V>;\n readonly dependencies?: KeyedDependencyRecord<K, V>;\n readonly equality?: (previous: T, next: T) => boolean;\n readonly name: string;\n readonly state?: (value: V, key: K) => State;\n readonly evaluate: (context: KeyedTransformContext<K, V, State>) => KeyedTransformResult<T>;\n};\n\n/** Shared driver-keyed lifecycle for pure and retained keyed transforms. */\nexport const createKeyedTransform = <K extends string, V, T, State = undefined>(\n definition: KeyedTransformDefinition<K, V, T, State>\n): KeyedProjection<K, T> => {\n assertKeyedProjection(definition.source, `${definition.name} source`);\n const compiled = compileKeyedDependencies(\n definition.source,\n definition.dependencies as KeyedDependencyRecord<string, unknown> | undefined,\n definition.name\n );\n const [projection] = defineProcessor({\n dependencies: compiled.projections,\n outputs: [\n {\n kind: 'collection',\n equality: (definition.equality ?? Object.is) as (\n previous: unknown,\n next: unknown\n ) => boolean,\n },\n ],\n create: () => {\n const dependencies = createKeyedDependencyRuntime(compiled);\n const states = new Map<string, State>();\n\n const dropState = (key: string): void => {\n states.delete(key);\n dependencies.remove(key);\n };\n\n return {\n evaluate: evaluation => {\n const driver = evaluation.sources[0];\n const output = evaluation.outputs[0];\n if (driver.kind !== 'collection' || output.kind !== 'collection')\n throw new Error(`${definition.name} requires collection input and output.`);\n const invalidation = collectKeyedInvalidation(\n driver,\n evaluation.sources,\n dependencies,\n evaluation.reset\n );\n dependencies.prepare(evaluation.sources, invalidation.rebuild);\n\n const stateFor = (key: string, value: V): State => {\n if (states.has(key)) return states.get(key) as State;\n const state = definition.state\n ? definition.state(value, key as K)\n : (undefined as State);\n assertSynchronous(state);\n if (definition.state) states.set(key, state);\n return state;\n };\n\n const project = (key: string): boolean => {\n if (!driver.read.has(key)) return false;\n const value = driver.read.get(key) as V;\n const beforePresent = output.previous.has(key);\n const next = definition.evaluate({\n key: key as K,\n value,\n dependencies: dependencies.resolve(value, key, evaluation.sources),\n state: stateFor(key, value),\n reset: evaluation.reset,\n cause: evaluation.cause,\n });\n assertSynchronous(next);\n if (next === keyedAbsent) output.output.remove(key);\n else output.output.set(key, next);\n return beforePresent !== output.next.has(key);\n };\n\n if (invalidation.rebuild) {\n dependencies.clearBindings();\n const ids = driver.read.ids();\n for (const key of states.keys()) if (!driver.read.has(key)) states.delete(key);\n if (!evaluation.reset)\n for (const key of output.previous.ids())\n if (!driver.read.has(key)) output.output.remove(key);\n for (const key of ids) project(key);\n output.output.order(ids.filter(key => output.next.has(key)));\n dependencies.remember(evaluation.sources);\n return;\n }\n\n let membershipChanged = false;\n for (const entry of invalidation.removed) {\n membershipChanged ||= output.previous.has(entry.key);\n output.output.remove(entry.key);\n dropState(entry.key);\n }\n for (const key of invalidation.keys) {\n const changedMembership = project(key);\n membershipChanged ||= changedMembership;\n }\n if (invalidation.structural || membershipChanged)\n output.output.order(driver.read.ids().filter(key => output.next.has(key)));\n dependencies.remember(evaluation.sources);\n },\n release: () => {\n states.clear();\n dependencies.release();\n },\n };\n },\n name: definition.name,\n });\n return projection as KeyedProjection<K, T>;\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doxum",
3
- "version": "0.1.32",
3
+ "version": "0.1.34",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "description": "Doxum is a typed runtime for complex mutable documents.",
@@ -45,19 +45,21 @@ Follow these choices unless the requirement says otherwise:
45
45
  4. Use `observe` to bring a document/readable/external source into the projection graph.
46
46
  5. Use named-object `derive` for pure aggregate values.
47
47
  6. Use `derive.keyed.from` to turn an ordered scalar/static collection into a keyed projection. Use `derive.keyed.merge` to compose multiple keyed projections; for base + sparse overrides, use `{ conflict: 'last' }`.
48
- 7. Use `derive.keyed` when one keyed source owns output membership/order. Prefer its built-in `keys`, `values`, `entries`, `get`, `from`, `merge`, `subset`, `filter`, `compact`, `groupBy`, and `singleton` primitives over hand-written incremental collection patches.
48
+ 7. Use `derive.keyed` when one keyed source owns output membership/order. Prefer its built-in `keys`, `values`, `entries`, `get`, `from`, `merge`, `subset`, `filter`, `compact`, `groupBy`, `flatMap`, and `singleton` primitives over hand-written incremental collection patches.
49
49
  8. Express per-output-key joins through `{ source }` for same-key lookup, `{ source, key }` for one mapped key, or `{ source, keys }` for several mapped keys. Let the Runtime own binding and reverse invalidation; do not maintain an application `Map` just to route dependency changes.
50
50
  9. Use `runtime.items(keyedProjection)` or `scope.items(...)` for stable per-membership item `Readable`s.
51
51
  10. Use `incremental.keyed` for independent retained state per driver key. Use `incremental.collection` or `incremental.group` only when direct incremental output patching or shared retained state is required.
52
52
  11. Use `ProjectionScope` only for lifecycle ownership. Define projections normally, then `scope.own(...)` before that definition is first materialized as a root.
53
53
 
54
+ Use `runtime.read` or `Readable.current()` for current values both inside and outside batches. `runtime.batch(() => ...)` groups net notifications; demanded dependencies may compute during a read. Ordinary commands compose without another reader API. Keep derived values in derive instead of synchronizing an input mirror. Use `derive.keyed.flatMap` for synchronous pure one-to-many output with global child keys; do not hand-maintain child membership in advanced state.
55
+
54
56
  ## Failure and lifecycle rules
55
57
 
56
58
  - Doxum callbacks are synchronous unless the public API explicitly returns a Promise.
57
59
  - `TransactionRejected` expresses expected application rejection; ordinary thrown exceptions roll back and rethrow unchanged.
58
60
  - A committed document write remains committed even if projection or listener notification later fails; observer errors are reported on the result or through projection error handling.
59
61
  - `CollectionChange` is an advanced processor transport contract. Reset, membership transitions, value updates, and order are distinct facts.
60
- - `input.collection` has a strong exception boundary: callback or equality failure installs no partial next state.
62
+ - Input acceptance has a strong exception boundary: assignment equality or collection callback/equality failure installs no partial next state. A batch is not a transaction and retains earlier successful writes.
61
63
  - Dispose the owning `ProjectionRuntime`, `ProjectionScope`, and `LocalSync` with the application/service lifecycle that created them.
62
64
 
63
65
  ## Completion contract
@@ -14,7 +14,7 @@ type Readable<T> = {
14
14
  };
15
15
  ```
16
16
 
17
- `select(document, ...)`, `runtime.select(...)`, `runtime.items(...).keys`, item readables, history, and local-sync state all use this contract. Subscription listeners receive no payload; read the latest published value with `current()`.
17
+ `select(document, ...)`, `runtime.select(...)`, `runtime.items(...).keys`, item readables, history, and local-sync state all use this contract. Subscription listeners receive no payload; read the current value with `current()`.
18
18
 
19
19
  Consumer listener failure does not retroactively roll back the source mutation that caused the notification.
20
20
 
@@ -121,7 +121,7 @@ editSelection(draft => {
121
121
  });
122
122
  ```
123
123
 
124
- `useInput` writes through the provided Runtime/scope. The input definition must belong to that owner.
124
+ `useInput` writes through the provided Runtime/scope. The input definition must belong to that owner. Scalar setter arguments are always values, including functions; they do not use React's updater-function convention. Collection edit callbacks must be synchronous. For compound domain commands, call the Core Runtime/scope's `batch(() => ...)` and use ordinary `read`. Imperative reads can advance derived values before notifications drive the next React render. Do not implement a React-side source mirror or per-child flatMap cache.
125
125
 
126
126
  ### Document selectors
127
127
 
@@ -45,10 +45,13 @@ This file is maintainer-only. Application/library consumers should use [Public A
45
45
  dependencies through imperative Runtime reads. A scope adds lifecycle ownership only
46
46
  through `scope.own`; scoped definitions may depend on root definitions, while root and
47
47
  sibling scopes cannot depend on scoped definitions. Notification failures leave commits
48
- accepted. Batch defers projection publication, not document commits/listeners.
48
+ accepted. Public projection reads request current state; batch defers projection
49
+ notifications, not demand computation or document commits/listeners. Processors use one
50
+ real retained instance across demanded evaluations.
49
51
  Lazy definition metadata does not materialize sources. Input, observe and source
50
- materialization remain separate boundaries. One output object owns staged/published
51
- state, revision, listeners and graph-facing consumer capability; scheduler alone
52
+ materialization remain separate boundaries. One output object owns staged/current
53
+ state, per-consumer unconsumed deltas, notification baselines, revision, listeners
54
+ and graph-facing consumer capability; scheduler alone
52
55
  attaches/detaches dependency edges. Collection-input callback/equality failure installs
53
56
  no partial Runtime-local state. Cleanup is exhaustive after ownership is detached;
54
57
  initialization failure releases already-created projection resources and preserves the
@@ -287,6 +287,33 @@ Semantics:
287
287
 
288
288
  Use this instead of adapter/business code subscribing to keys and maintaining its own `Map<K,Readable<V>>`.
289
289
 
290
+ ### One-to-many keyed expansion
291
+
292
+ ```ts
293
+ const lines = derive.keyed.flatMap(orders, order =>
294
+ order.lines.map(line => [line.id, line] as const)
295
+ );
296
+
297
+ const errors = derive.keyed.flatMap(
298
+ forms,
299
+ { rules, fields: { source: fieldsById, keys: form => form.fieldIds } },
300
+ (form, formId, dependencies) =>
301
+ validateForm(form, dependencies).map(
302
+ error => [JSON.stringify([formId, error.fieldId, error.code]), error] as const
303
+ )
304
+ );
305
+ ```
306
+
307
+ The synchronous selector returns a finite readonly array of readonly `[outputKey, value]` tuples. The output is a `KeyedProjection<OutputKey, Value>`. Both overloads accept optional per-entry equality as the last argument. Named global and dynamic same/one/many keyed dependencies use the existing driver-key protocol. Callbacks stay value-first.
308
+
309
+ Output order concatenates each parent's returned key sequence in formal parent order. Only invalidated parents run the selector on a normal successful update; parent order-only changes run no selectors. A global dependency may invalidate every parent. Membership or order changes may rebuild the complete formal output order: selector locality does not imply every operation is O(changes).
310
+
311
+ Output keys must be globally unique strings. Duplicate keys within a parent or across final parent results are processor errors, never silent overwrites. Use an unambiguous application key encoding for locally unique child IDs; there is no default delimiter or generated index identity. For identity across parent transfers, use a global child ID independent of the parent. `[]` means no members; `[[key, undefined]]` means a present member with an undefined value.
312
+
313
+ Equality defaults to `Object.is` and only controls an existing key's value update, preserving the previous published reference when equal, including reset/recovery. It cannot suppress membership or order. If one global key moves between parents in a single notification interval, its final membership is continuous and `runtime.items(...).get(key)` retains its identity. A real removal in an earlier notification interval ends that membership.
314
+
315
+ Selector/key-construction, tuple validation, duplicate-key and equality failures publish no partial collection and use normal processor recovery. Recovery can rerun selectors for all parents, so selectors must be pure. A persistent fault blocks dependents and reads throw until recovery. Definitions are lazy and reusable; caches are isolated per Runtime and released with their owner. Derive additional keyed views from the result normally. Async loading, recursive traversal and dynamically creating projections are outside this primitive; retained spatial/search indexes still belong in advanced processors.
316
+
290
317
  ## Projection inputs
291
318
 
292
319
  Scalar local state:
@@ -310,7 +337,7 @@ Inputs belong to one materializing Runtime/scope. They are not canonical documen
310
337
 
311
338
  `input.collection` edit callbacks are synchronous borrowed sessions. If the callback throws, nothing is installed. Entry equality is also evaluated before the next local state is formally installed; if equality throws, published state and the next edit baseline remain unchanged.
312
339
 
313
- An equality-equivalent `set` retains the previously published value reference and publishes no entry update.
340
+ An equality-equivalent `set` retains the latest accepted value reference; candidates equivalent to the notification baseline reuse its reference. See Current reads and batching for net-change and exception rules.
314
341
 
315
342
  ## ProjectionScope
316
343
 
@@ -342,12 +369,44 @@ runtime.batch(() => {
342
369
  }, { cause });
343
370
  ```
344
371
 
345
- Projection batching defers projection graph settlement/listeners until the batch completes. It does not delay or roll back canonical document commits or document listeners.
372
+ Projection batching defers external projection notifications; current reads can advance necessary computations before the batch completes. It does not delay or roll back canonical document commits or document listeners.
346
373
 
347
- Reads of projections inside the batch see the last published projection state, not an eagerly settled draft. Batch the whole application action before its first source update when one settled projection publication is required.
374
+ Reads inside a batch see current state. Batch the whole application action before its first source update when one final net notification is required.
348
375
 
349
376
  There is no cross-document transaction or rollback implied by `runtime.batch`.
350
377
 
378
+ ### Current reads and batching
379
+
380
+ `runtime.read(projection)` and `Readable.current()` return current state inside and outside a batch. Inputs reflect the latest successfully accepted writes; derived projections update their necessary dependency chain on demand. Document projections read committed document state, never an uncommitted document draft. Clean repeated reads reuse cached results. `scope.read` has the same semantics with its usual ownership checks.
381
+
382
+ ```ts
383
+ const count = input(0);
384
+ const doubled = derive({ count }, ({ count }) => count * 2);
385
+
386
+ function increment() {
387
+ runtime.update(count, runtime.read(count) + 1);
388
+ }
389
+
390
+ runtime.batch(() => {
391
+ increment();
392
+ runtime.read(doubled); // 2: computes the demanded derived value
393
+ increment();
394
+ runtime.read(doubled); // 4
395
+ });
396
+ ```
397
+
398
+ `batch` receives a zero-argument synchronous callback. It defers external projection notifications until the outermost batch ends; computations not demanded by reads may also wait until that boundary. A nested batch does not notify early. Commands can compose directly without adding an inner batch solely for fresh reads. Synchronous return values and `cause` remain supported. Batch does not delay document commits/document listeners or provide cross-input/document rollback.
399
+
400
+ Current reads can advance a processor multiple times in one batch. Retained state advances on the real processor instance, and each processor receives the changes since its own previous successful evaluation. Unrelated branches remain unevaluated until demanded or final settlement. Processor invocation counts are not domain events: intermediate reads can affect the sequence of retained-state updates, including internal member removal/recreation. Explicit named/dynamic dependencies remain required. Public reads cannot be used from processor, draft or equality callbacks to bypass declarations or reenter computation. Materialized current values can be read from notification callbacks; writes and new graph materialization remain forbidden there.
401
+
402
+ `Readable.revision()` describes current value progress and may advance before its subscriber is notified. It is not a count of subscriber calls. Direct, selector and item readables all stay current when subscribed. Notifications compare the notification interval's initial and final states, so intermediate reads neither emit early nor consume a pending notification. An A→B→A return to the same value/reference produces no value notification; equality-equivalent candidates retain the relevant baseline reference. Identical object contents alone do not imply equality under `Object.is`. Collection membership/order and explicit reset keep their own semantics.
403
+
404
+ `runtime.items()` reads current keys/values while ending member lifecycles at the notification boundary. A temporarily missing existing key can read as `undefined`, then reappear under the same Readable identity in that batch. A handle acquired for a transient newly present key ends if the key is absent at the boundary; a later re-add gets a new handle. Pure value changes never end membership. A previously ended handle stays ended.
405
+
406
+ Collection reads are immutable version snapshots; later writes cannot mutate a previously returned view. Repeated reads at the same output revision reuse the view. Views and handles retain their owner's disposal checks. Payloads remain readonly by ownership contract: compute replacements or use the synchronous collection draft instead of mutating a read result. Scalar assignment always stores its second argument, including functions and Promise payloads. Batch/draft callbacks themselves cannot return thenables, and drafts expire when the edit callback returns.
407
+
408
+ Input acceptance checks candidate equality against the latest accepted value and, when distinct, the notification baseline before installation. All comparisons for an edit succeed before any accepted state changes. Equality must be pure, synchronous and stable. A failed assignment/draft/equality leaves the previous acceptance baseline intact and throws synchronously; earlier successes remain. Derived failures discovered by a read throw `ProjectionError` at that read, retain accepted source updates, and recover through the normal processor reset/retry protocol after invalidation. `onError` reporting and external notifications remain at the outer boundary. If the batch callback throws, prior successes still settle and the original exception keeps priority over error-reporter failures.
409
+
351
410
  ## Collection change protocol
352
411
 
353
412
  Advanced keyed processors receive one transport shape:
@@ -328,6 +328,7 @@ The keyed family:
328
328
  | `get` | Scalar dynamic lookup into one current keyed entry |
329
329
  | `from` | Ordered scalar/static collection → keyed projection |
330
330
  | `merge` | Multiple keyed projections → union with explicit conflict policy |
331
+ | `flatMap` | Ordered pure one-to-many keyed expansion |
331
332
  | `groupBy` | One-to-many reverse index |
332
333
  | `singleton` | Optional scalar → zero-or-one keyed projection |
333
334
  | `subset` | Externally ordered keyed subset |
@@ -353,6 +354,9 @@ derive.keyed.filter(source, predicate): KeyedProjection<K,V>
353
354
  derive.keyed.filter(source, dependencies, predicate): KeyedProjection<K,V>
354
355
  derive.keyed.compact(source, selector, equality?): KeyedProjection<K,T>
355
356
  derive.keyed.compact(source, dependencies, selector, equality?): KeyedProjection<K,T>
357
+ derive.keyed.flatMap(source, select, equality?): KeyedProjection<OutputKey, Value>
358
+ derive.keyed.flatMap(source, dependencies, select, equality?): KeyedProjection<OutputKey, Value>
359
+ // select(value, driverKey, dependencies?) returns readonly (readonly [OutputKey, Value])[]
356
360
  derive.keyed.groupBy(source, selector): KeyedProjection<GroupKey, readonly K[]>
357
361
  derive.keyed.groupBy(source, dependencies, selector): KeyedProjection<GroupKey, readonly K[]>
358
362
  derive.keyed.singleton(sourceProjection, keyOf, equality?): KeyedProjection<K,V>
@@ -368,6 +372,8 @@ Merged formal order is always `stableUnique(S0.ids() ++ S1.ids() ++ ... ++ Sn.id
368
372
 
369
373
  `groupBy` has deterministic order on both axes. Every bucket value contains source keys in formal source order. Output group keys are ordered by the earliest current source member that belongs to each group; if multiple groups first occur on the same source member, their order is the selector's group-key order for that member. Source membership/order changes can therefore reorder group keys even when the set of groups is unchanged.
370
374
 
375
+ `flatMap` concatenates parent child-tuples in formal parent order. Keys are globally unique strings; duplicates are processor errors, and `undefined` is a legal present value. Equality retains published entry references without suppressing membership/order. Same-settlement parent transfers preserve global-key membership; order-only parent changes do not rerun selectors. It shares the named dependency protocol and processor recovery. Structural output maintenance may scan full order.
376
+
371
377
  Dynamic keyed dependency entries are either ordinary global `Projection`s or:
372
378
 
373
379
  ```ts
@@ -387,14 +393,16 @@ const runtime = createProjectionRuntime({
387
393
  ```
388
394
 
389
395
  ```ts
396
+ // Synchronous is signature notation here, not an additional root export.
397
+ type Synchronous<T> = T extends PromiseLike<unknown> ? never : T;
390
398
  type ProjectionRuntime = {
391
399
  read<T>(projection: Projection<T>): T;
392
400
  select<T>(projection: Projection<T>): Readable<T>;
393
401
  select<T,R>(projection: Projection<T>, selector: (value: T) => R, equality?): Readable<R>;
394
402
  items<K,V>(projection: KeyedProjection<K,V>): ProjectionItems<K,V>;
395
- update<T>(input: Input<T>, value: T): void;
396
- update<K,V>(input: CollectionInput<K,V>, run: (draft: CollectionInputDraft<K,V>) => void): void;
397
- batch<T>(run: () => T, options?: { cause?: unknown }): T;
403
+ update<T>(input: Input<T>, value: NoInfer<T>): void;
404
+ update<K,V,R>(input: CollectionInput<K,V>, run: (draft: CollectionInputDraft<K,V>) => Synchronous<R>): void;
405
+ batch<T>(run: () => Synchronous<T>, options?: { cause?: unknown }): T;
398
406
  scope(): ProjectionScope;
399
407
  dispose(): void;
400
408
  };
@@ -417,6 +425,8 @@ type CollectionInputDraft<K,V> = {
417
425
  };
418
426
  ```
419
427
 
428
+ `read` and all projection Readable `current()` methods return current state; stale dependencies compute on demand. `batch` has a zero-argument synchronous callback and defers external notifications until the outermost boundary. Reads may advance retained processors multiple times. Input equality runs before acceptance; failure retains earlier successes. Collection views are immutable version snapshots. See [Current reads and batching](projections.md#current-reads-and-batching) for revisions, net notifications, item lifecycle and recovery.
429
+
420
430
  ### External projection sources
421
431
 
422
432
  ```ts
@@ -597,7 +607,7 @@ Every declared output must be returned from the static output tree exactly once.
597
607
  useProjection(projection): T
598
608
  useProjection(projection, selector, equality?): R
599
609
  useInput(input): readonly [T, (value: T) => void]
600
- useInput(collectionInput): readonly [ReadonlyMap<K,V>, (edit: (draft: CollectionInputDraft<K,V>) => void) => void]
610
+ useInput(collectionInput): readonly [ReadonlyMap<K,V>, <R>(edit: (draft: CollectionInputDraft<K,V>) => Synchronous<R>) => void]
601
611
  useDocumentSelector(document, selector, equality?): R
602
612
  useReadable(readable): T
603
613
  useHistory(history): HistoryState & { undo(): OperationResult<C>; redo(): OperationResult<C> }
@@ -524,3 +524,35 @@ await sync.dispose();
524
524
  ```
525
525
 
526
526
  Local-sync provides browser durability and leadership. Keep network collaboration, server authorization, and distributed merge policy in a separate boundary.
527
+
528
+ ## Composable input commands
529
+
530
+ ```ts
531
+ const count = input(0);
532
+ const doubled = derive({ count }, ({ count }) => count * 2);
533
+ function increment() {
534
+ runtime.update(count, runtime.read(count) + 1);
535
+ }
536
+ runtime.batch(() => {
537
+ increment();
538
+ increment();
539
+ });
540
+ ```
541
+
542
+ For a command spanning independent inputs, use ordinary `runtime.read` and `runtime.update`. Wrap the whole action in `runtime.batch(() => ...)` when it needs a single net notification boundary. Current reads also work for derived projections and may advance their dependencies. Use collection drafts for selection edits. Do not maintain an input mirror or manually synchronize derived values. A failed step does not undo earlier accepted steps.
543
+
544
+ ## Ordered child records and validation errors
545
+
546
+ ```ts
547
+ const lines = derive.keyed.flatMap(orders, order =>
548
+ order.lines.map(line => [line.id, line] as const)
549
+ );
550
+ const errors = derive.keyed.flatMap(forms, { rules }, (form, formId, dependencies) =>
551
+ validateForm(form, dependencies.rules).map(
552
+ error => [JSON.stringify([formId, error.fieldId, error.code]), error] as const
553
+ )
554
+ );
555
+ const labels = derive.keyed(lines, line => line.label);
556
+ ```
557
+
558
+ Choose globally unique child IDs or an unambiguous composite encoding. A parent-based composite key intentionally changes identity when its parent changes. Duplicate final keys fail rather than overwrite. Use `[]` for no children and `[key, undefined]` for a present undefined child. For retained R-tree/search-index state, continue using advanced processors rather than building state into a flatMap selector.