@adobe/data 0.9.60 → 0.9.62

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 (222) hide show
  1. package/dist/ecs/archetype/archetype.d.ts +9 -2
  2. package/dist/ecs/archetype/archetype.js.map +1 -1
  3. package/dist/ecs/archetype/create-archetype.js +5 -2
  4. package/dist/ecs/archetype/create-archetype.js.map +1 -1
  5. package/dist/ecs/database/combine-plugins.d.ts +5 -1
  6. package/dist/ecs/database/combine-plugins.js +3 -3
  7. package/dist/ecs/database/combine-plugins.js.map +1 -1
  8. package/dist/ecs/database/concurrency/concurrency-strategy.d.ts +86 -0
  9. package/dist/ecs/database/concurrency/concurrency-strategy.js +3 -0
  10. package/dist/ecs/database/concurrency/concurrency-strategy.js.map +1 -0
  11. package/dist/ecs/database/concurrency/immediate-concurrency.d.ts +22 -0
  12. package/dist/ecs/database/concurrency/immediate-concurrency.js +74 -0
  13. package/dist/ecs/database/concurrency/immediate-concurrency.js.map +1 -0
  14. package/dist/ecs/database/concurrency/index.d.ts +4 -0
  15. package/dist/ecs/database/concurrency/index.js +5 -0
  16. package/dist/ecs/database/concurrency/index.js.map +1 -0
  17. package/dist/ecs/database/concurrency/rebase-replay-concurrency.d.ts +20 -0
  18. package/dist/ecs/database/concurrency/rebase-replay-concurrency.js +34 -0
  19. package/dist/ecs/database/concurrency/rebase-replay-concurrency.js.map +1 -0
  20. package/dist/ecs/database/concurrency/roll-forward-concurrency.d.ts +33 -0
  21. package/dist/ecs/database/concurrency/roll-forward-concurrency.js +115 -0
  22. package/dist/ecs/database/concurrency/roll-forward-concurrency.js.map +1 -0
  23. package/dist/ecs/database/concurrency/roll-forward-concurrency.test.d.ts +1 -0
  24. package/dist/ecs/database/concurrency/roll-forward-concurrency.test.js +136 -0
  25. package/dist/ecs/database/concurrency/roll-forward-concurrency.test.js.map +1 -0
  26. package/dist/ecs/database/create-plugin.d.ts +17 -14
  27. package/dist/ecs/database/create-plugin.js +2 -1
  28. package/dist/ecs/database/create-plugin.js.map +1 -1
  29. package/dist/ecs/database/database.d.ts +61 -11
  30. package/dist/ecs/database/database.index.performance.test.d.ts +1 -0
  31. package/dist/ecs/database/database.index.performance.test.js +417 -0
  32. package/dist/ecs/database/database.index.performance.test.js.map +1 -0
  33. package/dist/ecs/database/database.index.test.d.ts +1 -0
  34. package/dist/ecs/database/database.index.test.js +1142 -0
  35. package/dist/ecs/database/database.index.test.js.map +1 -0
  36. package/dist/ecs/database/database.index.type-test.d.ts +1 -0
  37. package/dist/ecs/database/database.index.type-test.js +275 -0
  38. package/dist/ecs/database/database.index.type-test.js.map +1 -0
  39. package/dist/ecs/database/database.js.map +1 -1
  40. package/dist/ecs/database/database.reset.test.js +2 -1
  41. package/dist/ecs/database/database.reset.test.js.map +1 -1
  42. package/dist/ecs/database/deep-extends-chain.type-test.d.ts +256 -256
  43. package/dist/ecs/database/index-api-proof.type-test.d.ts +1 -0
  44. package/dist/ecs/database/index-api-proof.type-test.js +88 -0
  45. package/dist/ecs/database/index-api-proof.type-test.js.map +1 -0
  46. package/dist/ecs/database/index-registry/create-index-registry.d.ts +53 -0
  47. package/dist/ecs/database/index-registry/create-index-registry.js +174 -0
  48. package/dist/ecs/database/index-registry/create-index-registry.js.map +1 -0
  49. package/dist/ecs/database/index-registry/create-index.d.ts +60 -0
  50. package/dist/ecs/database/index-registry/create-index.js +539 -0
  51. package/dist/ecs/database/index-registry/create-index.js.map +1 -0
  52. package/dist/ecs/database/index-registry/index.d.ts +4 -0
  53. package/dist/ecs/database/index-registry/index.js +4 -0
  54. package/dist/ecs/database/index-registry/index.js.map +1 -0
  55. package/dist/ecs/database/index.d.ts +1 -0
  56. package/dist/ecs/database/index.js +1 -0
  57. package/dist/ecs/database/index.js.map +1 -1
  58. package/dist/ecs/database/observe-index-entities.d.ts +26 -0
  59. package/dist/ecs/database/observe-index-entities.js +66 -0
  60. package/dist/ecs/database/observe-index-entities.js.map +1 -0
  61. package/dist/ecs/database/observed/create-observed-database.js +1 -1
  62. package/dist/ecs/database/observed/create-observed-database.js.map +1 -1
  63. package/dist/ecs/database/observed/observed-database.d.ts +1 -1
  64. package/dist/ecs/database/public/create-database.d.ts +12 -27
  65. package/dist/ecs/database/public/create-database.js +252 -10
  66. package/dist/ecs/database/public/create-database.js.map +1 -1
  67. package/dist/ecs/database/public/create-database.test.js +8 -7
  68. package/dist/ecs/database/public/create-database.test.js.map +1 -1
  69. package/dist/ecs/database/public/create-transaction-dispatcher.d.ts +4 -2
  70. package/dist/ecs/database/public/create-transaction-dispatcher.js +2 -8
  71. package/dist/ecs/database/public/create-transaction-dispatcher.js.map +1 -1
  72. package/dist/ecs/database/reconciling/create-rebase-replay-applier.d.ts +26 -0
  73. package/dist/ecs/database/reconciling/create-rebase-replay-applier.js +121 -0
  74. package/dist/ecs/database/reconciling/create-rebase-replay-applier.js.map +1 -0
  75. package/dist/ecs/database/reconciling/create-reconciling-database.d.ts +11 -0
  76. package/dist/ecs/database/reconciling/create-reconciling-database.js +28 -137
  77. package/dist/ecs/database/reconciling/create-reconciling-database.js.map +1 -1
  78. package/dist/ecs/database/transactional-store/create-transactional-store.js.map +1 -1
  79. package/dist/ecs/database/transactional-store/transactional-store.d.ts +4 -3
  80. package/dist/ecs/entity-location-table/create-entity-location-table.js +2 -2
  81. package/dist/ecs/entity-location-table/create-entity-location-table.js.map +1 -1
  82. package/dist/ecs/entity-location-table/entity-location-table.d.ts +7 -1
  83. package/dist/ecs/plugins/scheduler/scheduler.d.ts +1 -0
  84. package/dist/ecs/store/core/core.d.ts +7 -1
  85. package/dist/ecs/store/core/create-core.js +3 -3
  86. package/dist/ecs/store/core/create-core.js.map +1 -1
  87. package/dist/ecs/store/index-types.d.ts +142 -0
  88. package/dist/ecs/store/index-types.js +3 -0
  89. package/dist/ecs/store/index-types.js.map +1 -0
  90. package/dist/ecs/store/public/create-store.js +206 -4
  91. package/dist/ecs/store/public/create-store.js.map +1 -1
  92. package/dist/ecs/store/public/create-store.test.js +25 -0
  93. package/dist/ecs/store/public/create-store.test.js.map +1 -1
  94. package/dist/ecs/store/store.d.ts +38 -14
  95. package/dist/ecs/store/store.js +5 -4
  96. package/dist/ecs/store/store.js.map +1 -1
  97. package/dist/ecs/store/transaction-functions.d.ts +4 -3
  98. package/dist/schema/fractional-index/between-n.d.ts +2 -0
  99. package/dist/schema/fractional-index/between-n.js +34 -0
  100. package/dist/schema/fractional-index/between-n.js.map +1 -0
  101. package/dist/schema/fractional-index/between-n.test.d.ts +1 -0
  102. package/dist/schema/fractional-index/between-n.test.js +36 -0
  103. package/dist/schema/fractional-index/between-n.test.js.map +1 -0
  104. package/dist/schema/fractional-index/between.d.ts +2 -0
  105. package/dist/schema/fractional-index/between.js +3 -0
  106. package/dist/schema/fractional-index/between.js.map +1 -0
  107. package/dist/schema/fractional-index/between.test.d.ts +1 -0
  108. package/dist/schema/fractional-index/between.test.js +68 -0
  109. package/dist/schema/fractional-index/between.test.js.map +1 -0
  110. package/dist/schema/fractional-index/decrement-integer.d.ts +1 -0
  111. package/dist/schema/fractional-index/decrement-integer.js +32 -0
  112. package/dist/schema/fractional-index/decrement-integer.js.map +1 -0
  113. package/dist/schema/fractional-index/decrement-integer.test.d.ts +1 -0
  114. package/dist/schema/fractional-index/decrement-integer.test.js +31 -0
  115. package/dist/schema/fractional-index/decrement-integer.test.js.map +1 -0
  116. package/dist/schema/fractional-index/digits.d.ts +1 -0
  117. package/dist/schema/fractional-index/digits.js +3 -0
  118. package/dist/schema/fractional-index/digits.js.map +1 -0
  119. package/dist/schema/fractional-index/fractional-index.d.ts +4 -0
  120. package/dist/schema/fractional-index/fractional-index.js +2 -0
  121. package/dist/schema/fractional-index/fractional-index.js.map +1 -0
  122. package/dist/schema/fractional-index/increment-integer.d.ts +1 -0
  123. package/dist/schema/fractional-index/increment-integer.js +32 -0
  124. package/dist/schema/fractional-index/increment-integer.js.map +1 -0
  125. package/dist/schema/fractional-index/increment-integer.test.d.ts +1 -0
  126. package/dist/schema/fractional-index/increment-integer.test.js +34 -0
  127. package/dist/schema/fractional-index/increment-integer.test.js.map +1 -0
  128. package/dist/schema/fractional-index/initial.d.ts +2 -0
  129. package/dist/schema/fractional-index/initial.js +2 -0
  130. package/dist/schema/fractional-index/initial.js.map +1 -0
  131. package/dist/schema/fractional-index/integer-length.d.ts +1 -0
  132. package/dist/schema/fractional-index/integer-length.js +9 -0
  133. package/dist/schema/fractional-index/integer-length.js.map +1 -0
  134. package/dist/schema/fractional-index/integer-part.d.ts +1 -0
  135. package/dist/schema/fractional-index/integer-part.js +9 -0
  136. package/dist/schema/fractional-index/integer-part.js.map +1 -0
  137. package/dist/schema/fractional-index/key-between.d.ts +2 -0
  138. package/dist/schema/fractional-index/key-between.js +39 -0
  139. package/dist/schema/fractional-index/key-between.js.map +1 -0
  140. package/dist/schema/fractional-index/midpoint.d.ts +1 -0
  141. package/dist/schema/fractional-index/midpoint.js +23 -0
  142. package/dist/schema/fractional-index/midpoint.js.map +1 -0
  143. package/dist/schema/fractional-index/midpoint.test.d.ts +1 -0
  144. package/dist/schema/fractional-index/midpoint.test.js +83 -0
  145. package/dist/schema/fractional-index/midpoint.test.js.map +1 -0
  146. package/dist/schema/fractional-index/public.d.ts +4 -0
  147. package/dist/schema/fractional-index/public.js +6 -0
  148. package/dist/schema/fractional-index/public.js.map +1 -0
  149. package/dist/schema/fractional-index/schema.d.ts +4 -0
  150. package/dist/schema/fractional-index/schema.js +5 -0
  151. package/dist/schema/fractional-index/schema.js.map +1 -0
  152. package/dist/schema/fractional-index/smallest-integer.d.ts +1 -0
  153. package/dist/schema/fractional-index/smallest-integer.js +3 -0
  154. package/dist/schema/fractional-index/smallest-integer.js.map +1 -0
  155. package/dist/schema/fractional-index/validate-integer.d.ts +1 -0
  156. package/dist/schema/fractional-index/validate-integer.js +7 -0
  157. package/dist/schema/fractional-index/validate-integer.js.map +1 -0
  158. package/dist/schema/fractional-index/validate-order-key.d.ts +1 -0
  159. package/dist/schema/fractional-index/validate-order-key.js +11 -0
  160. package/dist/schema/fractional-index/validate-order-key.js.map +1 -0
  161. package/dist/schema/guid/create.d.ts +2 -0
  162. package/dist/schema/guid/create.js +10 -0
  163. package/dist/schema/guid/create.js.map +1 -0
  164. package/dist/schema/guid/create.test.d.ts +1 -0
  165. package/dist/schema/guid/create.test.js +39 -0
  166. package/dist/schema/guid/create.test.js.map +1 -0
  167. package/dist/schema/guid/equals.d.ts +2 -0
  168. package/dist/schema/guid/equals.js +3 -0
  169. package/dist/schema/guid/equals.js.map +1 -0
  170. package/dist/schema/guid/equals.test.d.ts +1 -0
  171. package/dist/schema/guid/equals.test.js +30 -0
  172. package/dist/schema/guid/equals.test.js.map +1 -0
  173. package/dist/schema/guid/from-uuid.d.ts +2 -0
  174. package/dist/schema/guid/from-uuid.js +15 -0
  175. package/dist/schema/guid/from-uuid.js.map +1 -0
  176. package/dist/schema/guid/from-uuid.test.d.ts +1 -0
  177. package/dist/schema/guid/from-uuid.test.js +39 -0
  178. package/dist/schema/guid/from-uuid.test.js.map +1 -0
  179. package/dist/schema/guid/guid.performance.test.d.ts +1 -0
  180. package/dist/schema/guid/guid.performance.test.js +297 -0
  181. package/dist/schema/guid/guid.performance.test.js.map +1 -0
  182. package/dist/schema/guid/index.d.ts +4 -0
  183. package/dist/schema/guid/index.js +3 -0
  184. package/dist/schema/guid/index.js.map +1 -0
  185. package/dist/schema/guid/layout.d.ts +1 -0
  186. package/dist/schema/guid/layout.js +5 -0
  187. package/dist/schema/guid/layout.js.map +1 -0
  188. package/dist/schema/guid/nil.d.ts +2 -0
  189. package/dist/schema/guid/nil.js +3 -0
  190. package/dist/schema/guid/nil.js.map +1 -0
  191. package/dist/schema/guid/public.d.ts +8 -0
  192. package/dist/schema/guid/public.js +10 -0
  193. package/dist/schema/guid/public.js.map +1 -0
  194. package/dist/schema/guid/schema.d.ts +12 -0
  195. package/dist/schema/guid/schema.js +10 -0
  196. package/dist/schema/guid/schema.js.map +1 -0
  197. package/dist/schema/guid/schema.test.d.ts +1 -0
  198. package/dist/schema/guid/schema.test.js +35 -0
  199. package/dist/schema/guid/schema.test.js.map +1 -0
  200. package/dist/schema/guid/to-unserializable-key.d.ts +2 -0
  201. package/dist/schema/guid/to-unserializable-key.js +10 -0
  202. package/dist/schema/guid/to-unserializable-key.js.map +1 -0
  203. package/dist/schema/guid/to-uuid.d.ts +2 -0
  204. package/dist/schema/guid/to-uuid.js +15 -0
  205. package/dist/schema/guid/to-uuid.js.map +1 -0
  206. package/dist/schema/guid/to-uuid.test.d.ts +1 -0
  207. package/dist/schema/guid/to-uuid.test.js +31 -0
  208. package/dist/schema/guid/to-uuid.test.js.map +1 -0
  209. package/dist/schema/index.d.ts +2 -0
  210. package/dist/schema/index.js +2 -0
  211. package/dist/schema/index.js.map +1 -1
  212. package/dist/table/select-rows.d.ts +7 -4
  213. package/dist/table/select-rows.js.map +1 -1
  214. package/dist/test-setup.js +2 -2
  215. package/dist/test-setup.js.map +1 -1
  216. package/dist/tsconfig.tsbuildinfo +1 -1
  217. package/package.json +3 -1
  218. package/references/data-lit/package.json +1 -1
  219. package/references/data-lit-tictactoe/package.json +1 -1
  220. package/references/data-react/package.json +1 -1
  221. package/references/data-react-hello/package.json +1 -1
  222. package/references/data-react-pixie/package.json +1 -1
