doxum 0.1.11 → 0.1.12

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 (33) hide show
  1. package/README.md +5 -0
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.d.cts +1 -1
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/{integration-BKgGuodm.cjs → integration-BShL68Nc.cjs} +2 -2
  7. package/dist/{integration-BKgGuodm.cjs.map → integration-BShL68Nc.cjs.map} +1 -1
  8. package/dist/{integration-VTZ3ICsO.js → integration-CWjttg7H.js} +2 -2
  9. package/dist/{integration-VTZ3ICsO.js.map → integration-CWjttg7H.js.map} +1 -1
  10. package/dist/integration.cjs +2 -2
  11. package/dist/integration.d.cts +1 -1
  12. package/dist/integration.d.ts +1 -1
  13. package/dist/integration.js +2 -2
  14. package/dist/react.cjs +29 -2
  15. package/dist/react.cjs.map +1 -1
  16. package/dist/react.d.cts +3 -2
  17. package/dist/react.d.ts +3 -2
  18. package/dist/react.js +29 -3
  19. package/dist/react.js.map +1 -1
  20. package/dist/{store-Bs0C0rNd.d.ts → store-2i8pYXqa.d.ts} +2 -1
  21. package/dist/{store-DHFXfWSz.js → store-7XBEcR8s.js} +6 -1
  22. package/dist/{store-DHFXfWSz.js.map → store-7XBEcR8s.js.map} +1 -1
  23. package/dist/{store-DU2u-qFH.cjs → store-DBv58dns.cjs} +6 -1
  24. package/dist/{store-DU2u-qFH.cjs.map → store-DBv58dns.cjs.map} +1 -1
  25. package/dist/{store-CJuwJl_K.d.cts → store-Ks80xWS_.d.cts} +2 -1
  26. package/package.json +1 -1
  27. package/skills/doxum-runtime/SKILL.md +3 -1
  28. package/skills/doxum-runtime/references/guide.en.md +4 -0
  29. package/skills/doxum-runtime/references/guide.zh-CN.md +3 -0
  30. package/skills/doxum-runtime/references/patterns.en.md +4 -1
  31. package/skills/doxum-runtime/references/patterns.zh-CN.md +3 -1
  32. package/skills/doxum-runtime/references/projections.en.md +9 -0
  33. package/skills/doxum-runtime/references/projections.zh-CN.md +8 -0
package/README.md CHANGED
@@ -223,6 +223,7 @@ const scaled = project({ count, zoom }, ({ count, zoom }) => count * zoom);
223
223
  const store = createProjectionStore({ onError: console.error });
224
224
  store.get(scaled);
225
225
  store.set(zoom, 2);
