doxum 0.1.26 → 0.1.28

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.
Files changed (39) hide show
  1. package/README.md +86 -3
  2. package/dist/advanced.cjs +40 -30
  3. package/dist/advanced.cjs.map +1 -1
  4. package/dist/advanced.d.cts +34 -2
  5. package/dist/advanced.d.ts +34 -2
  6. package/dist/advanced.js +31 -22
  7. package/dist/advanced.js.map +1 -1
  8. package/dist/{definition-xgk3YNBp.d.ts → dependency-B3E65M1E.d.cts} +27 -3
  9. package/dist/{definition-CDOuvb5C.d.cts → dependency-BYbdDHNa.d.ts} +27 -3
  10. package/dist/driver-B5vdPohL.js.map +1 -1
  11. package/dist/driver-BL91gn7_.cjs.map +1 -1
  12. package/dist/index.cjs +885 -394
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +33 -18
  15. package/dist/index.d.ts +33 -18
  16. package/dist/index.js +784 -293
  17. package/dist/index.js.map +1 -1
  18. package/dist/local-sync.cjs.map +1 -1
  19. package/dist/local-sync.js.map +1 -1
  20. package/dist/transform-B4T3AcJr.js +938 -0
  21. package/dist/transform-B4T3AcJr.js.map +1 -0
  22. package/dist/transform-DUleAsG0.cjs +1105 -0
  23. package/dist/transform-DUleAsG0.cjs.map +1 -0
  24. package/package.json +1 -1
  25. package/skills/doxum-runtime/SKILL.md +16 -6
  26. package/skills/doxum-runtime/references/api.en.md +49 -15
  27. package/skills/doxum-runtime/references/api.zh-CN.md +47 -13
  28. package/skills/doxum-runtime/references/guide.en.md +2 -1
  29. package/skills/doxum-runtime/references/guide.zh-CN.md +2 -1
  30. package/skills/doxum-runtime/references/invariants.en.md +2 -2
  31. package/skills/doxum-runtime/references/invariants.zh-CN.md +2 -2
  32. package/skills/doxum-runtime/references/patterns.en.md +1 -1
  33. package/skills/doxum-runtime/references/patterns.zh-CN.md +1 -1
  34. package/skills/doxum-runtime/references/projections.en.md +77 -4
  35. package/skills/doxum-runtime/references/projections.zh-CN.md +74 -3
  36. package/dist/scheduler--137L3j-.js +0 -500
  37. package/dist/scheduler--137L3j-.js.map +0 -1
  38. package/dist/scheduler-D4VthaaK.cjs +0 -589
  39. package/dist/scheduler-D4VthaaK.cjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform-DUleAsG0.cjs","names":["isPlainObject","isPlainObject"],"sources":["../core/src/profile.ts","../core/src/projection/definition.ts","../core/src/projection/collection/view.ts","../core/src/projection/dependency.ts","../core/src/projection/collection/change.ts","../core/src/projection/contract.ts","../core/src/projection/graph/scheduler.ts","../core/src/projection/keyed/relation.ts","../core/src/projection/keyed/dependency.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 get: key => value.get(key),\n has: key => value.has(key),\n ids: () => Object.freeze([...value.keys()]),\n});\n\n/** Immutable map-like view over a CollectionRead. */\nexport const collectionView = <K extends string, V>(\n read: CollectionRead<K, V>\n): ReadonlyMap<K, V> => {\n const ids = read.ids();\n const entries = function* (): IterableIterator<[K, V]> {\n for (const key of ids) yield [key, read.get(key) as V];\n };\n const values = function* (): IterableIterator<V> {\n for (const key of ids) yield read.get(key) as V;\n };\n const view: ReadonlyMap<K, V> = {\n get: key => read.get(key),\n has: key => read.has(key),\n get size() {\n return ids.length;\n },\n keys: () => ids[Symbol.iterator](),\n values,\n entries,\n forEach: (callback, thisArg) => {\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));\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 { CollectionChange } from '@/projection/contract';\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 commonOrderChanged = <K extends string>(\n before: readonly K[],\n after: readonly K[],\n added: ReadonlySet<K>,\n removed: ReadonlySet<K>\n): boolean => {\n const beforeCommon = before.filter(key => !removed.has(key));\n const afterCommon = after.filter(key => !added.has(key));\n return beforeCommon.some((key, index) => afterCommon[index] !== key);\n};\n\n/** Builds the canonical incremental CollectionChange from already-known net transitions. */\nexport const createCollectionChange = <K extends string, V>(input: {\n readonly added: readonly Added<K, V>[];\n readonly updated: readonly Updated<K, V>[];\n readonly removed: readonly Removed<K, V>[];\n readonly beforeOrder: readonly K[];\n readonly afterOrder: readonly K[];\n}): CollectionChange<K, V> | undefined => {\n const addedKeys = new Set(input.added.map(entry => entry.key));\n const removedKeys = new Set(input.removed.map(entry => entry.key));\n const orderChanged =\n input.beforeOrder !== input.afterOrder &&\n commonOrderChanged(input.beforeOrder, input.afterOrder, addedKeys, removedKeys);\n if (!input.added.length && !input.updated.length && !input.removed.length && !orderChanged)\n return undefined;\n return Object.freeze({\n kind: 'incremental' as const,\n added: Object.freeze([...input.added]),\n updated: Object.freeze([...input.updated]),\n removed: Object.freeze([...input.removed]),\n ...(orderChanged\n ? {\n order: Object.freeze({\n before: Object.freeze([...input.beforeOrder]),\n after: Object.freeze([...input.afterOrder]),\n }),\n }\n : {}),\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 return createCollectionChange({\n added,\n updated,\n removed,\n beforeOrder: [...previous.keys()],\n afterOrder: [...current.keys()],\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","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): SourceContext;\n current(): unknown;\n revision(): number;\n reset(): boolean;\n subscribe(listener: OutputListener): Unsubscribe;\n emit(call: (listener: OutputListener, change?: CollectionChange<string, unknown>) => void): 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 readonly order: number;\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' | '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 heap: ProcessorRecord[] = [];\n const queued = new Set<ProcessorRecord>();\n const completed = new Set<ProcessorRecord>();\n const emissions = 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('Projection cannot be re-entered during processing or notification.');\n };\n const lock = (value: boolean) => guards.forEach(guard => guard(value));\n\n const enqueue = (processor: ProcessorRecord) => {\n if (processor.disposed || queued.has(processor)) return;\n queued.add(processor);\n profile.projection('scheduledNodes');\n let index = heap.length;\n heap.push(processor);\n while (index > 0) {\n const parent = (index - 1) >> 1;\n if (heap[parent].order < processor.order) break;\n heap[index] = heap[parent];\n index = parent;\n }\n heap[index] = processor;\n };\n\n const pop = (): ProcessorRecord => {\n const first = heap[0];\n const last = heap.pop()!;\n if (heap.length) {\n let index = 0;\n while (index * 2 + 1 < heap.length) {\n let child = index * 2 + 1;\n if (child + 1 < heap.length && heap[child + 1].order < heap[child].order) child++;\n if (last.order < heap[child].order) break;\n heap[index] = heap[child];\n index = child;\n }\n heap[index] = last;\n }\n return first;\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 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 settle = () => {\n if (disposed || depth || phase !== 'idle') return;\n phase = 'compute';\n lock(true);\n const cause = settleCause();\n try {\n for (const source of pendingSources) {\n if (source.disposed) continue;\n const wasFaulted = source.fault !== undefined;\n let changed = false;\n let force = false;\n if (!source.fault || source.recovering()) {\n try {\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 const recovered = wasFaulted && !source.fault;\n if (changed) source.publish();\n if (source.fault || changed || force || recovered) {\n const output = source.outputs[0];\n emissions.add(output);\n output.forEachConsumer(enqueue);\n }\n }\n\n while (heap.length) {\n const processor = pop();\n if (processor.disposed) continue;\n const wasFaulted = processor.fault !== undefined;\n profile.projection('processedNodes');\n let changedOutputs: readonly OutputRecord[] = Object.freeze([]);\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());\n try {\n changedOutputs = processor.evaluate(reset, cause, wasFaulted);\n const dependencyFailure = processor.dependencies.find(output => output.owner.fault)\n ?.owner.fault;\n if (dependencyFailure) throw dependencyFailure;\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 const recovered = wasFaulted && !processor.fault;\n if (processor.fault) {\n processor.outputs.forEach(output => {\n emissions.add(output);\n output.forEachConsumer(enqueue);\n });\n } else {\n if (changedOutputs.length) {\n processor.publish();\n changedOutputs.forEach(output => emissions.add(output));\n }\n const propagated = recovered ? processor.outputs : changedOutputs;\n propagated.forEach(output => output.forEachConsumer(enqueue));\n }\n if (processor.fault || changedOutputs.length) {\n profile.projection('publishedNodes');\n }\n }\n } finally {\n lock(false);\n phase = 'idle';\n }\n };\n\n const flush = (): readonly ObserverError[] => {\n if (disposed || depth) return [];\n if (pendingSources.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((listener, change) => {\n try {\n listener(change);\n } catch (cause) {\n errors.push(errorFor(output.owner, cause, 'listener'));\n }\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 pendingSources.forEach(source => source.clear());\n completed.forEach(processor => processor.clear());\n pendingSources.clear();\n queued.clear();\n completed.clear();\n emissions.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 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 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 order: () => sequence++,\n initialize<T>(callback: () => T): T {\n assertIdle();\n phase = 'compute';\n lock(true);\n try {\n return callback();\n } finally {\n lock(false);\n phase = 'idle';\n }\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 heap.length = 0;\n queued.clear();\n completed.clear();\n emissions.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","export type KeyRelation = {\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 replace(left, right) {\n const previous = forward.get(left) ?? Object.freeze([]);\n if (previous.length === right.length && previous.every((key, index) => key === right[index]))\n return false;\n detach(left, previous);\n if (!right.length) {\n forward.delete(left);\n return true;\n }\n const next = Object.freeze([...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 { collectionChange } from '@/projection/collection/change';\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 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 | 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\nexport type KeyedDependencies<DriverKey extends string, DriverValue, D extends object> = {\n readonly [P in keyof D]: P extends string ? KeyedDependency<DriverKey, DriverValue> : 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: '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(\n `${label} dependencies must be projections or singular/plural keyed lookups.`\n );\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(\n `${label} dynamic keyed dependency must declare exactly one of key or keys.`\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 assertKeyedProjection(candidate.source, `${label} dynamic keyed dependency source`);\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 selectedKeys = (\n dependency: CompiledDynamicKeyedDependency,\n value: unknown,\n key: string\n): readonly string[] => {\n const result = dependency.select(value, key);\n assertSynchronous(result);\n if (dependency.kind === 'one') {\n if (result === undefined) return Object.freeze([]);\n if (typeof result !== 'string')\n throw new TypeError('Dynamic keyed dependency key must be a string or undefined.');\n return Object.freeze([result]);\n }\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 const keys: 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 keys.push(selected);\n }\n return Object.freeze(keys);\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 DynamicDependencyState = {\n readonly kind: 'dynamic';\n readonly entry: Exclude<CompiledKeyedDependency, { readonly kind: 'global' }>;\n readonly sourceIndex: number;\n readonly relation: KeyRelation;\n revision: number;\n };\n type DependencyState = GlobalDependencyState | DynamicDependencyState;\n const states: DependencyState[] = compiled.entries.map((entry, index) =>\n entry.kind === 'global'\n ? { kind: 'global', entry, sourceIndex: index + 1, revision: -1, globalValue: undefined }\n : {\n kind: 'dynamic',\n entry,\n sourceIndex: index + 1,\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 dependency = state.entry;\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 const keys = selectedKeys(dependency, driverValue, driverKey);\n state.relation.replace(driverKey, keys);\n if (dependency.kind === 'one') {\n const selected = keys[0];\n values[dependency.name] = selected === undefined ? undefined : source.read.get(selected);\n continue;\n }\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 const dependency = state.entry;\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 for (const sourceKey of collectionChange.keys(source.change))\n for (const dependent of state.relation.reverse(sourceKey) ?? []) 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 state.relation.clear();\n }\n driverRevision = -1;\n },\n };\n};\n","import type { CollectionRead, SourceContext } from '@/projection/contract';\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 dependencies.prepare(evaluation.sources, evaluation.reset);\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 (evaluation.reset) {\n dependencies.clearBindings();\n const ids = driver.read.ids();\n const present = new Set(ids);\n for (const key of [...states.keys()]) if (!present.has(key)) states.delete(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 const dirty = new Set<string>();\n let all = false;\n let updateOrder = false;\n let membershipChanged = false;\n if (dependencies.driverChanged(driver)) {\n const change = driver.change;\n if (!change || change.kind === 'reset') {\n all = true;\n updateOrder = true;\n for (const key of output.previous.ids()) {\n if (driver.read.has(key)) continue;\n output.output.remove(key);\n dropState(key);\n membershipChanged = true;\n }\n } else {\n for (const entry of change.removed) {\n membershipChanged ||= output.previous.has(entry.key);\n output.output.remove(entry.key);\n dropState(entry.key);\n dirty.delete(entry.key);\n }\n for (const entry of change.added) dirty.add(entry.key);\n for (const entry of change.updated) dirty.add(entry.key);\n updateOrder = Boolean(change.order);\n }\n }\n\n all ||= dependencies.collectInvalidated(evaluation.sources, dirty);\n if (all) for (const key of driver.read.ids()) dirty.add(key);\n for (const key of dirty) {\n const changedMembership = project(key);\n membershipChanged ||= changedMembership;\n }\n if (updateOrder || 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.26",
3
+ "version": "0.1.28",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "description": "Doxum is a typed runtime for complex mutable documents.",
@@ -47,20 +47,30 @@ Before runtime changes read [invariants](references/invariants.en.md) or
47
47
  `KeyedProjection<K,V>` is the single public keyed projection handle. Collection
48
48
  `observe`, `derive.keyed`, `incremental.collection`, group collection leaves and
49
49
  `CollectionInput<K,V>` all use that same keyed capability.
50
- Use named-object `derive` for pure aggregate values. Use `derive.keyed` when one keyed
51
- driver owns the output key domain/order: per-entry equality suppresses unchanged
52
- selected values. Its dependency form uses a named object: plain Projection members
53
- invalidate the driver key set, while `{ source, key }` members let the Runtime own
54
- per-output-key source bindings and reverse lookup. Selectors receive
50
+ Use named-object `derive` for pure aggregate values. The `derive.keyed` family owns
51
+ keyed derivation: ordinary `derive.keyed` preserves driver membership/order;
52
+ `keys`/`values`/`entries` expose standard ordered read shapes; `get` is the precise
53
+ scalar keyed lookup; `subset`/`filter`/`compact` own membership-changing derivation;
54
+ `groupBy` is the generic reverse-index primitive and `singleton` is optional-scalar
55
+ to 0/1 keyed composition.
56
+ Per-entry equality suppresses unchanged generated values. Its dependency form uses a named object: plain Projection members
57
+ invalidate the driver key set, while `{ source, key }` / `{ source, keys }` members let the Runtime own
58
+ singular/plural per-output-key source bindings and reverse lookup. Selectors receive
55
59
  `(entry, key)` or `(entry, key, dependencies)`. The producer graph remains explicit and static;
56
60
  processors never perform imperative Runtime reads to discover dependencies.
61
+ Use `runtime.items(keyedProjection)` / `scope.items(...)` for Runtime-owned ordered
62
+ membership plus stable per-membership item Readables; do not rebuild that cache in adapters.
57
63
  `input.collection` edits have a strong exception boundary: callback or per-entry
58
64
  equality failure leaves both the published value and the next draft unchanged.
59
65
  A `ProjectionScope` only adds lifecycle ownership through `scope.own(...)`; create
60
66
  definitions with the root declaration APIs, then own a projection or static output tree
61
67
  before that definition is first materialized as a root.
62
68
  Use advanced `incremental` only for retained state or cross-key coordination that
63
- cannot be expressed by `derive.keyed`. React selector tracking remains a consumer
69
+ cannot be expressed by the `derive.keyed` family. `incremental.keyed` owns independent
70
+ per-driver-key retained state while preserving driver membership/order and reuses the
71
+ same dynamic keyed dependency routing. `collectionChange.keys` is the
72
+ transport-level iterable for incremental added/updated/removed keys; callers handle
73
+ reset and order semantics themselves. React selector tracking remains a consumer
64
74
  concern through `ProjectionProvider` and `useProjection(projection, selector)`.
65
75
  - Advanced incremental definitions always declare `process`; `state()` is present only
66
76
  when retained state is actually needed. `incremental.group` declares its static
@@ -105,22 +105,38 @@ const rows = observe(document, path => path.rows);
105
105
  const count = derive({ rows }, ({ rows }) => rows.size);
106
106
  ```
107
107
 
108
- | API | Contract |
109
- | ----------------------------------------------- | ------------------------------------------------------------------- |
110
- | `input(initial, equality?)` | Runtime-local writable scalar `Input<T>`. |
111
- | `input.collection<K,V>(initial?, equality?)` | Runtime-local keyed `CollectionInput<K,V>` with per-entry equality. |
112
- | `observe(document)` | Whole-document Projection source. |
113
- | `observe(document, path => ...)` | Schema-path scalar or keyed Projection source. |
114
- | `observe(readable)` | Adapt a Doxum `Readable`. |
115
- | `observe(externalSource)` | Adapt exported external value/collection source contracts. |
116
- | `derive(dependencies, compute, equality?)` | Pure value Projection with named dependencies. |
117
- | `derive.keyed(driver, select, equality?)` | Preserve driver keys/order and project each entry. |
118
- | `derive.keyed(driver, deps, select, equality?)` | Keyed projection with named global/dynamic keyed dependencies. |
108
+ | API | Contract |
109
+ | ------------------------------------------------------- | -------------------------------------------------------------------- |
110
+ | `input(initial, equality?)` | Runtime-local writable scalar `Input<T>`. |
111
+ | `input.collection<K,V>(initial?, equality?)` | Runtime-local keyed `CollectionInput<K,V>` with per-entry equality. |
112
+ | `observe(document)` | Whole-document Projection source. |
113
+ | `observe(document, path => ...)` | Schema-path scalar or keyed Projection source. |
114
+ | `observe(readable)` | Adapt a Doxum `Readable`. |
115
+ | `observe(externalSource)` | Adapt exported external value/collection source contracts. |
116
+ | `derive(dependencies, compute, equality?)` | Pure value Projection with named dependencies. |
117
+ | `derive.keyed(driver, select, equality?)` | Preserve driver keys/order and project each entry. |
118
+ | `derive.keyed(driver, deps, select, equality?)` | Keyed projection with named global/dynamic keyed dependencies. |
119
+ | `derive.keyed.keys(source)` | Ordered key array; value-only updates do not publish. |
120
+ | `derive.keyed.values(source)` | Ordered value array following keyed collection order. |
121
+ | `derive.keyed.entries(source)` | Ordered readonly `[key, value]` tuples with stable unchanged tuples. |
122
+ | `derive.keyed.get(source, key, equality?)` | Scalar lookup bound precisely to the selected keyed entry. |
123
+ | `derive.keyed.subset(source, orderedKeys)` | Keyed subset whose membership/order come from ordered keys. |
124
+ | `derive.keyed.filter(source, predicate)` | Keyed subset preserving source values and source-relative order. |
125
+ | `derive.keyed.filter(source, deps, predicate)` | Filter with the standard keyed dependency protocol. |
126
+ | `derive.keyed.compact(source, select, equality?)` | Map entries and omit keys whose selected value is `undefined`. |
127
+ | `derive.keyed.compact(source, deps, select, equality?)` | Compact with standard keyed dependencies. |
128
+ | `derive.keyed.groupBy(source, selector)` | Reverse index from group key to source keys in formal source order. |
129
+ | `derive.keyed.groupBy(source, deps, selector)` | Reverse index with the standard keyed dependency protocol. |
130
+ | `derive.keyed.singleton(source, keyOf, equality?)` | Convert an optional scalar to a zero-or-one keyed projection. |
119
131
 
120
132
  Dynamic keyed dependency syntax is
121
133
  `{ source: keyedProjection, key: (driverValue, driverKey) => sourceKey | undefined }`.
122
134
  The Runtime owns output-key to source-key bindings and reverse invalidation. This helper
123
135
  shape is inferred at the call site; no dedicated public helper type is required.
136
+ Plural lookup uses
137
+ `{ source: keyedProjection, keys: (driverValue, driverKey) => readonly sourceKey[] }`.
138
+ The array must be duplicate-free and ordered. The dependency value is a readonly map of
139
+ currently present selected entries in that order; missing selected keys remain bound.
124
140
  Keyed selectors keep stable leading arguments: `(value, key)` without extra dependencies
125
141
  and `(value, key, dependencies)` when the named dependency object is present.
126
142
 
@@ -128,6 +144,7 @@ and `(value, key, dependencies)` when the named dependency object is present.
128
144
 
129
145
  - `read(projection)`;
130
146
  - `select(projection)` and `select(projection, selector, equality?)`;
147
+ - `items(keyedProjection)` for ordered keys plus stable per-membership item Readables;
131
148
  - `update(input, nextValue)` for scalar `Input<T>`;
132
149
  - `update(collectionInput, draft => ...)` for `CollectionInput<K,V>`;
133
150
  - `batch(run, { cause? }?)`;
@@ -139,8 +156,8 @@ state is installed. If either throws, the published collection and the next draf
139
156
  remain at the pre-update state.
140
157
 
141
158
  `CollectionInputDraft` exposes `get`, `has`, `set`, `remove`. A throwing edit callback
142
- applies none of that edit. `ProjectionScope` mirrors `read`, `select`, `update`, `batch`,
143
- `dispose` and adds `own(projectionOrTree)` for lifecycle ownership of scalar/keyed inputs,
159
+ applies none of that edit. `ProjectionScope` mirrors `read`, `select`, `items`, `update`,
160
+ `batch`, `dispose` and adds `own(projectionOrTree)` for lifecycle ownership of scalar/keyed inputs,
144
161
  derives and advanced output trees. One definition can belong to only one scope; call
145
162
  `own` before that definition is first materialized as a root.
146
163
 
@@ -151,6 +168,10 @@ Public projection types are `Projection<T>`, `KeyedProjection<K,V>`, `Input<T>`,
151
168
  `ProjectionError` exposes only `phase` and `cause`;
152
169
  `ProjectionDisposedError` represents disposed access.
153
170
 
171
+ `filter` and `subset` reuse source values and therefore do not take a second equality.
172
+ `compact` owns membership through `undefined` while ordinary `derive.keyed` continues
173
+ to preserve every driver key, including when its selected value is `undefined`.
174
+
154
175
  External value sources expose `kind: 'value'`, `current()`, `revision()`, `subscribe()`.
155
176
  External collection sources expose `kind: 'collection'` plus `get/has/ids` reads and
156
177
  optional `CollectionImpact` invalidation hints; the adapter derives exact
@@ -161,6 +182,10 @@ optional `CollectionImpact` invalidation hints; the adapter derives exact
161
182
  Use advanced processors only when `derive` / `derive.keyed` cannot express retained
162
183
  state, cross-key indexes, or direct incremental output patching.
163
184
 
185
+ `collectionChange.keys(change)` iterates the added, updated and removed keys of an
186
+ incremental `CollectionChange` in that order. It does not interpret reset or order
187
+ changes; handle `reset` before calling it.
188
+
164
189
  All advanced functions use named dependencies and a closed definition object.
165
190
 
166
191
  ```ts
@@ -177,6 +202,15 @@ const total = incremental(
177
202
  `next`, and borrowed `output` with `set`, `remove`, `order`. `state()` is declared only
178
203
  when retained state is needed; stateless process contexts do not contain `state`.
179
204
 
205
+ `incremental.keyed(driver, dependencies, { process, state?, equality? })` preserves the
206
+ driver's membership/order and owns independent retained state per current driver key.
207
+ Ordinary dependencies invalidate all driver keys; singular/plural keyed dependencies use
208
+ reverse routing. Order-only driver changes do not run `process`. Removal releases one
209
+ key's state, re-add starts a new membership lifecycle, reset intersections retain state,
210
+ and processor recovery recreates all per-key state. The process context contains `key`,
211
+ `value`, named `dependencies`, `reset`, `cause`, and optional `state`; it returns only the
212
+ value for its own output key and receives no collection draft.
213
+
180
214
  `incremental.group(dependencies, { output, process, state? })` declares several leaves:
181
215
 
182
216
  ```ts
@@ -203,8 +237,8 @@ Runtime owns recovery: it recreates declared state and runs a reset evaluation.
203
237
  processors use the same recovery path without a state object. There is no public rebuild
204
238
  token or manual recovery protocol.
205
239
 
206
- Exported advanced helper types are the value/collection/group context and definition
207
- types, `CollectionChange`, and the declaration-safe `IncrementalGroupOutput` /
240
+ Exported advanced APIs include `collectionChange`, the value/collection/keyed/group context
241
+ and definition types, `CollectionChange`, and the declaration-safe `IncrementalGroupOutput` /
208
242
  `IncrementalGroupResult` type boundaries. Normal callers infer the latter two; internal
209
243
  scheduler/output plumbing is not part of the public contract.
210
244
 
@@ -103,22 +103,38 @@ const rows = observe(document, path => path.rows);
103
103
  const count = derive({ rows }, ({ rows }) => rows.size);
104
104
  ```
105
105
 
106
- | API | 契约 |
107
- | ----------------------------------------------- | -------------------------------------------------------------------- |
108
- | `input(initial, equality?)` | Runtime-local writable scalar `Input<T>`。 |
109
- | `input.collection<K,V>(initial?, equality?)` | Runtime-local keyed `CollectionInput<K,V>`,equality 按 entry 比较。 |
110
- | `observe(document)` | whole-document Projection source。 |
111
- | `observe(document, path => ...)` | schema-path scalar 或 keyed Projection source。 |
112
- | `observe(readable)` | 接入 Doxum `Readable`。 |
113
- | `observe(externalSource)` | 接入公开 external value/collection source contract。 |
114
- | `derive(dependencies, compute, equality?)` | named dependencies 的 pure value Projection。 |
115
- | `derive.keyed(driver, select, equality?)` | 保留 driver key/order,逐 entry projection。 |
116
- | `derive.keyed(driver, deps, select, equality?)` | 带 named global/dynamic keyed dependencies 的 keyed projection。 |
106
+ | API | 契约 |
107
+ | ------------------------------------------------------- | -------------------------------------------------------------------- |
108
+ | `input(initial, equality?)` | Runtime-local writable scalar `Input<T>`。 |
109
+ | `input.collection<K,V>(initial?, equality?)` | Runtime-local keyed `CollectionInput<K,V>`,equality 按 entry 比较。 |
110
+ | `observe(document)` | whole-document Projection source。 |
111
+ | `observe(document, path => ...)` | schema-path scalar 或 keyed Projection source。 |
112
+ | `observe(readable)` | 接入 Doxum `Readable`。 |
113
+ | `observe(externalSource)` | 接入公开 external value/collection source contract。 |
114
+ | `derive(dependencies, compute, equality?)` | named dependencies 的 pure value Projection。 |
115
+ | `derive.keyed(driver, select, equality?)` | 保留 driver key/order,逐 entry projection。 |
116
+ | `derive.keyed(driver, deps, select, equality?)` | 带 named global/dynamic keyed dependencies 的 keyed projection。 |
117
+ | `derive.keyed.keys(source)` | 正式顺序的 key array;value-only update 不发布。 |
118
+ | `derive.keyed.values(source)` | 按 keyed collection 正式顺序排列的 value array。 |
119
+ | `derive.keyed.entries(source)` | 正式顺序的 readonly `[key, value]` tuple,未变化 tuple 保持引用。 |
120
+ | `derive.keyed.get(source, key, equality?)` | 精确绑定当前 selected key 的 scalar lookup。 |
121
+ | `derive.keyed.subset(source, orderedKeys)` | membership/order 由 ordered keys 决定的 keyed subset。 |
122
+ | `derive.keyed.filter(source, predicate)` | 保留 source value 与 source-relative order 的 keyed filter。 |
123
+ | `derive.keyed.filter(source, deps, predicate)` | 使用标准 keyed dependency protocol 的 filter。 |
124
+ | `derive.keyed.compact(source, select, equality?)` | map entry,并省略 selected value 为 `undefined` 的 key。 |
125
+ | `derive.keyed.compact(source, deps, select, equality?)` | 使用标准 keyed dependencies 的 compact。 |
126
+ | `derive.keyed.groupBy(source, selector)` | group key → source keys 的 reverse index,成员遵循 source 正式顺序。 |
127
+ | `derive.keyed.groupBy(source, deps, selector)` | 使用标准 keyed dependency protocol 的 reverse index。 |
128
+ | `derive.keyed.singleton(source, keyOf, equality?)` | optional scalar → 0/1 keyed projection。 |
117
129
 
118
130
  动态 keyed dependency 写法为
119
131
  `{ source: keyedProjection, key: (driverValue, driverKey) => sourceKey | undefined }`。
120
132
  Runtime 拥有 output-key → source-key binding 和 reverse invalidation。这个 helper shape
121
133
  在调用点自动推断,不暴露独立 public helper type。
134
+ plural lookup 使用
135
+ `{ source: keyedProjection, keys: (driverValue, driverKey) => readonly sourceKey[] }`。
136
+ 返回数组必须有序且无重复;dependency value 是按该顺序包含当前存在 selected entry 的
137
+ readonly map。缺失 key 仍保留 reverse binding,后续 add 会使 dependent driver key 失效。
122
138
  keyed selector 的前置参数固定:无额外 dependency 时为 `(value, key)`;存在 named
123
139
  dependency object 时为 `(value, key, dependencies)`。
124
140
 
@@ -126,6 +142,7 @@ dependency object 时为 `(value, key, dependencies)`。
126
142
 
127
143
  - `read(projection)`;
128
144
  - `select(projection)`、`select(projection, selector, equality?)`;
145
+ - `items(keyedProjection)`:有序 keys + membership 生命周期稳定的逐 key Readable;
129
146
  - `update(input, nextValue)`:写 scalar `Input<T>`;
130
147
  - `update(collectionInput, draft => ...)`:写 `CollectionInput<K,V>`;
131
148
  - `batch(run, { cause? }?)`;
@@ -136,7 +153,7 @@ dependency object 时为 `(value, key, dependencies)`。
136
153
  任一环节抛错时,已发布 collection 与下一次 draft 都保持更新前状态。
137
154
 
138
155
  `CollectionInputDraft` 提供 `get`、`has`、`set`、`remove`。edit callback throw 时该次 edit
139
- 整体不应用。`ProjectionScope` 镜像 `read`、`select`、`update`、`batch`、`dispose`,
156
+ 整体不应用。`ProjectionScope` 镜像 `read`、`select`、`items`、`update`、`batch`、`dispose`,
140
157
  并增加 `own(projectionOrTree)`,统一拥有 scalar/keyed input、derive 与 advanced output
141
158
  tree 的 lifecycle。同一个 definition 只能属于一个 scope,并且必须在该 definition
142
159
  首次作为 root materialize 之前调用 `own`。
@@ -148,6 +165,10 @@ tree 的 lifecycle。同一个 definition 只能属于一个 scope,并且必
148
165
  `ProjectionError` 只公开 `phase` 与 `cause`;
149
166
  `ProjectionDisposedError` 表达 disposed access。
150
167
 
168
+ `filter` / `subset` 直接复用 source value,因此没有第二个 equality 参数。
169
+ `compact` 用 `undefined` 表达 membership 缺失;普通 `derive.keyed` 仍保留所有 driver key,
170
+ 即使 selected value 本身为 `undefined`。
171
+
151
172
  External value source 提供 `kind: 'value'`、`current()`、`revision()`、`subscribe()`。
152
173
  External collection source 提供 `kind: 'collection'` 和 `get/has/ids` read,可给
153
174
  `CollectionImpact` invalidation hint;adapter 会导出精确 `CollectionChange`。
@@ -157,6 +178,10 @@ External collection source 提供 `kind: 'collection'` 和 `get/has/ids` read,
157
178
  只有 retained state、cross-key index 或直接 incremental patch 无法用
158
179
  `derive` / `derive.keyed` 清晰表达时才使用 advanced processor。
159
180
 
181
+ `collectionChange.keys(change)` 按 added → updated → removed 遍历 incremental
182
+ `CollectionChange` 的 entry-transition keys。它不解释 reset,也不会把 order change
183
+ 扩展成所有 keys;调用前由业务代码先处理 `reset`。
184
+
160
185
  所有 advanced API 都使用 named dependencies + closed definition object。
161
186
 
162
187
  ```ts
@@ -173,6 +198,15 @@ const total = incremental(
173
198
  `previous`、`next` 和 borrowed `output`;output 有 `set`、`remove`、`order`。只有确实
174
199
  需要 retained state 时才声明 `state()`;无状态 process context 不包含 `state`。
175
200
 
201
+ `incremental.keyed(driver, dependencies, { process, state?, equality? })` 保留 driver
202
+ membership/order,并为每个当前 driver key 独立拥有 retained state。普通 dependency
203
+ 变化使所有当前 driver key 失效;singular/plural keyed dependency 通过 reverse routing
204
+ 只运行真正依赖的 key。driver 仅 order 变化不会执行 `process`。remove 释放该 key state,
205
+ 同 key re-add 进入新的 membership lifecycle;reset intersection 保留 state,processor
206
+ fault recovery 会重建全部 per-key state。process context 包含 `key`、`value`、named
207
+ `dependencies`、`reset`、`cause` 和可选 `state`,返回当前 output key 的值,不暴露
208
+ collection draft。
209
+
176
210
  `incremental.group(dependencies, { output, process, state? })` 声明多个 leaf:
177
211
 
178
212
  ```ts
@@ -198,7 +232,7 @@ const view = incremental.group(
198
232
  拥有:重新创建已声明的 state,再执行 reset evaluation;stateless processor 走同一恢复
199
233
  路径但没有 state object。没有公开 rebuild token 或手工恢复协议。
200
234
 
201
- advanced 导出 value/collection/group 的 context/definition 类型、`CollectionChange`,
235
+ advanced 导出 `collectionChange`、value/collection/keyed/group 的 context/definition 类型、`CollectionChange`,
202
236
  以及声明可移植性所需的 `IncrementalGroupOutput` / `IncrementalGroupResult` 类型边界。
203
237
  普通调用方通常只依赖推导;scheduler/output runtime plumbing 不属于公开 API。
204
238
 
@@ -105,7 +105,8 @@ lazy and materialized by one `createProjectionRuntime({ onError })` owner. When
105
105
  keyed source determines output keys/order, map entries independently with
106
106
  `derive.keyed(entries, entry => entry.label)`. Dynamic keyed lookup stays in that
107
107
  same derivation through a named dependency object; plain Projection members are
108
- global dependencies and `{ source, key }` members are per-output-key lookups. The
108
+ global dependencies, `{ source, key }` members are singular per-output-key lookups,
109
+ and `{ source, keys }` members are ordered plural lookups. The
109
110
  selector receives `(entry, key, dependencies)`, while the Runtime owns the
110
111
  binding/reverse index and the producer DAG remains explicit. Use isolated
111
112
  `doxum/advanced` incremental entry points only for retained state, custom cross-key
@@ -91,7 +91,8 @@ observerErrors 属于已提交结果。
91
91
  `createProjectionRuntime({ onError })` owner 物化和管理。当一个 keyed source 决定
92
92
  output key/order 时,用 `derive.keyed(entries, entry => entry.label)` 独立映射每个
93
93
  entry;跨 collection 的动态 key lookup 继续在同一个 derivation 中用命名依赖对象声明:
94
- 普通 Projection 成员是全局依赖,`{ source, key }` 成员是逐 output key lookup,selector
94
+ 普通 Projection 成员是全局依赖,`{ source, key }` 是 singular lookup,`{ source, keys }`
95
+ 是有序 plural lookup,selector
95
96
  接收 `(entry, key, dependencies)`。Runtime 拥有 binding/reverse index,producer DAG
96
97
  仍保持显式。只有 `derive.keyed` 无法表达的 retained state、自定义跨 key index 或
97
98
  keyed patch 才放到隔离的 `doxum/advanced` incremental 入口。生命周期、draft、
@@ -40,8 +40,8 @@ implementation invariants that affect design and review decisions.
40
40
  reversible; remote commits invalidate history. Groups travel in one session.
41
41
  9. Projections declare producer sources and settle before listeners. The producer DAG
42
42
  remains static. `derive.keyed` declares extra sources in one named dependency object;
43
- `{ source, key }` members may bind each output key to a key in an explicitly declared
44
- keyed source. The materialized Runtime owns those bindings and reverse indexes,
43
+ `{ source, key }` members bind one source key and `{ source, keys }` members bind an
44
+ ordered duplicate-free set of source keys for each output key. The materialized Runtime owns those bindings and reverse indexes,
45
45
  including bindings to currently missing source entries. Processors do not create graph
46
46
  dependencies through imperative Runtime reads. A scope adds lifecycle ownership only
47
47
  through `scope.own`; scoped definitions may depend on root definitions, while root and
@@ -31,8 +31,8 @@
31
31
  8. apply 要求 expectedRevision,记录本地真实旧状态。本地 reset 可撤销,
32
32
  remote commit 使 history 失效;group 在单个 session 中旅行。
33
33
  9. projection 显式声明 producer source,先于监听结算,producer DAG 保持静态。
34
- `derive.keyed` 用一个命名依赖对象声明额外 source;其中 `{ source, key }` 成员可以
35
- 把每个 output key 绑定到已显式声明 keyed source 的某个 key。物化后的 Runtime
34
+ `derive.keyed` 用一个命名依赖对象声明额外 source;`{ source, key }` 为每个 output key
35
+ 绑定一个 source key,`{ source, keys }` 绑定有序且无重复的 source-key 集合。物化后的 Runtime
36
36
  拥有这些 binding 和 reverse index,包括当前尚不存在的 source entry。processor
37
37
  不通过 imperative Runtime read 创建图依赖。scope 只通过 `scope.own` 增加 lifecycle
38
38
  ownership;scoped definition 可以依赖 root definition,root 与 sibling scope 不能依赖
@@ -122,7 +122,7 @@ runtime.update(selection, draft => draft.set(rowId, true));
122
122
  ```
123
123
 
124
124
  Use named-object `derive` for aggregate values. Use `derive.keyed` when one keyed
125
- driver owns output keys/order. Its named dependency form handles dynamic keyed lookups;
125
+ driver owns output keys/order. Its named dependency form handles singular/plural dynamic keyed lookups;
126
126
  the Runtime owns the binding/reverse index. Use `input.collection` for Runtime-local
127
127
  keyed UI/application state rather than canonical document state.
128
128
 
@@ -120,7 +120,7 @@ runtime.update(selection, draft => draft.set(rowId, true));
120
120
  ```
121
121
 
122
122
  聚合值使用 named-object `derive`。一个 keyed driver 拥有 output key/order 时使用
123
- `derive.keyed`;named dependency form 负责 dynamic keyed lookup,binding/reverse
123
+ `derive.keyed`;named dependency form 负责 singular/plural dynamic keyed lookup,binding/reverse
124
124
  index 由 Runtime 拥有。`input.collection` 用于 Runtime-local 的 keyed UI/application
125
125
  state,不进入 canonical document state。
126
126