@@ -0,0 +1,136 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+ //
3
+ // Verifies the pluggable-concurrency seam by running a client-side
4
+ // roll-forward replay strategy through the public `createDatabase` API, and
5
+ // contrasting it with the built-in rebase-replay strategy on an identical
6
+ // scenario.
7
+ import { describe, it, expect, vi } from "vitest";
8
+ import { Database } from "../database.js";
9
+ import { createRollForwardConcurrency } from "./roll-forward-concurrency.js";
10
+ import { createRebaseReplayConcurrency } from "./rebase-replay-concurrency.js";
11
+ // A single numeric component is enough to expose the roll-forward vs
12
+ // re-execute difference: one transaction derives its value from current state.
13
+ const plugin = Database.Plugin.create({
14
+ components: {
15
+ counter: { type: "number" },
16
+ },
17
+ resources: {},
18
+ archetypes: {
19
+ Counter: ["counter"],
20
+ },
21
+ transactions: {
22
+ createCounter(t, args) {
23
+ return t.archetypes.Counter.insert({ counter: args.counter });
24
+ },
25
+ // Reads current value and adds 10 — its result depends on the base
26
+ // state it runs against. This is the transaction whose replay semantics
27
+ // distinguish roll-forward from re-execute.
28
+ bumpFromCurrent(t, args) {
29
+ const current = t.read(args.entity)?.counter ?? 0;
30
+ t.update(args.entity, { counter: current + 10 });
31
+ },
32
+ setAbsolute(t, args) {
33
+ t.update(args.entity, { counter: args.value });
34
+ },
35
+ },
36
+ });
37
+ const makeDb = (concurrency) => Database.create(plugin, { concurrency });
38
+ // Seed a server-confirmed entity (positive time) so the entity exists in the
39
+ // committed base before any optimistic local edit. Returns its id.
40
+ const seedCommittedCounter = (db, value) => {
41
+ const result = db.apply({ id: 1, userId: "seed", name: "createCounter", args: { counter: value }, time: Date.now() });
42
+ return result.value;
43
+ };
44
+ describe("createRollForwardConcurrency — pluggable concurrency viability", () => {
45
+ it("plugs into createDatabase and exposes itself as the database concurrency strategy", () => {
46
+ const db = makeDb(createRollForwardConcurrency("A"));
47
+ expect(db.concurrency.deferredCommit).toBe(true);
48
+ expect(db.concurrency.userId).toBe("A");
49
+ });
50
+ it("applies a server-confirmed delta directly", () => {
51
+ const db = makeDb(createRollForwardConcurrency("A"));
52
+ const entity = seedCommittedCounter(db, 42);
53
+ expect(db.read(entity)?.counter).toBe(42);
54
+ });
55
+ it("makes a local optimistic transient visible immediately", () => {
56
+ const db = makeDb(createRollForwardConcurrency("A"));
57
+ const entity = seedCommittedCounter(db, 0);
58
+ db.transactions.bumpFromCurrent({ entity });
59
+ // Deferred-commit: applied locally as a transient before any echo.
60
+ expect(db.read(entity)?.counter).toBe(10);
61
+ });
62
+ it("replays pending edits by rolling captured post-images forward, not by re-executing", () => {
63
+ const db = makeDb(createRollForwardConcurrency("A"));
64
+ const entity = seedCommittedCounter(db, 0);
65
+ // Local optimistic edit: 0 -> 10, captured post-image = "set counter 10".
66
+ db.transactions.bumpFromCurrent({ entity });
67
+ expect(db.read(entity)?.counter).toBe(10);
68
+ // A peer's confirmed delta moves the base out from under the pending edit.
69
+ db.apply({ id: 99, userId: "B", name: "setAbsolute", args: { entity, value: 100 }, time: Date.now() + 1 });
70
+ // Roll-forward replays the *captured tuple* (set counter 10), so the
71
+ // pending edit's original post-image wins — NOT 110 (which is what
72
+ // re-executing bumpFromCurrent against the new base of 100 would give).
73
+ expect(db.read(entity)?.counter).toBe(10);
74
+ });
75
+ it("cancel discards a pending transient and restores committed state", () => {
76
+ const db = makeDb(createRollForwardConcurrency("A"));
77
+ const entity = seedCommittedCounter(db, 5);
78
+ // Drive a cancellable transient through the dispatcher via an async
79
+ // generator that yields once then throws (cleanly tears down).
80
+ const observer = vi.fn();
81
+ const unobserve = db.observe.entity(entity)(observer);
82
+ db.transactions.bumpFromCurrent({ entity });
83
+ expect(db.read(entity)?.counter).toBe(15);
84
+ // Cancel the pending entry by its dispatcher-assigned id. The first
85
+ // (and only) wrapped transaction gets id 1 from the dispatcher counter.
86
+ db.cancel(1, "A");
87
+ expect(db.read(entity)?.counter).toBe(5);
88
+ unobserve();
89
+ });
90
+ it("reset clears the pending buffer", () => {
91
+ const db = makeDb(createRollForwardConcurrency("A"));
92
+ const entity = seedCommittedCounter(db, 0);
93
+ db.transactions.bumpFromCurrent({ entity });
94
+ expect(db.read(entity)?.counter).toBe(10);
95
+ db.reset();
96
+ // Store is empty and the pending buffer is gone — re-seeding starts clean.
97
+ const reseeded = seedCommittedCounter(db, 7);
98
+ expect(db.read(reseeded)?.counter).toBe(7);
99
+ });
100
+ it("toData serializes only committed state and leaves the live transient intact", () => {
101
+ const db = makeDb(createRollForwardConcurrency("A"));
102
+ const entity = seedCommittedCounter(db, 0);
103
+ db.transactions.bumpFromCurrent({ entity });
104
+ expect(db.read(entity)?.counter).toBe(10);
105
+ const snapshot = db.toData();
106
+ // The live optimistic transient survives the rollback→serialize→replay.
107
+ expect(db.read(entity)?.counter).toBe(10);
108
+ // The snapshot is a detached copy of committed state only: loading it
109
+ // into a fresh database yields the committed base (0), not the pending
110
+ // optimistic value (10). This must hold even though `onAfterToData`
111
+ // replayed the transient back onto the live store after serialization.
112
+ const loaded = Database.create(plugin);
113
+ loaded.fromData(snapshot);
114
+ const loadedValues = loaded.select(["counter"]).map(e => loaded.read(e)?.counter);
115
+ expect(loadedValues).toEqual([0]);
116
+ });
117
+ });
118
+ describe("roll-forward vs rebase-replay — same seam, different replay semantics", () => {
119
+ // Identical scenario, swapping only the concurrency strategy factory. The
120
+ // divergent result proves the two engines are genuinely different and that
121
+ // the pluggable seam selects between them with no other changes.
122
+ const runRebaseScenario = (concurrency) => {
123
+ const db = makeDb(concurrency);
124
+ const entity = seedCommittedCounter(db, 0);
125
+ db.transactions.bumpFromCurrent({ entity });
126
+ db.apply({ id: 99, userId: "B", name: "setAbsolute", args: { entity, value: 100 }, time: Date.now() + 1 });
127
+ return db.read(entity)?.counter ?? NaN;
128
+ };
129
+ it("roll-forward preserves the captured post-image (10)", () => {
130
+ expect(runRebaseScenario(createRollForwardConcurrency("A"))).toBe(10);
131
+ });
132
+ it("rebase-replay re-executes against the new base (110)", () => {
133
+ expect(runRebaseScenario(createRebaseReplayConcurrency("A"))).toBe(110);
134
+ });
135
+ });
136
+ //# sourceMappingURL=roll-forward-concurrency.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roll-forward-concurrency.test.js","sourceRoot":"","sources":["../../../../src/ecs/database/concurrency/roll-forward-concurrency.test.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Database, SystemFunction, ServiceFactories, FromServiceFactories, FromComputedFactories, type PluginComputedFactories } from "./database.js";
1
+ import { Database, SystemFunction, ServiceFactories, FromServiceFactories, FromComputedFactories, type PluginComputedFactories, type IndexDeclarations } from "./database.js";
2
2
  import type { ComponentSchemas } from "../component-schemas.js";