226
+ const title = store.item(titles, taskId); // Stable Readable<string | undefined>.
226
227
  ```
227
228
 
228
229
  Projection declarations are lazy and reusable. A `ProjectionStore` owns
@@ -237,6 +238,10 @@ keys, order dirtiness, commits and reset state.
237
238
  Ordinary mappers intentionally model only one-source, same-key transforms.
238
239
  Cross-collection relationships use an advanced collection processor with explicit,
239
240
  application-owned dependency indexes; processor reads are not tracked automatically.
241
+ For per-key observation, `store.item(collection, key)` returns a stable `Readable`
242
+ that only notifies for that key. React components use
243
+ `useProjectionItem(collection, key)`; unrelated keys and order-only changes do not
244
+ rerender the component.
240
245
 
241
246
  Processors settle before external listeners. `store.batch` defers graph
242
247
  settlement and projection notifications, but document commits/listeners remain
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_issue = require("./issue-DhrNdQNg.cjs");
3
- const require_store = require("./store-DU2u-qFH.cjs");
3
+ const require_store = require("./store-DBv58dns.cjs");
4
4
  const require_driver = require("./driver-xOIkwrB8.cjs");
5
5
  //#region core/src/history.ts
6
6
  const createHistory = (input) => {
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { $ as ObjectShape, D as snapshot, E as replace, F as ChangeSet, G as DocumentTreeNode, H as DocumentAnchor, I as MemberChange, K as DocumentTreeValue, L as ValueTransition, P as Change, Q as ObjectNode, S as DocumentImpact, T as Read, U as DocumentListConfig, V as DocumentAddress, W as DocumentNode, X as ListNode, Y as Infer, Z as MapNode, _ as Unsubscribe, _t as ParseError, a as DocumentDisposedError, at as TreeNode, b as MutationIssueCode, bt as parse, c as DocumentReentrancyError, ct as VariantShape, d as LocalHistory, dt as map, et as OptionalNode, f as ObserverError, ft as object, g as TransactionResult, gt as variant, h as TransactionRejected, ht as tree, i as DocumentDiagnostic, it as TableNode, l as DocumentRuntime, lt as field, mt as table, n as CommitSource, nt as ReadonlyValue, o as DocumentProblem, p as OperationResult, pt as optional, q as FieldNode, r as DocumentCommit, rt as SchemaPath, s as DocumentReadable, st as VariantNode, u as HistoryState, ut as list, v as Readable, vt as ParseIssue, w as Draft, x as CollectionImpact, y as MutationIssue, yt as Validator } from "./contract-DtGVSXSK.cjs";
2
- import { C as ProjectionDisposedError, S as project, _ as ProjectionSources, a as AdvancedCollectionSpec, b as ValueProjection, c as CollectionProjection, d as DocumentCollectionProjection, f as DocumentEvent, g as ProjectionEvents, h as Projection, i as AdvancedCollectionProcess, l as CollectionSource, m as InputProjection, n as createProjectionStore, o as AdvancedValueSpec, p as DocumentProjection, s as CollectionEvent, t as ProjectionStore, u as DocumentCollectionEvent, v as ProjectionValues, w as ProjectionError, x as input, y as ValueEvent } from "./store-CJuwJl_K.cjs";
2
+ import { C as ProjectionDisposedError, S as project, _ as ProjectionSources, a as AdvancedCollectionSpec, b as ValueProjection, c as CollectionProjection, d as DocumentCollectionProjection, f as DocumentEvent, g as ProjectionEvents, h as Projection, i as AdvancedCollectionProcess, l as CollectionSource, m as InputProjection, n as createProjectionStore, o as AdvancedValueSpec, p as DocumentProjection, s as CollectionEvent, t as ProjectionStore, u as DocumentCollectionEvent, v as ProjectionValues, w as ProjectionError, x as input, y as ValueEvent } from "./store-Ks80xWS_.cjs";
3
3
 
4
4
  //#region core/src/runtime.d.ts
5
5
  declare const createDocument: <S extends ObjectNode>(input: {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { $ as ObjectShape, D as snapshot, E as replace, F as ChangeSet, G as DocumentTreeNode, H as DocumentAnchor, I as MemberChange, K as DocumentTreeValue, L as ValueTransition, P as Change, Q as ObjectNode, S as DocumentImpact, T as Read, U as DocumentListConfig, V as DocumentAddress, W as DocumentNode, X as ListNode, Y as Infer, Z as MapNode, _ as Unsubscribe, _t as ParseError, a as DocumentDisposedError, at as TreeNode, b as MutationIssueCode, bt as parse, c as DocumentReentrancyError, ct as VariantShape, d as LocalHistory, dt as map, et as OptionalNode, f as ObserverError, ft as object, g as TransactionResult, gt as variant, h as TransactionRejected, ht as tree, i as DocumentDiagnostic, it as TableNode, l as DocumentRuntime, lt as field, mt as table, n as CommitSource, nt as ReadonlyValue, o as DocumentProblem, p as OperationResult, pt as optional, q as FieldNode, r as DocumentCommit, rt as SchemaPath, s as DocumentReadable, st as VariantNode, u as HistoryState, ut as list, v as Readable, vt as ParseIssue, w as Draft, x as CollectionImpact, y as MutationIssue, yt as Validator } from "./contract-CeAnEPBA.js";
2
- import { C as ProjectionDisposedError, S as project, _ as ProjectionSources, a as AdvancedCollectionSpec, b as ValueProjection, c as CollectionProjection, d as DocumentCollectionProjection, f as DocumentEvent, g as ProjectionEvents, h as Projection, i as AdvancedCollectionProcess, l as CollectionSource, m as InputProjection, n as createProjectionStore, o as AdvancedValueSpec, p as DocumentProjection, s as CollectionEvent, t as ProjectionStore, u as DocumentCollectionEvent, v as ProjectionValues, w as ProjectionError, x as input, y as ValueEvent } from "./store-Bs0C0rNd.js";
2
+ import { C as ProjectionDisposedError, S as project, _ as ProjectionSources, a as AdvancedCollectionSpec, b as ValueProjection, c as CollectionProjection, d as DocumentCollectionProjection, f as DocumentEvent, g as ProjectionEvents, h as Projection, i as AdvancedCollectionProcess, l as CollectionSource, m as InputProjection, n as createProjectionStore, o as AdvancedValueSpec, p as DocumentProjection, s as CollectionEvent, t as ProjectionStore, u as DocumentCollectionEvent, v as ProjectionValues, w as ProjectionError, x as input, y as ValueEvent } from "./store-2i8pYXqa.js";
3
3
 
4
4
  //#region core/src/runtime.d.ts
5
5
  declare const createDocument: <S extends ObjectNode>(input: {
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { A as insert, D as equal, F as remove, L as profile, M as keys, N as matches, _ as resolveTreeContainer, a as compiledShape, c as debugKey, d as overlaps, f as read, g as resolveLocated, h as resolveContainer, i as AddressIndex, j as install, l as memberKey, n as fail, o as contains, p as resolveAddress, r as invalidValue, s as createAddressResolver, t as MutationRejected, v as resolveValue } from "./issue-DVaGQGeP.js";
2
- import { A as object, B as parse, C as createAccess, D as field, E as compilePath, F as ParseError, I as checkKey, L as checkValue, M as table, N as tree, O as list, P as variant, R as copyValue, T as snapshot, _ as readWith, a as input, b as TransactionRejected, c as createNotification, d as shareNotification, g as bindRuntimeAccess, h as accessOf, i as ProjectionError, j as optional, k as map, l as disposeNotification, m as subscribeTargets, o as project, p as subscribeRoot, r as ProjectionDisposedError, s as bindDocumentReadable, t as createProjectionStore, u as notify, v as DocumentDisposedError, w as replace, x as createImpact, y as DocumentReentrancyError, z as equalValue } from "./store-DHFXfWSz.js";
2
+ import { A as object, B as parse, C as createAccess, D as field, E as compilePath, F as ParseError, I as checkKey, L as checkValue, M as table, N as tree, O as list, P as variant, R as copyValue, T as snapshot, _ as readWith, a as input, b as TransactionRejected, c as createNotification, d as shareNotification, g as bindRuntimeAccess, h as accessOf, i as ProjectionError, j as optional, k as map, l as disposeNotification, m as subscribeTargets, o as project, p as subscribeRoot, r as ProjectionDisposedError, s as bindDocumentReadable, t as createProjectionStore, u as notify, v as DocumentDisposedError, w as replace, x as createImpact, y as DocumentReentrancyError, z as equalValue } from "./store-7XBEcR8s.js";
3
3
  import { n as bindRuntimeDriver, o as decodeChanges, r as disposeRuntimeDriver, s as sealChanges, t as assertRuntimeWritable } from "./driver-BlR81Dqg.js";
4
4
  //#region core/src/history.ts
5
5
  const createHistory = (input) => {
@@ -1,4 +1,4 @@
1
- const require_store = require("./store-DU2u-qFH.cjs");
1
+ const require_store = require("./store-DBv58dns.cjs");
2
2
  //#region core/src/access/dependency.ts
3
3
  const createDependencyTracker = () => {
4
4
  const targets = [];
@@ -27,4 +27,4 @@ Object.defineProperty(exports, "track", {
27
27
  }
28
28
  });
29
29
 
30
- //# sourceMappingURL=integration-BKgGuodm.cjs.map
30
+ //# sourceMappingURL=integration-BShL68Nc.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"integration-BKgGuodm.cjs","names":["readWith"],"sources":["../core/src/access/dependency.ts","../core/src/integration.ts"],"sourcesContent":["import type { ImpactTarget } from '../schema';\nimport * as impactTarget from '../impact-target';\n\nexport type DependencyTracker = {\n readonly record: (target: ImpactTarget<unknown>) => void;\n readonly snapshot: () => readonly ImpactTarget<unknown>[];\n};\n\nexport const createDependencyTracker = (): DependencyTracker => {\n const targets: ImpactTarget<unknown>[] = [];\n return {\n record: value => {\n if (!targets.some(entry => impactTarget.same(entry, value))) targets.push(value);\n },\n snapshot: () => Object.freeze(targets.slice()),\n };\n};\n","import type { ObjectNode, ImpactTarget } from './schema';\nimport type { Read } from './access/scope';\nimport type { DocumentReadable } from './runtime/contract';\nimport { createDependencyTracker } from './access/dependency';\nimport { readWith } from './runtime/access';\nexport { projectionStoreDebug } from './projection/store';\nexport type { AddressRef } from './address';\nexport { contains, debugKey, overlaps, read as readAddress, resolveAddress } from './address';\nexport { subscribeDependencies } from './runtime/notification';\nexport { same as sameTarget } from './impact-target';\nexport type { ImpactTarget } from './schema';\n\nexport type TrackedSelection<TValue> = {\n readonly value: TValue;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\n// Framework adapters receive one immutable result instead of coordinating a\n// mutable collector with the reader's scoped lifetime themselves.\nexport const track = <TSchema extends ObjectNode, TValue>(\n runtime: DocumentReadable<TSchema>,\n selector: (read: Read<TSchema>) => TValue\n): TrackedSelection<TValue> => {\n const dependencies = createDependencyTracker();\n const value = readWith(runtime, selector, dependencies);\n return Object.freeze({ value, targets: dependencies.snapshot() });\n};\n"],"mappings":";;AAQA,MAAa,gCAAmD;CAC9D,MAAM,UAAmC,EAAE;AAC3C,QAAO;EACL,SAAQ,UAAS;AACf,OAAI,CAAC,QAAQ,MAAK,UAAA,cAAA,KAA2B,OAAO,MAAM,CAAC,CAAE,SAAQ,KAAK,MAAM;;EAElF,gBAAgB,OAAO,OAAO,QAAQ,OAAO,CAAC;EAC/C;;;;ACIH,MAAa,SACX,SACA,aAC6B;CAC7B,MAAM,eAAe,yBAAyB;CAC9C,MAAM,QAAQA,cAAAA,SAAS,SAAS,UAAU,aAAa;AACvD,QAAO,OAAO,OAAO;EAAE;EAAO,SAAS,aAAa,UAAU;EAAE,CAAC"}
1
+ {"version":3,"file":"integration-BShL68Nc.cjs","names":["readWith"],"sources":["../core/src/access/dependency.ts","../core/src/integration.ts"],"sourcesContent":["import type { ImpactTarget } from '../schema';\nimport * as impactTarget from '../impact-target';\n\nexport type DependencyTracker = {\n readonly record: (target: ImpactTarget<unknown>) => void;\n readonly snapshot: () => readonly ImpactTarget<unknown>[];\n};\n\nexport const createDependencyTracker = (): DependencyTracker => {\n const targets: ImpactTarget<unknown>[] = [];\n return {\n record: value => {\n if (!targets.some(entry => impactTarget.same(entry, value))) targets.push(value);\n },\n snapshot: () => Object.freeze(targets.slice()),\n };\n};\n","import type { ObjectNode, ImpactTarget } from './schema';\nimport type { Read } from './access/scope';\nimport type { DocumentReadable } from './runtime/contract';\nimport { createDependencyTracker } from './access/dependency';\nimport { readWith } from './runtime/access';\nexport { projectionStoreDebug } from './projection/store';\nexport type { AddressRef } from './address';\nexport { contains, debugKey, overlaps, read as readAddress, resolveAddress } from './address';\nexport { subscribeDependencies } from './runtime/notification';\nexport { same as sameTarget } from './impact-target';\nexport type { ImpactTarget } from './schema';\n\nexport type TrackedSelection<TValue> = {\n readonly value: TValue;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\n// Framework adapters receive one immutable result instead of coordinating a\n// mutable collector with the reader's scoped lifetime themselves.\nexport const track = <TSchema extends ObjectNode, TValue>(\n runtime: DocumentReadable<TSchema>,\n selector: (read: Read<TSchema>) => TValue\n): TrackedSelection<TValue> => {\n const dependencies = createDependencyTracker();\n const value = readWith(runtime, selector, dependencies);\n return Object.freeze({ value, targets: dependencies.snapshot() });\n};\n"],"mappings":";;AAQA,MAAa,gCAAmD;CAC9D,MAAM,UAAmC,EAAE;AAC3C,QAAO;EACL,SAAQ,UAAS;AACf,OAAI,CAAC,QAAQ,MAAK,UAAA,cAAA,KAA2B,OAAO,MAAM,CAAC,CAAE,SAAQ,KAAK,MAAM;;EAElF,gBAAgB,OAAO,OAAO,QAAQ,OAAO,CAAC;EAC/C;;;;ACIH,MAAa,SACX,SACA,aAC6B;CAC7B,MAAM,eAAe,yBAAyB;CAC9C,MAAM,QAAQA,cAAAA,SAAS,SAAS,UAAU,aAAa;AACvD,QAAO,OAAO,OAAO;EAAE;EAAO,SAAS,aAAa,UAAU;EAAE,CAAC"}
@@ -1,4 +1,4 @@
1
- import { S as same, _ as readWith } from "./store-DHFXfWSz.js";
1
+ import { S as same, _ as readWith } from "./store-7XBEcR8s.js";
2
2
  //#region core/src/access/dependency.ts
3
3
  const createDependencyTracker = () => {
4
4
  const targets = [];
@@ -22,4 +22,4 @@ const track = (runtime, selector) => {
22
22
  //#endregion
23
23
  export { track as t };
24
24
 
25
- //# sourceMappingURL=integration-VTZ3ICsO.js.map
25
+ //# sourceMappingURL=integration-CWjttg7H.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"integration-VTZ3ICsO.js","names":["impactTarget.same"],"sources":["../core/src/access/dependency.ts","../core/src/integration.ts"],"sourcesContent":["import type { ImpactTarget } from '../schema';\nimport * as impactTarget from '../impact-target';\n\nexport type DependencyTracker = {\n readonly record: (target: ImpactTarget<unknown>) => void;\n readonly snapshot: () => readonly ImpactTarget<unknown>[];\n};\n\nexport const createDependencyTracker = (): DependencyTracker => {\n const targets: ImpactTarget<unknown>[] = [];\n return {\n record: value => {\n if (!targets.some(entry => impactTarget.same(entry, value))) targets.push(value);\n },\n snapshot: () => Object.freeze(targets.slice()),\n };\n};\n","import type { ObjectNode, ImpactTarget } from './schema';\nimport type { Read } from './access/scope';\nimport type { DocumentReadable } from './runtime/contract';\nimport { createDependencyTracker } from './access/dependency';\nimport { readWith } from './runtime/access';\nexport { projectionStoreDebug } from './projection/store';\nexport type { AddressRef } from './address';\nexport { contains, debugKey, overlaps, read as readAddress, resolveAddress } from './address';\nexport { subscribeDependencies } from './runtime/notification';\nexport { same as sameTarget } from './impact-target';\nexport type { ImpactTarget } from './schema';\n\nexport type TrackedSelection<TValue> = {\n readonly value: TValue;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\n// Framework adapters receive one immutable result instead of coordinating a\n// mutable collector with the reader's scoped lifetime themselves.\nexport const track = <TSchema extends ObjectNode, TValue>(\n runtime: DocumentReadable<TSchema>,\n selector: (read: Read<TSchema>) => TValue\n): TrackedSelection<TValue> => {\n const dependencies = createDependencyTracker();\n const value = readWith(runtime, selector, dependencies);\n return Object.freeze({ value, targets: dependencies.snapshot() });\n};\n"],"mappings":";;AAQA,MAAa,gCAAmD;CAC9D,MAAM,UAAmC,EAAE;AAC3C,QAAO;EACL,SAAQ,UAAS;AACf,OAAI,CAAC,QAAQ,MAAK,UAASA,KAAkB,OAAO,MAAM,CAAC,CAAE,SAAQ,KAAK,MAAM;;EAElF,gBAAgB,OAAO,OAAO,QAAQ,OAAO,CAAC;EAC/C;;;;ACIH,MAAa,SACX,SACA,aAC6B;CAC7B,MAAM,eAAe,yBAAyB;CAC9C,MAAM,QAAQ,SAAS,SAAS,UAAU,aAAa;AACvD,QAAO,OAAO,OAAO;EAAE;EAAO,SAAS,aAAa,UAAU;EAAE,CAAC"}
1
+ {"version":3,"file":"integration-CWjttg7H.js","names":["impactTarget.same"],"sources":["../core/src/access/dependency.ts","../core/src/integration.ts"],"sourcesContent":["import type { ImpactTarget } from '../schema';\nimport * as impactTarget from '../impact-target';\n\nexport type DependencyTracker = {\n readonly record: (target: ImpactTarget<unknown>) => void;\n readonly snapshot: () => readonly ImpactTarget<unknown>[];\n};\n\nexport const createDependencyTracker = (): DependencyTracker => {\n const targets: ImpactTarget<unknown>[] = [];\n return {\n record: value => {\n if (!targets.some(entry => impactTarget.same(entry, value))) targets.push(value);\n },\n snapshot: () => Object.freeze(targets.slice()),\n };\n};\n","import type { ObjectNode, ImpactTarget } from './schema';\nimport type { Read } from './access/scope';\nimport type { DocumentReadable } from './runtime/contract';\nimport { createDependencyTracker } from './access/dependency';\nimport { readWith } from './runtime/access';\nexport { projectionStoreDebug } from './projection/store';\nexport type { AddressRef } from './address';\nexport { contains, debugKey, overlaps, read as readAddress, resolveAddress } from './address';\nexport { subscribeDependencies } from './runtime/notification';\nexport { same as sameTarget } from './impact-target';\nexport type { ImpactTarget } from './schema';\n\nexport type TrackedSelection<TValue> = {\n readonly value: TValue;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\n// Framework adapters receive one immutable result instead of coordinating a\n// mutable collector with the reader's scoped lifetime themselves.\nexport const track = <TSchema extends ObjectNode, TValue>(\n runtime: DocumentReadable<TSchema>,\n selector: (read: Read<TSchema>) => TValue\n): TrackedSelection<TValue> => {\n const dependencies = createDependencyTracker();\n const value = readWith(runtime, selector, dependencies);\n return Object.freeze({ value, targets: dependencies.snapshot() });\n};\n"],"mappings":";;AAQA,MAAa,gCAAmD;CAC9D,MAAM,UAAmC,EAAE;AAC3C,QAAO;EACL,SAAQ,UAAS;AACf,OAAI,CAAC,QAAQ,MAAK,UAASA,KAAkB,OAAO,MAAM,CAAC,CAAE,SAAQ,KAAK,MAAM;;EAElF,gBAAgB,OAAO,OAAO,QAAQ,OAAO,CAAC;EAC/C;;;;ACIH,MAAa,SACX,SACA,aAC6B;CAC7B,MAAM,eAAe,yBAAyB;CAC9C,MAAM,QAAQ,SAAS,SAAS,UAAU,aAAa;AACvD,QAAO,OAAO,OAAO;EAAE;EAAO,SAAS,aAAa,UAAU;EAAE,CAAC"}
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_issue = require("./issue-DhrNdQNg.cjs");
3
- const require_store = require("./store-DU2u-qFH.cjs");
4
- const require_integration = require("./integration-BKgGuodm.cjs");
3
+ const require_store = require("./store-DBv58dns.cjs");
4
+ const require_integration = require("./integration-BShL68Nc.cjs");
5
5
  exports.contains = require_issue.contains;
6
6
  exports.debugKey = require_issue.debugKey;
7
7
  exports.overlaps = require_issue.overlaps;
@@ -1,5 +1,5 @@
1
1
  import { A as debugKey, J as ImpactTarget, M as read, N as resolveAddress, O as AddressRef, Q as ObjectNode, T as Read, _ as Unsubscribe, j as overlaps, k as contains, s as DocumentReadable, t as CommitListener } from "./contract-DtGVSXSK.cjs";
2
- import { r as projectionStoreDebug } from "./store-CJuwJl_K.cjs";
2
+ import { r as projectionStoreDebug } from "./store-Ks80xWS_.cjs";
3
3
 
4
4
  //#region core/src/impact-target.d.ts
5
5
  declare const same: (left: ImpactTarget<unknown>, right: ImpactTarget<unknown>) => boolean;
@@ -1,5 +1,5 @@
1
1
  import { A as debugKey, J as ImpactTarget, M as read, N as resolveAddress, O as AddressRef, Q as ObjectNode, T as Read, _ as Unsubscribe, j as overlaps, k as contains, s as DocumentReadable, t as CommitListener } from "./contract-CeAnEPBA.js";
2
- import { r as projectionStoreDebug } from "./store-Bs0C0rNd.js";
2
+ import { r as projectionStoreDebug } from "./store-2i8pYXqa.js";
3
3
 
4
4
  //#region core/src/impact-target.d.ts
5
5
  declare const same: (left: ImpactTarget<unknown>, right: ImpactTarget<unknown>) => boolean;
@@ -1,4 +1,4 @@
1
1
  import { c as debugKey, d as overlaps, f as read, o as contains, p as resolveAddress } from "./issue-DVaGQGeP.js";
2
- import { S as same, f as subscribeDependencies, n as projectionStoreDebug } from "./store-DHFXfWSz.js";
3
- import { t as track } from "./integration-VTZ3ICsO.js";
2
+ import { S as same, f as subscribeDependencies, n as projectionStoreDebug } from "./store-7XBEcR8s.js";
3
+ import { t as track } from "./integration-CWjttg7H.js";
4
4
  export { contains, debugKey, overlaps, projectionStoreDebug, read as readAddress, resolveAddress, same as sameTarget, subscribeDependencies, track };
package/dist/react.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_store = require("./store-DU2u-qFH.cjs");
3
- const require_integration = require("./integration-BKgGuodm.cjs");
2
+ const require_store = require("./store-DBv58dns.cjs");
3
+ const require_integration = require("./integration-BShL68Nc.cjs");
4
4
  let react = require("react");
5
5
  //#region react/src/hooks.ts
6
6
  const ProjectionContext = (0, react.createContext)(void 0);
@@ -12,6 +12,32 @@ function useProjection(projection, store) {
12
12
  const read = (0, react.useCallback)(() => owner.get(projection), [owner, projection]);
13
13
  return (0, react.useSyncExternalStore)((0, react.useCallback)((listener) => owner.subscribe(projection, listener), [owner, projection]), read, read);
14
14
  }
15
+ function useProjectionItem(projection, key, store) {
16
+ const context = (0, react.useContext)(ProjectionContext);
17
+ const owner = store ?? context;
18
+ if (!owner) throw new Error("ProjectionStore is required.");
19
+ const item = (0, react.useMemo)(() => owner.item(projection, key), [
20
+ key,
21
+ owner,
22
+ projection
23
+ ]);
24
+ const read = (0, react.useMemo)(() => {
25
+ let previousRevision = -1;
26
+ let snapshot;
27
+ return () => {
28
+ const value = item.current();
29
+ const revision = item.revision();
30
+ if (snapshot && revision === previousRevision) return snapshot;
31
+ previousRevision = revision;
32
+ snapshot = {
33
+ value,
34
+ revision
35
+ };
36
+ return snapshot;
37
+ };
38
+ }, [item]);
39
+ return (0, react.useSyncExternalStore)((0, react.useCallback)((listener) => item.subscribe(listener), [item]), read, read).value;
40
+ }
15
41
  function useSetProjection(projection, store) {
16
42
  const context = (0, react.useContext)(ProjectionContext);
17
43
  const owner = store ?? context;
@@ -120,6 +146,7 @@ exports.ProjectionProvider = ProjectionProvider;
120
146
  exports.useDocumentSelector = useDocumentSelector;
121
147
  exports.useHistory = useHistory;
122
148
  exports.useProjection = useProjection;
149
+ exports.useProjectionItem = useProjectionItem;
123
150
  exports.useReadable = useReadable;
124
151
  exports.useSetProjection = useSetProjection;
125
152
 
@@ -1 +1 @@
1
- {"version":3,"file":"react.cjs","names":["sameTarget","track","subscribeDependencies"],"sources":["../react/src/hooks.ts"],"sourcesContent":["import type {\n DocumentReadable,\n ObjectNode,\n DocumentSelector,\n HistoryState,\n LocalHistory,\n OperationResult,\n Readable,\n ProjectionStore,\n ValueProjection,\n InputProjection,\n} from 'doxum';\nimport { track, subscribeDependencies, sameTarget, type ImpactTarget } from 'doxum/integration';\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\n\nexport const ProjectionContext = createContext<ProjectionStore | undefined>(undefined);\nexport const ProjectionProvider = ProjectionContext.Provider;\n\nexport function useProjection<T>(projection: ValueProjection<T>, store?: ProjectionStore): T {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n const read = useCallback(() => owner.get(projection), [owner, projection]);\n const subscribe = useCallback(\n (listener: () => void) => owner.subscribe(projection, listener),\n [owner, projection]\n );\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport function useSetProjection<T>(\n projection: InputProjection<T>,\n store?: ProjectionStore\n): (value: T) => void {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n return useCallback((value: T) => owner.set(projection, value), [owner, projection]);\n}\n\nexport type DocumentSelectorOptions<TResult> = {\n readonly isEqual?: (previous: TResult, next: TResult) => boolean;\n readonly server?: () => TResult;\n};\n\ntype SelectorCache<TSchema extends ObjectNode, TResult> = {\n readonly runtime: DocumentReadable<TSchema>;\n readonly value: TResult;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\nconst objectIs = <T>(previous: T, next: T): boolean => Object.is(previous, next);\nconst sameTargets = (\n left: readonly ImpactTarget<unknown>[],\n right: readonly ImpactTarget<unknown>[]\n): boolean => {\n if (left.length !== right.length) return false;\n for (let index = 0; index < left.length; index += 1)\n if (!sameTarget(left[index], right[index])) return false;\n return true;\n};\n\nexport function useDocumentSelector<TSchema extends ObjectNode, TResult>(\n runtime: DocumentReadable<TSchema>,\n selector: DocumentSelector<TSchema, TResult>,\n options?: DocumentSelectorOptions<TResult>\n): TResult {\n const equality = options?.isEqual ?? objectIs;\n const cache = useRef<SelectorCache<TSchema, TResult> | undefined>(undefined);\n const serverCache = useRef<\n | {\n readonly runtime: DocumentReadable<TSchema>;\n readonly selector: DocumentSelector<TSchema, TResult>;\n readonly source: (() => TResult) | undefined;\n readonly value: TResult;\n }\n | undefined\n >(undefined);\n\n const read = useMemo(() => {\n // Each selector closure owns its revision cache, including inline selectors\n // that allocate arrays or objects. Equality only compares distinct snapshots.\n let snapshot: { readonly revision: number; readonly value: TResult } | undefined;\n return (): TResult => {\n const revision = runtime.revision();\n if (snapshot?.revision === revision) return snapshot.value;\n const selection = track(runtime, selector);\n const previous = cache.current;\n const value =\n previous && previous.runtime === runtime && equality(previous.value, selection.value)\n ? previous.value\n : selection.value;\n cache.current = { runtime, value, targets: selection.targets };\n snapshot = { revision, value };\n return value;\n };\n }, [equality, runtime, selector]);\n\n const subscribe = useCallback(\n (listener: () => void) => {\n read();\n let targets = cache.current?.targets ?? [];\n let unsubscribe: () => void = () => undefined;\n const install = () => {\n if (targets.length === 0) return () => undefined;\n return subscribeDependencies(runtime, targets, onCommit);\n };\n const onCommit = () => {\n const previous = cache.current;\n const next = read();\n const nextTargets = cache.current?.targets ?? [];\n if (!sameTargets(targets, nextTargets)) {\n unsubscribe();\n targets = nextTargets;\n unsubscribe = install();\n }\n if (previous && !Object.is(previous.value, next)) listener();\n };\n unsubscribe = install();\n return () => unsubscribe();\n },\n [read, runtime]\n );\n\n const server = options?.server;\n const readServer = useCallback((): TResult => {\n const previous = serverCache.current;\n if (\n previous &&\n previous.source === server &&\n previous.runtime === runtime &&\n previous.selector === selector\n )\n return previous.value;\n const value = server ? server() : read();\n serverCache.current = { runtime, selector, source: server, value };\n return value;\n }, [read, server, runtime, selector]);\n\n return useSyncExternalStore(subscribe, read, readServer);\n}\n\nexport function useReadable<T>(readable: Readable<T>): T {\n const subscribe = useCallback((listener: () => void) => readable.subscribe(listener), [readable]);\n const read = useCallback(() => readable.current(), [readable]);\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport function useHistory<TCommit>(history: LocalHistory<TCommit>): HistoryState & {\n undo(): OperationResult<TCommit>;\n redo(): OperationResult<TCommit>;\n} {\n const subscribe = useCallback((listener: () => void) => history.subscribe(listener), [history]);\n const read = useCallback(() => history.current(), [history]);\n const state = useSyncExternalStore(subscribe, read, read);\n const undo = useCallback(() => history.undo(), [history]);\n const redo = useCallback(() => history.redo(), [history]);\n\n return useMemo(() => ({ ...state, undo, redo }), [redo, state, undo]);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"react.cjs","names":["sameTarget","track","subscribeDependencies"],"sources":["../react/src/hooks.ts"],"sourcesContent":["import type {\n DocumentReadable,\n ObjectNode,\n DocumentSelector,\n HistoryState,\n LocalHistory,\n OperationResult,\n Readable,\n ProjectionStore,\n CollectionProjection,\n ValueProjection,\n InputProjection,\n} from 'doxum';\nimport { track, subscribeDependencies, sameTarget, type ImpactTarget } from 'doxum/integration';\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\n\nexport const ProjectionContext = createContext<ProjectionStore | undefined>(undefined);\nexport const ProjectionProvider = ProjectionContext.Provider;\n\nexport function useProjection<T>(projection: ValueProjection<T>, store?: ProjectionStore): T {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n const read = useCallback(() => owner.get(projection), [owner, projection]);\n const subscribe = useCallback(\n (listener: () => void) => owner.subscribe(projection, listener),\n [owner, projection]\n );\n return useSyncExternalStore(subscribe, read, read);\n}\n\ntype ProjectionItemSnapshot<T> = {\n readonly value: T | undefined;\n readonly revision: number;\n};\n\nexport function useProjectionItem<K extends string, V>(\n projection: CollectionProjection<K, V>,\n key: K,\n store?: ProjectionStore\n): V | undefined {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n const item = useMemo(() => owner.item(projection, key), [key, owner, projection]);\n const read = useMemo(() => {\n let previousRevision = -1;\n let snapshot: ProjectionItemSnapshot<V> | undefined;\n return (): ProjectionItemSnapshot<V> => {\n const value = item.current();\n const revision = item.revision();\n if (snapshot && revision === previousRevision) return snapshot;\n previousRevision = revision;\n snapshot = { value, revision };\n return snapshot;\n };\n }, [item]);\n const subscribe = useCallback((listener: () => void) => item.subscribe(listener), [item]);\n return useSyncExternalStore(subscribe, read, read).value;\n}\n\nexport function useSetProjection<T>(\n projection: InputProjection<T>,\n store?: ProjectionStore\n): (value: T) => void {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n return useCallback((value: T) => owner.set(projection, value), [owner, projection]);\n}\n\nexport type DocumentSelectorOptions<TResult> = {\n readonly isEqual?: (previous: TResult, next: TResult) => boolean;\n readonly server?: () => TResult;\n};\n\ntype SelectorCache<TSchema extends ObjectNode, TResult> = {\n readonly runtime: DocumentReadable<TSchema>;\n readonly value: TResult;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\nconst objectIs = <T>(previous: T, next: T): boolean => Object.is(previous, next);\nconst sameTargets = (\n left: readonly ImpactTarget<unknown>[],\n right: readonly ImpactTarget<unknown>[]\n): boolean => {\n if (left.length !== right.length) return false;\n for (let index = 0; index < left.length; index += 1)\n if (!sameTarget(left[index], right[index])) return false;\n return true;\n};\n\nexport function useDocumentSelector<TSchema extends ObjectNode, TResult>(\n runtime: DocumentReadable<TSchema>,\n selector: DocumentSelector<TSchema, TResult>,\n options?: DocumentSelectorOptions<TResult>\n): TResult {\n const equality = options?.isEqual ?? objectIs;\n const cache = useRef<SelectorCache<TSchema, TResult> | undefined>(undefined);\n const serverCache = useRef<\n | {\n readonly runtime: DocumentReadable<TSchema>;\n readonly selector: DocumentSelector<TSchema, TResult>;\n readonly source: (() => TResult) | undefined;\n readonly value: TResult;\n }\n | undefined\n >(undefined);\n\n const read = useMemo(() => {\n // Each selector closure owns its revision cache, including inline selectors\n // that allocate arrays or objects. Equality only compares distinct snapshots.\n let snapshot: { readonly revision: number; readonly value: TResult } | undefined;\n return (): TResult => {\n const revision = runtime.revision();\n if (snapshot?.revision === revision) return snapshot.value;\n const selection = track(runtime, selector);\n const previous = cache.current;\n const value =\n previous && previous.runtime === runtime && equality(previous.value, selection.value)\n ? previous.value\n : selection.value;\n cache.current = { runtime, value, targets: selection.targets };\n snapshot = { revision, value };\n return value;\n };\n }, [equality, runtime, selector]);\n\n const subscribe = useCallback(\n (listener: () => void) => {\n read();\n let targets = cache.current?.targets ?? [];\n let unsubscribe: () => void = () => undefined;\n const install = () => {\n if (targets.length === 0) return () => undefined;\n return subscribeDependencies(runtime, targets, onCommit);\n };\n const onCommit = () => {\n const previous = cache.current;\n const next = read();\n const nextTargets = cache.current?.targets ?? [];\n if (!sameTargets(targets, nextTargets)) {\n unsubscribe();\n targets = nextTargets;\n unsubscribe = install();\n }\n if (previous && !Object.is(previous.value, next)) listener();\n };\n unsubscribe = install();\n return () => unsubscribe();\n },\n [read, runtime]\n );\n\n const server = options?.server;\n const readServer = useCallback((): TResult => {\n const previous = serverCache.current;\n if (\n previous &&\n previous.source === server &&\n previous.runtime === runtime &&\n previous.selector === selector\n )\n return previous.value;\n const value = server ? server() : read();\n serverCache.current = { runtime, selector, source: server, value };\n return value;\n }, [read, server, runtime, selector]);\n\n return useSyncExternalStore(subscribe, read, readServer);\n}\n\nexport function useReadable<T>(readable: Readable<T>): T {\n const subscribe = useCallback((listener: () => void) => readable.subscribe(listener), [readable]);\n const read = useCallback(() => readable.current(), [readable]);\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport function useHistory<TCommit>(history: LocalHistory<TCommit>): HistoryState & {\n undo(): OperationResult<TCommit>;\n redo(): OperationResult<TCommit>;\n} {\n const subscribe = useCallback((listener: () => void) => history.subscribe(listener), [history]);\n const read = useCallback(() => history.current(), [history]);\n const state = useSyncExternalStore(subscribe, read, read);\n const undo = useCallback(() => history.undo(), [history]);\n const redo = useCallback(() => history.redo(), [history]);\n\n return useMemo(() => ({ ...state, undo, redo }), [redo, state, undo]);\n}\n"],"mappings":"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"}
package/dist/react.d.cts CHANGED
@@ -1,10 +1,11 @@
1
1
  import * as _$react from "react";
2
- import { DocumentReadable, DocumentSelector, HistoryState, InputProjection, LocalHistory, ObjectNode, OperationResult, ProjectionStore, Readable, ValueProjection } from "doxum";
2
+ import { CollectionProjection, DocumentReadable, DocumentSelector, HistoryState, InputProjection, LocalHistory, ObjectNode, OperationResult, ProjectionStore, Readable, ValueProjection } from "doxum";
3
3
 
4
4
  //#region react/src/hooks.d.ts
5
5
  declare const ProjectionContext: _$react.Context<ProjectionStore | undefined>;
6
6
  declare const ProjectionProvider: _$react.Provider<ProjectionStore | undefined>;
7
7
  declare function useProjection<T>(projection: ValueProjection<T>, store?: ProjectionStore): T;
8
+ declare function useProjectionItem<K extends string, V>(projection: CollectionProjection<K, V>, key: K, store?: ProjectionStore): V | undefined;
8
9
  declare function useSetProjection<T>(projection: InputProjection<T>, store?: ProjectionStore): (value: T) => void;
9
10
  type DocumentSelectorOptions<TResult> = {
10
11
  readonly isEqual?: (previous: TResult, next: TResult) => boolean;
@@ -17,5 +18,5 @@ declare function useHistory<TCommit>(history: LocalHistory<TCommit>): HistorySta
17
18
  redo(): OperationResult<TCommit>;
18
19
  };
19
20
  //#endregion
20
- export { type DocumentSelectorOptions, ProjectionContext, ProjectionProvider, useDocumentSelector, useHistory, useProjection, useReadable, useSetProjection };
21
+ export { type DocumentSelectorOptions, ProjectionContext, ProjectionProvider, useDocumentSelector, useHistory, useProjection, useProjectionItem, useReadable, useSetProjection };
21
22
  //# sourceMappingURL=react.d.cts.map
package/dist/react.d.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import * as _$react from "react";
2
- import { DocumentReadable, DocumentSelector, HistoryState, InputProjection, LocalHistory, ObjectNode, OperationResult, ProjectionStore, Readable, ValueProjection } from "doxum";
2
+ import { CollectionProjection, DocumentReadable, DocumentSelector, HistoryState, InputProjection, LocalHistory, ObjectNode, OperationResult, ProjectionStore, Readable, ValueProjection } from "doxum";
3
3
 
4
4
  //#region react/src/hooks.d.ts
5
5
  declare const ProjectionContext: _$react.Context<ProjectionStore | undefined>;
6
6
  declare const ProjectionProvider: _$react.Provider<ProjectionStore | undefined>;
7
7
  declare function useProjection<T>(projection: ValueProjection<T>, store?: ProjectionStore): T;
8
+ declare function useProjectionItem<K extends string, V>(projection: CollectionProjection<K, V>, key: K, store?: ProjectionStore): V | undefined;
8
9
  declare function useSetProjection<T>(projection: InputProjection<T>, store?: ProjectionStore): (value: T) => void;
9
10
  type DocumentSelectorOptions<TResult> = {
10
11
  readonly isEqual?: (previous: TResult, next: TResult) => boolean;
@@ -17,5 +18,5 @@ declare function useHistory<TCommit>(history: LocalHistory<TCommit>): HistorySta
17
18
  redo(): OperationResult<TCommit>;
18
19
  };
19
20
  //#endregion
20
- export { type DocumentSelectorOptions, ProjectionContext, ProjectionProvider, useDocumentSelector, useHistory, useProjection, useReadable, useSetProjection };
21
+ export { type DocumentSelectorOptions, ProjectionContext, ProjectionProvider, useDocumentSelector, useHistory, useProjection, useProjectionItem, useReadable, useSetProjection };
21
22
  //# sourceMappingURL=react.d.ts.map
package/dist/react.js CHANGED
@@ -1,5 +1,5 @@
1
- import { S as same, f as subscribeDependencies } from "./store-DHFXfWSz.js";
2
- import { t as track } from "./integration-VTZ3ICsO.js";
1
+ import { S as same, f as subscribeDependencies } from "./store-7XBEcR8s.js";
2
+ import { t as track } from "./integration-CWjttg7H.js";
3
3
  import { createContext, useCallback, useContext, useMemo, useRef, useSyncExternalStore } from "react";
4
4
  //#region react/src/hooks.ts
5
5
  const ProjectionContext = createContext(void 0);
@@ -11,6 +11,32 @@ function useProjection(projection, store) {
11
11
  const read = useCallback(() => owner.get(projection), [owner, projection]);
12
12
  return useSyncExternalStore(useCallback((listener) => owner.subscribe(projection, listener), [owner, projection]), read, read);
13
13
  }
14
+ function useProjectionItem(projection, key, store) {
15
+ const context = useContext(ProjectionContext);
16
+ const owner = store ?? context;
17
+ if (!owner) throw new Error("ProjectionStore is required.");
18
+ const item = useMemo(() => owner.item(projection, key), [
19
+ key,
20
+ owner,
21
+ projection
22
+ ]);
23
+ const read = useMemo(() => {
24
+ let previousRevision = -1;
25
+ let snapshot;
26
+ return () => {
27
+ const value = item.current();
28
+ const revision = item.revision();
29
+ if (snapshot && revision === previousRevision) return snapshot;
30
+ previousRevision = revision;
31
+ snapshot = {
32
+ value,
33
+ revision
34
+ };
35
+ return snapshot;
36
+ };
37
+ }, [item]);
38
+ return useSyncExternalStore(useCallback((listener) => item.subscribe(listener), [item]), read, read).value;
39
+ }
14
40
  function useSetProjection(projection, store) {
15
41
  const context = useContext(ProjectionContext);
16
42
  const owner = store ?? context;
@@ -114,6 +140,6 @@ function useHistory(history) {
114
140
  ]);
115
141
  }
116
142
  //#endregion
117
- export { ProjectionContext, ProjectionProvider, useDocumentSelector, useHistory, useProjection, useReadable, useSetProjection };
143
+ export { ProjectionContext, ProjectionProvider, useDocumentSelector, useHistory, useProjection, useProjectionItem, useReadable, useSetProjection };
118
144
 
119
145
  //# sourceMappingURL=react.js.map
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","names":["sameTarget"],"sources":["../react/src/hooks.ts"],"sourcesContent":["import type {\n DocumentReadable,\n ObjectNode,\n DocumentSelector,\n HistoryState,\n LocalHistory,\n OperationResult,\n Readable,\n ProjectionStore,\n ValueProjection,\n InputProjection,\n} from 'doxum';\nimport { track, subscribeDependencies, sameTarget, type ImpactTarget } from 'doxum/integration';\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\n\nexport const ProjectionContext = createContext<ProjectionStore | undefined>(undefined);\nexport const ProjectionProvider = ProjectionContext.Provider;\n\nexport function useProjection<T>(projection: ValueProjection<T>, store?: ProjectionStore): T {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n const read = useCallback(() => owner.get(projection), [owner, projection]);\n const subscribe = useCallback(\n (listener: () => void) => owner.subscribe(projection, listener),\n [owner, projection]\n );\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport function useSetProjection<T>(\n projection: InputProjection<T>,\n store?: ProjectionStore\n): (value: T) => void {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n return useCallback((value: T) => owner.set(projection, value), [owner, projection]);\n}\n\nexport type DocumentSelectorOptions<TResult> = {\n readonly isEqual?: (previous: TResult, next: TResult) => boolean;\n readonly server?: () => TResult;\n};\n\ntype SelectorCache<TSchema extends ObjectNode, TResult> = {\n readonly runtime: DocumentReadable<TSchema>;\n readonly value: TResult;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\nconst objectIs = <T>(previous: T, next: T): boolean => Object.is(previous, next);\nconst sameTargets = (\n left: readonly ImpactTarget<unknown>[],\n right: readonly ImpactTarget<unknown>[]\n): boolean => {\n if (left.length !== right.length) return false;\n for (let index = 0; index < left.length; index += 1)\n if (!sameTarget(left[index], right[index])) return false;\n return true;\n};\n\nexport function useDocumentSelector<TSchema extends ObjectNode, TResult>(\n runtime: DocumentReadable<TSchema>,\n selector: DocumentSelector<TSchema, TResult>,\n options?: DocumentSelectorOptions<TResult>\n): TResult {\n const equality = options?.isEqual ?? objectIs;\n const cache = useRef<SelectorCache<TSchema, TResult> | undefined>(undefined);\n const serverCache = useRef<\n | {\n readonly runtime: DocumentReadable<TSchema>;\n readonly selector: DocumentSelector<TSchema, TResult>;\n readonly source: (() => TResult) | undefined;\n readonly value: TResult;\n }\n | undefined\n >(undefined);\n\n const read = useMemo(() => {\n // Each selector closure owns its revision cache, including inline selectors\n // that allocate arrays or objects. Equality only compares distinct snapshots.\n let snapshot: { readonly revision: number; readonly value: TResult } | undefined;\n return (): TResult => {\n const revision = runtime.revision();\n if (snapshot?.revision === revision) return snapshot.value;\n const selection = track(runtime, selector);\n const previous = cache.current;\n const value =\n previous && previous.runtime === runtime && equality(previous.value, selection.value)\n ? previous.value\n : selection.value;\n cache.current = { runtime, value, targets: selection.targets };\n snapshot = { revision, value };\n return value;\n };\n }, [equality, runtime, selector]);\n\n const subscribe = useCallback(\n (listener: () => void) => {\n read();\n let targets = cache.current?.targets ?? [];\n let unsubscribe: () => void = () => undefined;\n const install = () => {\n if (targets.length === 0) return () => undefined;\n return subscribeDependencies(runtime, targets, onCommit);\n };\n const onCommit = () => {\n const previous = cache.current;\n const next = read();\n const nextTargets = cache.current?.targets ?? [];\n if (!sameTargets(targets, nextTargets)) {\n unsubscribe();\n targets = nextTargets;\n unsubscribe = install();\n }\n if (previous && !Object.is(previous.value, next)) listener();\n };\n unsubscribe = install();\n return () => unsubscribe();\n },\n [read, runtime]\n );\n\n const server = options?.server;\n const readServer = useCallback((): TResult => {\n const previous = serverCache.current;\n if (\n previous &&\n previous.source === server &&\n previous.runtime === runtime &&\n previous.selector === selector\n )\n return previous.value;\n const value = server ? server() : read();\n serverCache.current = { runtime, selector, source: server, value };\n return value;\n }, [read, server, runtime, selector]);\n\n return useSyncExternalStore(subscribe, read, readServer);\n}\n\nexport function useReadable<T>(readable: Readable<T>): T {\n const subscribe = useCallback((listener: () => void) => readable.subscribe(listener), [readable]);\n const read = useCallback(() => readable.current(), [readable]);\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport function useHistory<TCommit>(history: LocalHistory<TCommit>): HistoryState & {\n undo(): OperationResult<TCommit>;\n redo(): OperationResult<TCommit>;\n} {\n const subscribe = useCallback((listener: () => void) => history.subscribe(listener), [history]);\n const read = useCallback(() => history.current(), [history]);\n const state = useSyncExternalStore(subscribe, read, read);\n const undo = useCallback(() => history.undo(), [history]);\n const redo = useCallback(() => history.redo(), [history]);\n\n return useMemo(() => ({ ...state, undo, redo }), [redo, state, undo]);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"react.js","names":["sameTarget"],"sources":["../react/src/hooks.ts"],"sourcesContent":["import type {\n DocumentReadable,\n ObjectNode,\n DocumentSelector,\n HistoryState,\n LocalHistory,\n OperationResult,\n Readable,\n ProjectionStore,\n CollectionProjection,\n ValueProjection,\n InputProjection,\n} from 'doxum';\nimport { track, subscribeDependencies, sameTarget, type ImpactTarget } from 'doxum/integration';\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\n\nexport const ProjectionContext = createContext<ProjectionStore | undefined>(undefined);\nexport const ProjectionProvider = ProjectionContext.Provider;\n\nexport function useProjection<T>(projection: ValueProjection<T>, store?: ProjectionStore): T {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n const read = useCallback(() => owner.get(projection), [owner, projection]);\n const subscribe = useCallback(\n (listener: () => void) => owner.subscribe(projection, listener),\n [owner, projection]\n );\n return useSyncExternalStore(subscribe, read, read);\n}\n\ntype ProjectionItemSnapshot<T> = {\n readonly value: T | undefined;\n readonly revision: number;\n};\n\nexport function useProjectionItem<K extends string, V>(\n projection: CollectionProjection<K, V>,\n key: K,\n store?: ProjectionStore\n): V | undefined {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n const item = useMemo(() => owner.item(projection, key), [key, owner, projection]);\n const read = useMemo(() => {\n let previousRevision = -1;\n let snapshot: ProjectionItemSnapshot<V> | undefined;\n return (): ProjectionItemSnapshot<V> => {\n const value = item.current();\n const revision = item.revision();\n if (snapshot && revision === previousRevision) return snapshot;\n previousRevision = revision;\n snapshot = { value, revision };\n return snapshot;\n };\n }, [item]);\n const subscribe = useCallback((listener: () => void) => item.subscribe(listener), [item]);\n return useSyncExternalStore(subscribe, read, read).value;\n}\n\nexport function useSetProjection<T>(\n projection: InputProjection<T>,\n store?: ProjectionStore\n): (value: T) => void {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n return useCallback((value: T) => owner.set(projection, value), [owner, projection]);\n}\n\nexport type DocumentSelectorOptions<TResult> = {\n readonly isEqual?: (previous: TResult, next: TResult) => boolean;\n readonly server?: () => TResult;\n};\n\ntype SelectorCache<TSchema extends ObjectNode, TResult> = {\n readonly runtime: DocumentReadable<TSchema>;\n readonly value: TResult;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\nconst objectIs = <T>(previous: T, next: T): boolean => Object.is(previous, next);\nconst sameTargets = (\n left: readonly ImpactTarget<unknown>[],\n right: readonly ImpactTarget<unknown>[]\n): boolean => {\n if (left.length !== right.length) return false;\n for (let index = 0; index < left.length; index += 1)\n if (!sameTarget(left[index], right[index])) return false;\n return true;\n};\n\nexport function useDocumentSelector<TSchema extends ObjectNode, TResult>(\n runtime: DocumentReadable<TSchema>,\n selector: DocumentSelector<TSchema, TResult>,\n options?: DocumentSelectorOptions<TResult>\n): TResult {\n const equality = options?.isEqual ?? objectIs;\n const cache = useRef<SelectorCache<TSchema, TResult> | undefined>(undefined);\n const serverCache = useRef<\n | {\n readonly runtime: DocumentReadable<TSchema>;\n readonly selector: DocumentSelector<TSchema, TResult>;\n readonly source: (() => TResult) | undefined;\n readonly value: TResult;\n }\n | undefined\n >(undefined);\n\n const read = useMemo(() => {\n // Each selector closure owns its revision cache, including inline selectors\n // that allocate arrays or objects. Equality only compares distinct snapshots.\n let snapshot: { readonly revision: number; readonly value: TResult } | undefined;\n return (): TResult => {\n const revision = runtime.revision();\n if (snapshot?.revision === revision) return snapshot.value;\n const selection = track(runtime, selector);\n const previous = cache.current;\n const value =\n previous && previous.runtime === runtime && equality(previous.value, selection.value)\n ? previous.value\n : selection.value;\n cache.current = { runtime, value, targets: selection.targets };\n snapshot = { revision, value };\n return value;\n };\n }, [equality, runtime, selector]);\n\n const subscribe = useCallback(\n (listener: () => void) => {\n read();\n let targets = cache.current?.targets ?? [];\n let unsubscribe: () => void = () => undefined;\n const install = () => {\n if (targets.length === 0) return () => undefined;\n return subscribeDependencies(runtime, targets, onCommit);\n };\n const onCommit = () => {\n const previous = cache.current;\n const next = read();\n const nextTargets = cache.current?.targets ?? [];\n if (!sameTargets(targets, nextTargets)) {\n unsubscribe();\n targets = nextTargets;\n unsubscribe = install();\n }\n if (previous && !Object.is(previous.value, next)) listener();\n };\n unsubscribe = install();\n return () => unsubscribe();\n },\n [read, runtime]\n );\n\n const server = options?.server;\n const readServer = useCallback((): TResult => {\n const previous = serverCache.current;\n if (\n previous &&\n previous.source === server &&\n previous.runtime === runtime &&\n previous.selector === selector\n )\n return previous.value;\n const value = server ? server() : read();\n serverCache.current = { runtime, selector, source: server, value };\n return value;\n }, [read, server, runtime, selector]);\n\n return useSyncExternalStore(subscribe, read, readServer);\n}\n\nexport function useReadable<T>(readable: Readable<T>): T {\n const subscribe = useCallback((listener: () => void) => readable.subscribe(listener), [readable]);\n const read = useCallback(() => readable.current(), [readable]);\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport function useHistory<TCommit>(history: LocalHistory<TCommit>): HistoryState & {\n undo(): OperationResult<TCommit>;\n redo(): OperationResult<TCommit>;\n} {\n const subscribe = useCallback((listener: () => void) => history.subscribe(listener), [history]);\n const read = useCallback(() => history.current(), [history]);\n const state = useSyncExternalStore(subscribe, read, read);\n const undo = useCallback(() => history.undo(), [history]);\n const redo = useCallback(() => history.redo(), [history]);\n\n return useMemo(() => ({ ...state, undo, redo }), [redo, state, undo]);\n}\n"],"mappings":"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"}
@@ -239,6 +239,7 @@ declare const createProjectionEngine: (options: {
239
239
  type ProjectionStore = {
240
240
  get<K extends string, V>(projection: CollectionProjection<K, V>): CollectionRead<K, V>;
241
241
  get<T>(projection: ValueProjection<T>): T;
242
+ item<K extends string, V>(projection: CollectionProjection<K, V>, key: K): Readable<V | undefined>;
242
243
  set<T>(projection: InputProjection<T>, value: T): void;
243
244
  subscribe<K extends string, V>(projection: CollectionProjection<K, V>, listener: (change: CollectionImpact<K>) => void): Unsubscribe;
244
245
  subscribe<T>(projection: ValueProjection<T>, listener: () => void): Unsubscribe;
@@ -259,4 +260,4 @@ declare const createProjectionStore: (options: {
259
260
  }) => ProjectionStore;
260
261
  //#endregion
261
262
  export { ProjectionDisposedError as C, project as S, ProjectionSources as _, AdvancedCollectionSpec as a, ValueProjection as b, CollectionProjection as c, DocumentCollectionProjection as d, DocumentEvent as f, ProjectionEvents as g, Projection as h, AdvancedCollectionProcess as i, CollectionSource as l, InputProjection as m, createProjectionStore as n, AdvancedValueSpec as o, DocumentProjection as p, projectionStoreDebug as r, CollectionEvent as s, ProjectionStore as t, DocumentCollectionEvent as u, ProjectionValues as v, ProjectionError as w, input as x, ValueEvent as y };
262
- //# sourceMappingURL=store-Bs0C0rNd.d.ts.map
263
+ //# sourceMappingURL=store-2i8pYXqa.d.ts.map
@@ -2514,6 +2514,11 @@ const createProjectionStore = (options) => {
2514
2514
  if ("current" in instance && typeof instance.current === "function") return instance.current();
2515
2515
  throw new TypeError("Projection is a source and has no published value.");
2516
2516
  }),
2517
+ item: ((projection, key) => {
2518
+ const instance = materialize(projection);
2519
+ if (!("item" in instance) || typeof instance.item !== "function") throw new TypeError("Projection is not a materialized collection.");
2520
+ return instance.item(key);
2521
+ }),
2517
2522
  set: (projection, value) => {
2518
2523
  materialize(projection);
2519
2524
  const target = inputs.get(projection);
@@ -2551,4 +2556,4 @@ const createProjectionStore = (options) => {
2551
2556
  //#endregion
2552
2557
  export { object as A, parse as B, createAccess as C, field as D, compilePath as E, ParseError as F, checkKey as I, checkValue as L, table as M, tree as N, list as O, variant as P, copyValue as R, same as S, snapshot as T, readWith as _, input as a, TransactionRejected as b, createNotification as c, shareNotification as d, subscribeDependencies as f, bindRuntimeAccess as g, accessOf as h, ProjectionError as i, optional as j, map as k, disposeNotification as l, subscribeTargets as m, projectionStoreDebug as n, project as o, subscribeRoot as p, ProjectionDisposedError as r, bindDocumentReadable as s, createProjectionStore as t, notify as u, DocumentDisposedError as v, replace as w, createImpact as x, DocumentReentrancyError as y, equalValue as z };
2553
2558
 
2554
- //# sourceMappingURL=store-DHFXfWSz.js.map
2559
+ //# sourceMappingURL=store-7XBEcR8s.js.map