3
3
  import type { ResourceSchemas } from "../resource-schemas.js";
4
4
  import type { ArchetypeComponents } from "../store/archetype-components.js";
@@ -14,7 +14,7 @@ import { Store } from "../store/store.js";
14
14
  * inference (`CombinePlugins<[XP, ...]>`) to avoid expensive 8-way type
15
15
  * expansion that amplifies TS7056 serialization overflow.
16
16
  */
17
- type CreatePluginResult<XP extends Database.Plugin, CS, RS, A, TD, S extends string, AD, SVF, CVF> = Database.Plugin<XP['components'] & CS, XP['resources'] & RS, XP['archetypes'] & A, XP['transactions'] & TD, S | StringKeyof<XP['systems']>, XP['actions'] & AD, XP['services'] & SVF, XP['computed'] & CVF>;
17
+ type CreatePluginResult<XP extends Database.Plugin, CS, RS, A, TD, S extends string, AD, SVF, CVF, IX> = Database.Plugin<XP['components'] & CS, XP['resources'] & RS, XP['archetypes'] & A, XP['transactions'] & TD, S | StringKeyof<XP['systems']>, XP['actions'] & AD, XP['services'] & SVF, XP['computed'] & CVF, XP['indexes'] & IX>;
18
18
  /**
19
19
  * Creates a Database.Plugin from a plugin descriptor.
20
20
  *
@@ -26,10 +26,11 @@ type CreatePluginResult<XP extends Database.Plugin, CS, RS, A, TD, S extends str
26
26
  * 3. components (optional) - Component schema definitions
27
27
  * 4. resources (optional) - Resource schema definitions
28
28
  * 5. archetypes (optional) - Archetype definitions
29
- * 6. computed (optional) - Computed observe factories (each returns Observe<unknown>)
30
- * 7. transactions (optional) - Transaction declarations
31
- * 8. actions (optional) - Action declarations
32
- * 9. systems (optional) - System declarations
29
+ * 6. indexes (optional) - Index declarations over components
30
+ * 7. computed (optional) - Computed observe factories (each returns Observe<unknown>)
31
+ * 8. transactions (optional) - Transaction declarations
32
+ * 9. actions (optional) - Action declarations
33
+ * 10. systems (optional) - System declarations
33
34
  *
34
35
  * Example:
35
36
  * ```ts
@@ -41,10 +42,11 @@ type CreatePluginResult<XP extends Database.Plugin, CS, RS, A, TD, S extends str
41
42
  * components: { ... }, // 3. components
42
43
  * resources: { ... }, // 4. resources
43
44
  * archetypes: { ... }, // 5. archetypes
44
- * computed: { ... }, // 6. computed
45
- * transactions: { ... }, // 7. transactions
46
- * actions: { ... }, // 8. actions
47
- * systems: { ... }, // 9. systems
45
+ * indexes: { ... }, // 6. indexes
46
+ * computed: { ... }, // 7. computed
47
+ * transactions: { ... }, // 8. transactions
48
+ * actions: { ... }, // 9. actions
49
+ * systems: { ... }, // 10. systems
48
50
  * })
49
51
  * ```
50
52
  *
@@ -60,7 +62,7 @@ type CreatePluginResult<XP extends Database.Plugin, CS, RS, A, TD, S extends str
60
62
  * @throws Error if properties are not in the correct order
61
63
  */
62
64
  type FullDBForPlugin<CS, RS, A, TD, S extends string, AD, XP extends Database.Plugin, SVF extends ServiceFactories<Database.FromPlugin<XP>>> = Database<FromSchemas<CS & XP['components']>, FromSchemas<RS & XP['resources']>, A & XP['archetypes'], ToTransactionFunctions<TD & XP['transactions']>, S | StringKeyof<XP['systems']>, ToActionFunctions<AD & XP['actions']>, FromServiceFactories<RemoveIndex<SVF> & XP['services']>>;
63
- export declare function createPlugin<const XP extends Database.Plugin<{}, {}, {}, {}, never, {}, {}, {}>, const CS extends ComponentSchemas, const RS extends ResourceSchemas, const A extends ArchetypeComponents<StringKeyof<RemoveIndex<CS> & XP['components']>>, const TD extends TransactionDeclarations<FromSchemas<RemoveIndex<CS> & XP['components']>, FromSchemas<RemoveIndex<RS> & XP['resources']>, RemoveIndex<A> & XP['archetypes']>, const AD, const S extends string = never, const SVF extends ServiceFactories<Database.FromPlugin<XP>> = {}, const CVF extends PluginComputedFactories<FullDBForPlugin<RemoveIndex<CS>, RemoveIndex<RS>, RemoveIndex<A>, RemoveIndex<TD>, S, RemoveIndex<AD> & XP['actions'], XP, RemoveIndex<SVF>>> = {}>(plugins: {
65
+ export declare function createPlugin<const XP extends Database.Plugin<{}, {}, {}, {}, never, {}, {}, {}, {}>, const CS extends ComponentSchemas, const RS extends ResourceSchemas, const A extends ArchetypeComponents<StringKeyof<RemoveIndex<CS> & XP['components']>>, const IX extends IndexDeclarations<FromSchemas<RemoveIndex<CS> & XP['components']>>, const TD extends TransactionDeclarations<FromSchemas<RemoveIndex<CS> & XP['components']>, FromSchemas<RemoveIndex<RS> & XP['resources']>, RemoveIndex<A> & XP['archetypes'], RemoveIndex<IX> & XP['indexes']>, const AD, const S extends string = never, const SVF extends ServiceFactories<Database.FromPlugin<XP>> = {}, const CVF extends PluginComputedFactories<FullDBForPlugin<RemoveIndex<CS>, RemoveIndex<RS>, RemoveIndex<A>, RemoveIndex<TD>, S, RemoveIndex<AD> & XP['actions'], XP, RemoveIndex<SVF>>> = {}>(plugins: {
64
66
  extends?: XP;
65
67
  services?: SVF & {
66
68
  readonly [K: string]: (db: Database.FromPlugin<XP>) => unknown;
@@ -68,14 +70,15 @@ export declare function createPlugin<const XP extends Database.Plugin<{}, {}, {}
68
70
  components?: CS;
69
71
  resources?: RS;
70
72
  archetypes?: A;
73
+ indexes?: IX;
71
74
  computed?: CVF & PluginComputedFactories<FullDBForPlugin<RemoveIndex<CS>, RemoveIndex<RS>, RemoveIndex<A>, {}, string, RemoveIndex<AD> & XP['actions'], XP, RemoveIndex<SVF>>>;
72
75
  transactions?: TD;
73
76
  actions?: AD & {
74
- readonly [K: string]: (db: Database<FromSchemas<RemoveIndex<CS> & XP['components']>, FromSchemas<RemoveIndex<RS> & XP['resources']>, RemoveIndex<A> & XP['archetypes'], ToTransactionFunctions<RemoveIndex<TD> & XP['transactions']>, S | StringKeyof<XP['systems']>, ToActionFunctions<XP['actions']>, FromServiceFactories<RemoveIndex<SVF> & XP['services']>, FromComputedFactories<RemoveIndex<CVF> & XP['computed']>>, input?: any) => any;
77
+ readonly [K: string]: (db: Database<FromSchemas<RemoveIndex<CS> & XP['components']>, FromSchemas<RemoveIndex<RS> & XP['resources']>, RemoveIndex<A> & XP['archetypes'], ToTransactionFunctions<RemoveIndex<TD> & XP['transactions']>, S | StringKeyof<XP['systems']>, ToActionFunctions<XP['actions']>, FromServiceFactories<RemoveIndex<SVF> & XP['services']>, FromComputedFactories<RemoveIndex<CVF> & XP['computed']>, RemoveIndex<IX> & XP['indexes']>, input?: any) => any;
75
78
  };
76
79
  systems?: {
77
80
  readonly [K in S]: {
78
- readonly create: (db: Database<FromSchemas<RemoveIndex<CS> & XP['components']>, FromSchemas<RemoveIndex<RS> & XP['resources']>, RemoveIndex<A> & XP['archetypes'], ToTransactionFunctions<RemoveIndex<TD> & XP['transactions']>, S | StringKeyof<XP['systems']>, ToActionFunctions<RemoveIndex<AD> & XP['actions']>, FromServiceFactories<RemoveIndex<SVF> & XP['services']>, FromComputedFactories<RemoveIndex<CVF> & XP['computed']>> & {
81
+ readonly create: (db: Database<FromSchemas<RemoveIndex<CS> & XP['components']>, FromSchemas<RemoveIndex<RS> & XP['resources']>, RemoveIndex<A> & XP['archetypes'], ToTransactionFunctions<RemoveIndex<TD> & XP['transactions']>, S | StringKeyof<XP['systems']>, ToActionFunctions<RemoveIndex<AD> & XP['actions']>, FromServiceFactories<RemoveIndex<SVF> & XP['services']>, FromComputedFactories<RemoveIndex<CVF> & XP['computed']>, RemoveIndex<IX> & XP['indexes']> & {
79
82
  readonly store: Store<FromSchemas<RemoveIndex<CS> & XP['components']>, FromSchemas<RemoveIndex<RS> & XP['resources']>, RemoveIndex<A> & XP['archetypes']>;
80
83
  services: {
81
84
  -readonly [K in keyof FromServiceFactories<RemoveIndex<SVF> & XP['services']>]: FromServiceFactories<RemoveIndex<SVF> & XP['services']>[K];
@@ -88,5 +91,5 @@ export declare function createPlugin<const XP extends Database.Plugin<{}, {}, {}
88
91
  };
89
92
  };
90
93
  };
91
- }): CreatePluginResult<XP, RemoveIndex<CS>, RemoveIndex<RS>, RemoveIndex<A>, RemoveIndex<TD>, S, AD, RemoveIndex<SVF>, RemoveIndex<CVF>>;
94
+ }): CreatePluginResult<XP, RemoveIndex<CS>, RemoveIndex<RS>, RemoveIndex<A>, RemoveIndex<TD>, S, AD, RemoveIndex<SVF>, RemoveIndex<CVF>, RemoveIndex<IX>>;
92
95
  export {};
@@ -1,7 +1,7 @@
1
1
  // © 2026 Adobe. MIT License. See /LICENSE for details.
2
2
  import { combinePlugins } from "./combine-plugins.js";
3
3
  function validatePropertyOrder(plugins) {
4
- const expectedOrder = ['extends', 'services', 'components', 'resources', 'archetypes', 'computed', 'transactions', 'actions', 'systems'];
4
+ const expectedOrder = ['extends', 'services', 'components', 'resources', 'archetypes', 'indexes', 'computed', 'transactions', 'actions', 'systems'];
5
5
  const actualKeys = Object.keys(plugins);
6
6
  const definedKeys = actualKeys.filter(key => key in plugins);
7
7
  for (let i = 0; i < definedKeys.length; i++) {
@@ -29,6 +29,7 @@ export function createPlugin(plugins) {
29
29
  components: plugins.components ?? {},
30
30
  resources: plugins.resources ?? {},
31
31
  archetypes: plugins.archetypes ?? {},
32
+ indexes: plugins.indexes ?? {},
32
33
  computed: plugins.computed ?? {},
33
34
  transactions: plugins.transactions ?? {},
34
35
  actions: plugins.actions ?? {},
@@ -1 +1 @@
1
- {"version":3,"file":"create-plugin.js","sourceRoot":"","sources":["../../../src/ecs/database/create-plugin.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAUvD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAwCtD,SAAS,qBAAqB,CAAC,OAAgC;IAC3D,MAAM,aAAa,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IACzI,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC;IAE7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,aAAa,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjD,IAAI,aAAa,KAAK,CAAC,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,6CAA6C,GAAG,4BAA4B,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5H,CAAC;QACD,uDAAuD;QACvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,iBAAiB,GAAG,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACzD,IAAI,iBAAiB,GAAG,aAAa,EAAE,CAAC;gBACpC,MAAM,IAAI,KAAK,CACX,qCAAqC,GAAG,uBAAuB,OAAO,KAAK;oBAC3E,mBAAmB,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACrF,CAAC;YACN,CAAC;QACL,CAAC;IACL,CAAC;AACL,CAAC;AA2DD,MAAM,UAAU,YAAY,CAWxB,OA+CC;IAED,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAE/B,mEAAmE;IACnE,MAAM,MAAM,GAAQ;QAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;QAChC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE;QACpC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,EAAE;QAClC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE;QACpC,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;QAChC,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,EAAE;QACxC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;QAC9B,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;KACjC,CAAC;IAEF,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,cAAc,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAQ,CAAC;IAC1D,CAAC;IACD,OAAO,MAAa,CAAC;AACzB,CAAC"}
1
+ {"version":3,"file":"create-plugin.js","sourceRoot":"","sources":["../../../src/ecs/database/create-plugin.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAUvD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA0CtD,SAAS,qBAAqB,CAAC,OAAgC;IAC3D,MAAM,aAAa,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IACpJ,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC;IAE7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,aAAa,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjD,IAAI,aAAa,KAAK,CAAC,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,6CAA6C,GAAG,4BAA4B,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5H,CAAC;QACD,uDAAuD;QACvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,iBAAiB,GAAG,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACzD,IAAI,iBAAiB,GAAG,aAAa,EAAE,CAAC;gBACpC,MAAM,IAAI,KAAK,CACX,qCAAqC,GAAG,uBAAuB,OAAO,KAAK;oBAC3E,mBAAmB,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACrF,CAAC;YACN,CAAC;QACL,CAAC;IACL,CAAC;AACL,CAAC;AA6DD,MAAM,UAAU,YAAY,CAYxB,OAkDC;IAED,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAE/B,mEAAmE;IACnE,MAAM,MAAM,GAAQ;QAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;QAChC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE;QACpC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,EAAE;QAClC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE;QACpC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;QAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;QAChC,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,EAAE;QACxC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;QAC9B,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;KACjC,CAAC;IAEF,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,cAAc,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAQ,CAAC;IAC1D,CAAC;IACD,OAAO,MAAa,CAAC;AACzB,CAAC"}
@@ -11,8 +11,10 @@ import { Components } from "../store/components.js";
11
11
  import { ArchetypeComponents } from "../store/archetype-components.js";
12
12
  import { RequiredComponents } from "../required-components.js";
13
13
  import { EntitySelectOptions } from "../store/entity-select-options.js";
14
+ import { Index as StoreIndex } from "../store/index-types.js";
14
15
  import type { Service } from "../../service/index.js";
15
- import { createDatabase, type DatabaseSyncOptions } from "./public/create-database.js";
16
+ import { createDatabase } from "./public/create-database.js";
17
+ import type { ConcurrencyStrategy } from "./concurrency/concurrency-strategy.js";
16
18
  import { ResourceSchemas } from "../resource-schemas.js";
17
19
  import { ComponentSchemas } from "../component-schemas.js";
18
20
  import { FromSchemas } from "../../schema/index.js";
@@ -78,11 +80,33 @@ export type PluginComputedValue = Observe<unknown> | ((...args: any[]) => Observ
78
80
  export type PluginComputedFactories<DB = any> = {
79
81
  readonly [K: string]: (db: DB) => PluginComputedValue;
80
82
  };
81
- export interface Database<C extends Components = {}, R extends ResourceComponents = {}, A extends ArchetypeComponents<StringKeyof<C>> = {}, F extends TransactionFunctions = {}, S extends string = never, AF extends ActionFunctions = {}, SV = {}, CV = unknown> extends ReadonlyStore<C, R, A>, Service {
83
+ /**
84
+ * Plugin-level map of indexes. Re-exported from `store/index-types.ts`
85
+ * where the canonical definition lives — same module that defines the
86
+ * unified `Index` type (raw + computed) so a single source of truth is
87
+ * shared between the Store layer (`store.indexes` typed handle map) and
88
+ * the Database layer (`db.indexes`, plugin descriptor constraint).
89
+ */
90
+ export type { IndexDeclarations } from "../store/index-types.js";
91
+ import type { IndexDeclarations } from "../store/index-types.js";
92
+ export interface Database<C extends Components = {}, R extends ResourceComponents = {}, A extends ArchetypeComponents<StringKeyof<C>> = {}, F extends TransactionFunctions = {}, S extends string = never, AF extends ActionFunctions = {}, SV = {}, CV = unknown, IX extends IndexDeclarations<C> = {}> extends ReadonlyStore<C, R, A, IX>, Service {
82
93
  readonly transactions: F & Service;
83
94
  readonly actions: AF & Service;
84
95
  readonly services: SV;
85
96
  readonly computed: CV;
97
+ /**
98
+ * Lookup handles for the indexes declared by plugins on this database.
99
+ * Each key in `IX` becomes a `Database.Index.Handle` whose method shape
100
+ * is narrowed by the declared key tuple and unique flag.
101
+ *
102
+ * The handles are also the implementation path used by `db.select` /
103
+ * `db.observe.select` when a `where` / `order` matches a declared
104
+ * index — call sites do not need to be aware of which index served
105
+ * the query, but the same handle is what runs underneath.
106
+ */
107
+ readonly indexes: {
108
+ readonly [K in keyof IX]: Database.Index.Handle<C, IX[K]>;
109
+ };
86
110
  readonly observe: {
87
111
  readonly components: {
88
112
  readonly [K in StringKeyof<C>]: Observe<void>;
@@ -137,13 +161,12 @@ export interface Database<C extends Components = {}, R extends ResourceComponent
137
161
  */
138
162
  readonly cancel: (id: number, userId?: number | string) => void;
139
163
  /**
140
- * The sync options the database was created with, or `undefined` for a
141
- * local-only database. Sync services read this to (a) confirm the
142
- * database was created in sync mode and (b) recover the `userId` for
143
- * authentication / logging without having to thread it through
144
- * separately.
164
+ * The concurrency strategy the database was created with. Sync services
165
+ * read `concurrency.userId` to recover the peer identifier and check
166
+ * `concurrency.deferredCommit` to confirm the database is in the
167
+ * appropriate mode for multi-peer operation.
145
168
  */
146
- readonly sync: DatabaseSyncOptions | undefined;
169
+ readonly concurrency: ConcurrencyStrategy;
147
170
  readonly system: {
148
171
  /** System create() return value, or null when create() returns void. Key is always present. */
149
172
  readonly functions: {
@@ -152,9 +175,31 @@ export interface Database<C extends Components = {}, R extends ResourceComponent
152
175
  /** Tier order for execution. Looser type allows extended dbs to be assignable to base. */
153
176
  readonly order: ReadonlyArray<ReadonlyArray<string>>;
154
177
  };
178
+ /**
179
+ * Serialize the database to a plain data snapshot.
180
+ *
181
+ * For a concurrency strategy that replays transients after serialization
182
+ * (`onAfterToData` — i.e. `createRebaseReplayConcurrency` /
183
+ * `createRollForwardConcurrency` / the legacy `createReconcilingDatabase`),
184
+ * this returns a snapshot **detached** from the live store: it rolls the
185
+ * transients back, serializes a copy of the committed state (`store.toData`
186
+ * with `copy: true` — columns and the entity table are cloned), then replays.
187
+ * So a database persisted with optimistic edits in flight contains only
188
+ * committed state, and the snapshot survives the subsequent replay.
189
+ *
190
+ * For strategies with no replay hook (the default `createImmediateConcurrency`),
191
+ * the faster live-reference snapshot is returned — it shares the store's
192
+ * buffers and is only valid until the next mutation, so callers must serialize
193
+ * it before mutating the database again.
194
+ *
195
+ * Historical note: the detach above fixes a bug where the live-reference
196
+ * snapshot was corrupted by the post-serialization replay, silently leaking
197
+ * in-flight transients into persisted state. The old reconciler tests missed
198
+ * it because they only asserted the snapshot was truthy, never round-tripped it.
199
+ */
155
200
  toData(): unknown;
156
201
  fromData(data: unknown): void;
157
- extend<P extends Database.Plugin>(plugin: P): Database<C & FromSchemas<RemoveIndex<P['components']>>, R & FromSchemas<RemoveIndex<P['resources']>>, A & RemoveIndex<P['archetypes']>, F & ToTransactionFunctions<RemoveIndex<P['transactions']>>, S | StringKeyof<P['systems']>, AF & ToActionFunctions<RemoveIndex<P['actions']>>, SV & FromServiceFactories<RemoveIndex<P['services']>>, CV & FromComputedFactories<RemoveIndex<P['computed']>>>;
202
+ extend<P extends Database.Plugin>(plugin: P): Database<C & FromSchemas<RemoveIndex<P['components']>>, R & FromSchemas<RemoveIndex<P['resources']>>, A & RemoveIndex<P['archetypes']>, F & ToTransactionFunctions<RemoveIndex<P['transactions']>>, S | StringKeyof<P['systems']>, AF & ToActionFunctions<RemoveIndex<P['actions']>>, SV & FromServiceFactories<RemoveIndex<P['services']>>, CV & FromComputedFactories<RemoveIndex<P['computed']>>, IX & RemoveIndex<P['indexes']>>;
158
203
  }
159
204
  export declare namespace Database {
160
205
  /**
@@ -163,11 +208,15 @@ export declare namespace Database {
163
208
  * (P extends Plugin<infer CS, ...> ? CS : never) to avoid expensive 8-way type
164
209
  * expansion that amplifies TS7056 serialization overflow in deep extends chains.
165
210
  */
166
- type FromPlugin<P extends Database.Plugin> = Database<FromSchemas<RemoveIndex<P['components']>>, FromSchemas<RemoveIndex<P['resources']>>, RemoveIndex<P['archetypes']>, ToTransactionFunctions<RemoveIndex<P['transactions']>>, StringKeyof<P['systems']>, ToActionFunctions<RemoveIndex<P['actions']>>, FromServiceFactories<RemoveIndex<P['services']>>, FromComputedFactories<RemoveIndex<P['computed']>>>;
211
+ type FromPlugin<P extends Database.Plugin> = Database<FromSchemas<RemoveIndex<P['components']>>, FromSchemas<RemoveIndex<P['resources']>>, RemoveIndex<P['archetypes']>, ToTransactionFunctions<RemoveIndex<P['transactions']>>, StringKeyof<P['systems']>, ToActionFunctions<RemoveIndex<P['actions']>>, FromServiceFactories<RemoveIndex<P['services']>>, FromComputedFactories<RemoveIndex<P['computed']>>, RemoveIndex<P['indexes']>>;
167
212
  const create: typeof createDatabase;
168
213
  const is: (value: unknown) => value is Database;
169
214
  const observeSelectDeep: <C extends Components, Include extends StringKeyof<C>>(db: Database<C, any, any, any, any, any, any, any>, include: readonly Include[] | ReadonlySet<Include | "id">, options?: EntitySelectOptions<C, Pick<C & RequiredComponents, Include>>) => Observe<readonly (RequiredComponents & { readonly [K in Include]: C[K]; })[]>;
170
- type Plugin<CS extends ComponentSchemas = any, RS extends ResourceSchemas = any, A extends ArchetypeComponents<StringKeyof<CS>> = any, TD extends TransactionDeclarations<FromSchemas<CS>, FromSchemas<RS>, any> = any, S extends string = any, AD extends ActionDeclarations<FromSchemas<CS>, FromSchemas<RS>, A, ToTransactionFunctions<TD>, S> = any, SVF extends ServiceFactories = any, CVF extends ComputedFactories = any> = {
215
+ type Index<C extends Components = any> = StoreIndex<C, any, any, any>;
216
+ namespace Index {
217
+ type Handle<C extends Components, I extends StoreIndex<C, any, any, any>> = StoreIndex.Handle<C, I>;
218
+ }
219
+ type Plugin<CS extends ComponentSchemas = any, RS extends ResourceSchemas = any, A extends ArchetypeComponents<StringKeyof<CS>> = any, TD extends TransactionDeclarations<FromSchemas<CS>, FromSchemas<RS>, any> = any, S extends string = any, AD extends ActionDeclarations<FromSchemas<CS>, FromSchemas<RS>, A, ToTransactionFunctions<TD>, S> = any, SVF extends ServiceFactories = any, CVF extends ComputedFactories = any, IX extends IndexDeclarations<FromSchemas<CS>> = any> = {
171
220
  readonly components: CS;
172
221
  readonly resources: RS;
173
222
  readonly archetypes: A;
@@ -176,6 +225,7 @@ export declare namespace Database {
176
225
  readonly actions: AD;
177
226
  readonly services: SVF;
178
227
  readonly computed: CVF;
228
+ readonly indexes: IX;
179
229
  };
180
230
  namespace Plugin {
181
231
  const create: typeof createPlugin;