@agentshouse/mdruntime 0.1.0-cb0eb0d87ff49 → 0.1.0-cb122f2ba154d

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 (230) hide show
  1. package/README.md +18 -15
  2. package/dist/adapter.d.ts +91 -34
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/attached-model.d.ts +5 -1
  5. package/dist/attached-model.d.ts.map +1 -1
  6. package/dist/attached-model.js +38 -4
  7. package/dist/binary.d.ts +0 -5
  8. package/dist/binary.d.ts.map +1 -1
  9. package/dist/binary.js +1 -1
  10. package/dist/bootstrap.d.ts +27 -8
  11. package/dist/bootstrap.d.ts.map +1 -1
  12. package/dist/bootstrap.js +174 -98
  13. package/dist/chain.d.ts +11 -0
  14. package/dist/chain.d.ts.map +1 -0
  15. package/dist/chain.js +64 -0
  16. package/dist/change-set.d.ts +9 -16
  17. package/dist/change-set.d.ts.map +1 -1
  18. package/dist/change-set.js +11 -88
  19. package/dist/change.d.ts +31 -1
  20. package/dist/change.d.ts.map +1 -1
  21. package/dist/change.js +10 -1
  22. package/dist/client.d.ts +18 -6
  23. package/dist/client.d.ts.map +1 -1
  24. package/dist/client.js +97 -10
  25. package/dist/collection.d.ts +11 -19
  26. package/dist/collection.d.ts.map +1 -1
  27. package/dist/collection.js +53 -289
  28. package/dist/compile.d.ts +16 -0
  29. package/dist/compile.d.ts.map +1 -0
  30. package/dist/compile.js +771 -0
  31. package/dist/connection.d.ts +38 -11
  32. package/dist/connection.d.ts.map +1 -1
  33. package/dist/connection.js +3134 -858
  34. package/dist/conversation.d.ts +22 -6
  35. package/dist/conversation.d.ts.map +1 -1
  36. package/dist/conversation.js +461 -131
  37. package/dist/digest.d.ts +7 -0
  38. package/dist/digest.d.ts.map +1 -0
  39. package/dist/digest.js +113 -0
  40. package/dist/durability.d.ts +5 -1
  41. package/dist/durability.d.ts.map +1 -1
  42. package/dist/durability.js +5 -0
  43. package/dist/entry.d.ts +4 -1
  44. package/dist/entry.d.ts.map +1 -1
  45. package/dist/entry.js +18 -23
  46. package/dist/file.d.ts +2 -19
  47. package/dist/file.d.ts.map +1 -1
  48. package/dist/file.js +7 -122
  49. package/dist/fulltext.d.ts +27 -0
  50. package/dist/fulltext.d.ts.map +1 -0
  51. package/dist/fulltext.js +370 -0
  52. package/dist/host.d.ts +12 -2
  53. package/dist/host.d.ts.map +1 -1
  54. package/dist/host.js +121 -13
  55. package/dist/identity.d.ts +0 -1
  56. package/dist/identity.d.ts.map +1 -1
  57. package/dist/identity.js +0 -3
  58. package/dist/index.d.ts +13 -9
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +5 -1
  61. package/dist/live.d.ts +22 -0
  62. package/dist/live.d.ts.map +1 -0
  63. package/dist/live.js +124 -0
  64. package/dist/media.d.ts +8 -0
  65. package/dist/media.d.ts.map +1 -0
  66. package/dist/media.js +208 -0
  67. package/dist/memory.d.ts +10 -4
  68. package/dist/memory.d.ts.map +1 -1
  69. package/dist/memory.js +88 -27
  70. package/dist/messages.d.ts +28 -0
  71. package/dist/messages.d.ts.map +1 -0
  72. package/dist/messages.js +90 -0
  73. package/dist/model.d.ts +9 -2
  74. package/dist/model.d.ts.map +1 -1
  75. package/dist/model.js +8 -2
  76. package/dist/name.d.ts +4 -0
  77. package/dist/name.d.ts.map +1 -0
  78. package/dist/name.js +122 -0
  79. package/dist/observation.d.ts +15 -0
  80. package/dist/observation.d.ts.map +1 -1
  81. package/dist/observation.js +93 -3
  82. package/dist/opened.d.ts +22 -0
  83. package/dist/opened.d.ts.map +1 -0
  84. package/dist/opened.js +107 -0
  85. package/dist/outcome.d.ts +45 -4
  86. package/dist/outcome.d.ts.map +1 -1
  87. package/dist/outcome.js +39 -0
  88. package/dist/overlay.d.ts +3 -5
  89. package/dist/overlay.d.ts.map +1 -1
  90. package/dist/overlay.js +95 -156
  91. package/dist/paths.d.ts +1 -0
  92. package/dist/paths.d.ts.map +1 -1
  93. package/dist/paths.js +4 -0
  94. package/dist/query.d.ts +39 -2
  95. package/dist/query.d.ts.map +1 -1
  96. package/dist/query.js +48 -7
  97. package/dist/reach.d.ts +18 -6
  98. package/dist/reach.d.ts.map +1 -1
  99. package/dist/reach.js +224 -70
  100. package/dist/react.d.ts +5 -3
  101. package/dist/react.d.ts.map +1 -1
  102. package/dist/react.js +7 -17
  103. package/dist/readiness.d.ts +63 -0
  104. package/dist/readiness.d.ts.map +1 -0
  105. package/dist/readiness.js +33 -0
  106. package/dist/reads.d.ts +11 -0
  107. package/dist/reads.d.ts.map +1 -0
  108. package/dist/reads.js +91 -0
  109. package/dist/recovery.d.ts +2 -2
  110. package/dist/recovery.d.ts.map +1 -1
  111. package/dist/recovery.js +8 -7
  112. package/dist/refresh.d.ts +16 -15
  113. package/dist/refresh.d.ts.map +1 -1
  114. package/dist/refresh.js +113 -50
  115. package/dist/replica.d.ts +56 -33
  116. package/dist/replica.d.ts.map +1 -1
  117. package/dist/replica.js +298 -179
  118. package/dist/room-draft.d.ts +34 -4
  119. package/dist/room-draft.d.ts.map +1 -1
  120. package/dist/room-draft.js +105 -31
  121. package/dist/rows.d.ts +38 -29
  122. package/dist/rows.d.ts.map +1 -1
  123. package/dist/rows.js +173 -94
  124. package/dist/save.d.ts +53 -14
  125. package/dist/save.d.ts.map +1 -1
  126. package/dist/save.js +529 -185
  127. package/dist/search.d.ts +32 -43
  128. package/dist/search.d.ts.map +1 -1
  129. package/dist/search.js +37 -170
  130. package/dist/seed.d.ts +16 -0
  131. package/dist/seed.d.ts.map +1 -0
  132. package/dist/seed.js +75 -0
  133. package/dist/shared.d.ts +8 -3
  134. package/dist/shared.d.ts.map +1 -1
  135. package/dist/shared.js +129 -66
  136. package/dist/status.d.ts +9 -0
  137. package/dist/status.d.ts.map +1 -1
  138. package/dist/status.js +3 -1
  139. package/dist/store.d.ts +100 -86
  140. package/dist/store.d.ts.map +1 -1
  141. package/dist/store.js +331 -632
  142. package/dist/stored.d.ts +135 -0
  143. package/dist/stored.d.ts.map +1 -0
  144. package/dist/stored.js +568 -0
  145. package/dist/tables.d.ts +352 -0
  146. package/dist/tables.d.ts.map +1 -0
  147. package/dist/tables.js +621 -0
  148. package/dist/turn.d.ts +5 -3
  149. package/dist/turn.d.ts.map +1 -1
  150. package/dist/turn.js +51 -21
  151. package/dist/validation.d.ts +30 -0
  152. package/dist/validation.d.ts.map +1 -0
  153. package/dist/validation.js +162 -0
  154. package/dist/windows.d.ts +22 -0
  155. package/dist/windows.d.ts.map +1 -0
  156. package/dist/windows.js +89 -0
  157. package/dist/wire.d.ts +168 -32
  158. package/dist/wire.d.ts.map +1 -1
  159. package/dist/wire.js +56 -31
  160. package/dist/words.d.ts +19 -0
  161. package/dist/words.d.ts.map +1 -0
  162. package/dist/words.js +156 -0
  163. package/package.json +18 -19
  164. package/AGENTS.md +0 -309
  165. package/dist/chat/acts.d.ts +0 -33
  166. package/dist/chat/acts.d.ts.map +0 -1
  167. package/dist/chat/acts.js +0 -36
  168. package/dist/chat/context.d.ts +0 -3
  169. package/dist/chat/context.d.ts.map +0 -1
  170. package/dist/chat/context.js +0 -10
  171. package/dist/chat/input.d.ts +0 -9
  172. package/dist/chat/input.d.ts.map +0 -1
  173. package/dist/chat/input.js +0 -99
  174. package/dist/chat/kit.d.ts +0 -60
  175. package/dist/chat/kit.d.ts.map +0 -1
  176. package/dist/chat/kit.js +0 -123
  177. package/dist/chat/lasting.d.ts +0 -6
  178. package/dist/chat/lasting.d.ts.map +0 -1
  179. package/dist/chat/lasting.js +0 -19
  180. package/dist/chat/list.d.ts +0 -26
  181. package/dist/chat/list.d.ts.map +0 -1
  182. package/dist/chat/list.js +0 -62
  183. package/dist/chat/markdown.d.ts +0 -20
  184. package/dist/chat/markdown.d.ts.map +0 -1
  185. package/dist/chat/markdown.js +0 -188
  186. package/dist/chat/message.d.ts +0 -6
  187. package/dist/chat/message.d.ts.map +0 -1
  188. package/dist/chat/message.js +0 -192
  189. package/dist/chat/messages.d.ts +0 -21
  190. package/dist/chat/messages.d.ts.map +0 -1
  191. package/dist/chat/messages.js +0 -151
  192. package/dist/chat/name.d.ts +0 -6
  193. package/dist/chat/name.d.ts.map +0 -1
  194. package/dist/chat/name.js +0 -37
  195. package/dist/chat/opened.d.ts +0 -11
  196. package/dist/chat/opened.d.ts.map +0 -1
  197. package/dist/chat/opened.js +0 -17
  198. package/dist/chat/overlay.d.ts +0 -31
  199. package/dist/chat/overlay.d.ts.map +0 -1
  200. package/dist/chat/overlay.js +0 -97
  201. package/dist/chat/parts.d.ts +0 -57
  202. package/dist/chat/parts.d.ts.map +0 -1
  203. package/dist/chat/parts.js +0 -119
  204. package/dist/chat/process.d.ts +0 -20
  205. package/dist/chat/process.d.ts.map +0 -1
  206. package/dist/chat/process.js +0 -32
  207. package/dist/chat/provider.d.ts +0 -63
  208. package/dist/chat/provider.d.ts.map +0 -1
  209. package/dist/chat/provider.js +0 -620
  210. package/dist/chat/question.d.ts +0 -9
  211. package/dist/chat/question.d.ts.map +0 -1
  212. package/dist/chat/question.js +0 -80
  213. package/dist/chat/questions.d.ts +0 -31
  214. package/dist/chat/questions.d.ts.map +0 -1
  215. package/dist/chat/questions.js +0 -111
  216. package/dist/chat/read.d.ts +0 -5
  217. package/dist/chat/read.d.ts.map +0 -1
  218. package/dist/chat/read.js +0 -13
  219. package/dist/chat/ready.d.ts +0 -33
  220. package/dist/chat/ready.d.ts.map +0 -1
  221. package/dist/chat/ready.js +0 -91
  222. package/dist/chat/style.d.ts +0 -4
  223. package/dist/chat/style.d.ts.map +0 -1
  224. package/dist/chat/style.js +0 -302
  225. package/dist/chat.d.ts +0 -14
  226. package/dist/chat.d.ts.map +0 -1
  227. package/dist/chat.js +0 -8
  228. package/dist/read-side.d.ts +0 -25
  229. package/dist/read-side.d.ts.map +0 -1
  230. package/dist/read-side.js +0 -639
package/dist/read-side.js DELETED
@@ -1,639 +0,0 @@
1
- import { and, BasicIndex, configureIndexDevMode, count, createCollection, createLiveQueryCollection, deepEquals, eq, inArray, or, toArray, } from '@tanstack/db';
2
- import { ARRAY_INDEX, parse, pointerSegments } from '@agentshouse/mdmodel';
3
- import { documentKey } from './rows.js';
4
- import { after, inUnits, ROW_WEIGHT } from './turn.js';
5
- function every(expressions) {
6
- const [first, second, ...rest] = expressions;
7
- return second === undefined ? first : and(first, second, ...rest);
8
- }
9
- function same(held, value) {
10
- return Array.isArray(held) ? held.includes(value) : held === value;
11
- }
12
- function ordered(held, [operator, bound]) {
13
- if (typeof held !== typeof bound || held === null || typeof held === 'object')
14
- return false;
15
- const left = held;
16
- const right = bound;
17
- if (operator === 'gt')
18
- return left > right;
19
- if (operator === 'gte')
20
- return left >= right;
21
- if (operator === 'lt')
22
- return left < right;
23
- return left <= right;
24
- }
25
- function satisfied(test, held) {
26
- if (test.op === 'eq')
27
- return same(held, test.value);
28
- if (test.op === 'ne')
29
- return !same(held, test.value);
30
- if (test.op === 'in')
31
- return test.values.some((value) => same(held, value));
32
- if (test.op === 'nin')
33
- return !test.values.some((value) => same(held, value));
34
- if (test.op === 'range')
35
- return test.bounds.every((bound) => ordered(held, bound));
36
- if (test.op === 'all')
37
- return Array.isArray(held) && test.values.every((value) => same(held, value));
38
- return Array.isArray(held) && held.length === test.size;
39
- }
40
- function tested(test, reached) {
41
- if (test.op === 'exists')
42
- return test.exists === (reached !== undefined);
43
- if (reached === undefined)
44
- return test.op === 'ne' || test.op === 'nin';
45
- return reached.some((held) => satisfied(test, held));
46
- }
47
- function conditioned(condition, row) {
48
- if ('every' in condition)
49
- return condition.every.every((item) => conditioned(item, row));
50
- if ('some' in condition)
51
- return condition.some.some((item) => conditioned(item, row));
52
- return tested(condition.test, row.reached[condition.field]);
53
- }
54
- function narrowed(query, where, alias) {
55
- return where === null ? query : query.fn.where((row) => conditioned(where, row[alias]));
56
- }
57
- function reached(reach, room, document) {
58
- return reach === null
59
- ? []
60
- : [or(inArray(room, [...reach.rooms]), inArray(document, [...reach.documents]))];
61
- }
62
- function scoped(scope, row, rooms, reach) {
63
- return every([
64
- eq(row.kind, 'document'),
65
- ...(rooms === null ? [] : [inArray(row.room, [...rooms])]),
66
- ...reached(reach, row.room, row.key),
67
- ...(scope.types === null ? [] : [inArray(row.type, [...scope.types])]),
68
- ...(scope.pathPrefix === null ? [] : [inArray(scope.pathPrefix, row.directories)]),
69
- ]);
70
- }
71
- function keyed(key, row) {
72
- return key.of === 'field' ? row.values[key.field] : row[key.of];
73
- }
74
- function live(query) {
75
- return createLiveQueryCollection({
76
- query: query,
77
- startSync: true,
78
- });
79
- }
80
- function related(q, rows, scope, field, kept, reach) {
81
- const matched = kept === 'source' ? 'target' : 'source';
82
- const from = q.from({ r: rows });
83
- const joined = from
84
- .where(({ r }) => every([eq(r.kind, 'reference'), ...(field === null ? [] : [inArray(field, r.forms)])]))
85
- .innerJoin({ m: rows }, ({ r, m }) => eq(r[matched], m.key))
86
- .where(({ m }) => scoped(scope, m, null, reach));
87
- return narrowed(joined, scope.where, 'm')
88
- .groupBy(({ r }) => r[kept])
89
- .select(({ r }) => ({ key: r[kept] }));
90
- }
91
- function filtered(q, rows, plan) {
92
- const from = q.from({ d: rows });
93
- let query = narrowed(from.where(({ d }) => scoped(plan.root, d, plan.rooms, plan.reach)), plan.root.where, 'd');
94
- if (plan.hop !== null) {
95
- const hop = related(q, rows, plan.hop, plan.hop.field, 'source', plan.reach);
96
- query = query.innerJoin({ h: hop }, ({ d, h }) => eq(d.key, h.key));
97
- }
98
- if (plan.backlinks !== null) {
99
- const backlinks = related(q, rows, plan.backlinks, plan.backlinks.field, 'target', plan.reach);
100
- query = query.innerJoin({ k: backlinks }, ({ d, k }) => eq(d.key, k.key));
101
- }
102
- return query;
103
- }
104
- function bodied(shape) {
105
- return shape.sections !== null || shape.preamble || shape.markdown;
106
- }
107
- function documents(q, rows, plan, shape) {
108
- let query = filtered(q, rows, plan);
109
- for (const { key, options } of shape.orderBy) {
110
- query = query.orderBy(({ d }) => keyed(key, d), options);
111
- }
112
- if (shape.orderBy.length === 0 && plan.limit !== null) {
113
- query = query.orderBy(({ d }) => d.key, { stringSort: 'lexical' });
114
- }
115
- if (plan.limit !== null)
116
- query = query.limit(plan.limit);
117
- return query.select(({ d }) => ({
118
- room: d.room,
119
- path: d.path,
120
- type: d.type,
121
- binary: d.binary,
122
- ...(shape.fields === null ? {} : { fields: d.fields }),
123
- ...(bodied(shape) ? { text: d.text } : {}),
124
- ...(shape.backlinks ? { backlinks: toArray(backlinked(q, rows, d, plan.reach)) } : {}),
125
- ...(shape.change ? { change: d.change } : {}),
126
- }));
127
- }
128
- function backlinked(q, rows, document, reach) {
129
- const from = q.from({ r: rows });
130
- return from
131
- .where(({ r }) => every([eq(r.target, document.key), ...reached(reach, r.room, r.source)]))
132
- .orderBy(({ r }) => r.path, { stringSort: 'lexical' })
133
- .orderBy(({ r }) => r.field, { stringSort: 'lexical' })
134
- .select(({ r }) => ({ path: r.path, type: r.type, field: r.field }));
135
- }
136
- function groups(q, stage, shape, limit) {
137
- const keys = shape.groupBy.map((_, index) => `key${index}`);
138
- const from = q.from({ m: stage });
139
- let query = from.groupBy(({ m }) => keys.map((key) => m[key]));
140
- for (const { by, direction } of shape.orderBy) {
141
- query = query.orderBy(({ m }) => (by === 'count' ? count(m.key) : m[keys[by]]), direction);
142
- }
143
- if (limit !== null && shape.orderBy.length > 0)
144
- query = query.limit(limit);
145
- return query.select(({ m }) => ({
146
- ...Object.fromEntries(keys.map((key) => [key, m[key]])),
147
- count: count(m.key),
148
- }));
149
- }
150
- function built(rows, plan) {
151
- const shape = plan.shape;
152
- if (shape.kind === 'documents') {
153
- const collection = live((q) => documents(q, rows, plan, shape));
154
- return { live: collection, dispose: () => void collection.cleanup() };
155
- }
156
- const stage = live((q) => filtered(q, rows, plan).select(({ d }) => ({
157
- key: d.key,
158
- ...Object.fromEntries(shape.groupBy.map((key, index) => [`key${index}`, keyed(key, d)])),
159
- })));
160
- const collection = live((q) => groups(q, stage, shape, plan.limit));
161
- return {
162
- live: collection,
163
- dispose: () => {
164
- void collection.cleanup();
165
- void stage.cleanup();
166
- },
167
- };
168
- }
169
- function sectionsOf(sections, names) {
170
- if (names === 'all')
171
- return sections;
172
- return Object.fromEntries(names.flatMap((name) => (Object.hasOwn(sections, name) ? [[name, sections[name]]] : [])));
173
- }
174
- function bodyOf(row, key, bodies) {
175
- const text = row.text;
176
- if (text === null)
177
- return null;
178
- const held = bodies?.get(key);
179
- if (held !== undefined && held.text === text)
180
- return held.document;
181
- const read = parse(text, row.path);
182
- const document = read.ok ? read.document : null;
183
- bodies?.set(key, { text, document });
184
- return document;
185
- }
186
- function masked(pointers) {
187
- const root = { whole: false, members: new Map() };
188
- for (const pointer of pointers) {
189
- let mask = root;
190
- for (const token of pointerSegments(pointer)) {
191
- const next = mask.members.get(token) ?? { whole: false, members: new Map() };
192
- mask.members.set(token, next);
193
- mask = next;
194
- }
195
- mask.whole = true;
196
- }
197
- return root;
198
- }
199
- function merged(left, right) {
200
- if (left === undefined)
201
- return right;
202
- const members = new Map(left.members);
203
- for (const [token, mask] of right.members)
204
- members.set(token, merged(members.get(token), mask));
205
- return { whole: left.whole || right.whole, members };
206
- }
207
- function cut(value, mask) {
208
- if (mask.whole)
209
- return value;
210
- if (Array.isArray(value)) {
211
- const each = {
212
- whole: false,
213
- members: new Map([...mask.members].filter(([token]) => !ARRAY_INDEX.test(token))),
214
- };
215
- const kept = [];
216
- value.forEach((item, index) => {
217
- const part = cut(item, merged(mask.members.get(String(index)), each));
218
- if (part !== undefined)
219
- kept[index] = part;
220
- });
221
- return kept.length === 0 ? undefined : kept;
222
- }
223
- if (typeof value !== 'object' || value === null)
224
- return undefined;
225
- const kept = Object.entries(value).flatMap(([key, held]) => {
226
- const member = mask.members.get(key);
227
- const part = member === undefined ? undefined : cut(held, member);
228
- return part === undefined ? [] : [[key, part]];
229
- });
230
- return kept.length === 0 ? undefined : Object.fromEntries(kept);
231
- }
232
- function selected(fields, pointers) {
233
- return (cut(fields, masked(pointers)) ?? {});
234
- }
235
- function documentOf(key, row, shape, bodies) {
236
- if (row.type === null) {
237
- const binary = row.binary;
238
- return {
239
- room: row.room,
240
- path: row.path,
241
- ...(binary === null ? {} : { binaryFile: binary }),
242
- };
243
- }
244
- const body = bodied(shape) ? bodyOf(row, key, bodies) : null;
245
- return {
246
- room: row.room,
247
- path: row.path,
248
- type: row.type,
249
- ...(shape.fields === null
250
- ? {}
251
- : {
252
- fields: shape.fields === 'all'
253
- ? row.fields
254
- : selected(row.fields, shape.fields),
255
- }),
256
- ...(shape.sections === null || body === null
257
- ? {}
258
- : { sections: sectionsOf(body.sections, shape.sections) }),
259
- ...(shape.preamble && body !== null ? { preamble: body.preamble } : {}),
260
- ...(shape.markdown && body !== null ? { markdown: body.content } : {}),
261
- ...(shape.backlinks
262
- ? {
263
- backlinks: row.backlinks.map(({ path, type, field }) => ({ path, type, field })),
264
- }
265
- : {}),
266
- ...(shape.change ? { change: row.change } : {}),
267
- };
268
- }
269
- function weight(row) {
270
- return ROW_WEIGHT + (typeof row?.text === 'string' ? row.text.length : 0);
271
- }
272
- function rowsOfPlan(plan, entries, bodies, each = (row) => row) {
273
- const shape = plan.shape;
274
- if (shape.kind === 'documents') {
275
- const documents = [];
276
- return after(inUnits(entries, ([key, row]) => {
277
- documents.push(each(documentOf(key, row, shape, bodies)));
278
- return weight(row);
279
- }), () => ({ rows: { documents }, keys: entries.map(([key]) => key) }));
280
- }
281
- const bounded = shape.orderBy.length === 0 && plan.limit !== null ? entries.slice(0, plan.limit) : entries;
282
- const groups = [];
283
- return after(inUnits(bounded, ([, row]) => {
284
- groups.push(each({
285
- key: shape.groupBy.map((_, index) => row[`key${index}`]),
286
- count: row.count,
287
- }));
288
- return ROW_WEIGHT;
289
- }), () => ({ rows: { groups }, keys: bounded.map(([key]) => key) }));
290
- }
291
- export function reconciled(previous, next) {
292
- const before = previous.result;
293
- const after = next.result;
294
- if ('pending' in before || 'pending' in after) {
295
- if (deepEquals(before, after))
296
- return null;
297
- return { keyed: next, message: next };
298
- }
299
- const earlier = 'groups' in before ? before.groups : before.documents;
300
- const held = new Map(previous.keys.map((key, index) => [key, earlier[index]]));
301
- const changed = [];
302
- const rows = ('groups' in after ? after.groups : after.documents).map((row, index) => {
303
- const key = next.keys[index];
304
- const kept = held.get(key);
305
- if (kept !== undefined && deepEquals(kept, row))
306
- return kept;
307
- changed.push([key, row]);
308
- return row;
309
- });
310
- const present = new Set(next.keys);
311
- const removed = previous.keys.filter((key) => !present.has(key));
312
- const moved = reordered(previous.keys, next.keys, present);
313
- const covered = !deepEquals(before.coverage, after.coverage);
314
- if (changed.length === 0 && removed.length === 0 && !moved && !covered)
315
- return null;
316
- return {
317
- keyed: {
318
- result: 'groups' in after
319
- ? { groups: rows, coverage: after.coverage }
320
- : { documents: rows, coverage: after.coverage },
321
- keys: next.keys,
322
- },
323
- message: {
324
- changed,
325
- removed,
326
- order: moved ? next.keys : null,
327
- ...(covered ? { coverage: after.coverage } : {}),
328
- },
329
- };
330
- }
331
- function reordered(previous, next, present) {
332
- let at = 0;
333
- for (const key of previous) {
334
- if (!present.has(key))
335
- continue;
336
- if (next[at] !== key)
337
- return true;
338
- at += 1;
339
- }
340
- return at !== next.length;
341
- }
342
- export function createReadSide() {
343
- configureIndexDevMode({ enabled: false });
344
- let sync;
345
- const rows = createCollection({
346
- getKey: (row) => row.key,
347
- gcTime: 0,
348
- startSync: true,
349
- autoIndex: 'eager',
350
- defaultIndexType: BasicIndex,
351
- sync: {
352
- rowUpdateMode: 'full',
353
- sync: (params) => {
354
- sync = params;
355
- params.markReady();
356
- },
357
- },
358
- });
359
- const shared = new Map();
360
- function searched(row) {
361
- const read = row.text === null ? null : parse(row.text, row.path);
362
- if (read === null || !read.ok)
363
- return null;
364
- return {
365
- room: row.room,
366
- path: row.path,
367
- type: row.type,
368
- fields: row.fields,
369
- preamble: read.document.preamble,
370
- sections: read.document.sections,
371
- };
372
- }
373
- function kept(entry, key, row) {
374
- const held = entry.rows.get(key);
375
- if (held !== undefined && deepEquals(held, row))
376
- return;
377
- entry.rows.set(key, row);
378
- }
379
- function rebuilt(entry) {
380
- return after(rowsOfPlan(entry.plan, [...entry.built.live.entries()], entry.bodies), ({ rows: found, keys }) => {
381
- const present = new Set(keys);
382
- for (const key of [...entry.rows.keys()])
383
- if (!present.has(key))
384
- entry.rows.delete(key);
385
- for (const key of [...entry.bodies.keys()]) {
386
- if (!present.has(key))
387
- entry.bodies.delete(key);
388
- }
389
- keys.forEach((key, index) => kept(entry, key, rowAt(found, index)));
390
- return keys;
391
- });
392
- }
393
- function refreshed(entry, dirty) {
394
- const shape = entry.plan.shape;
395
- const keys = [...entry.built.live.keys()];
396
- const named = new Set([...dirty, ...keys.filter((key) => !entry.rows.has(key))]);
397
- const values = [...named].map((key) => [key, entry.built.live.get(key)]);
398
- const done = inUnits(values, ([key, value]) => {
399
- if (value !== undefined)
400
- kept(entry, key, documentOf(key, value, shape, entry.bodies));
401
- else {
402
- entry.rows.delete(key);
403
- entry.bodies.delete(key);
404
- }
405
- return weight(value);
406
- });
407
- return after(done, () => keys);
408
- }
409
- function current(entry, keys, coverage) {
410
- const found = keys.map((key) => entry.rows.get(key));
411
- return {
412
- result: entry.plan.shape.kind === 'groups'
413
- ? { groups: found, coverage }
414
- : { documents: found, coverage },
415
- keys,
416
- };
417
- }
418
- function delivered(entry, next) {
419
- const previous = entry.result;
420
- entry.result = next;
421
- const message = previous === undefined ? null : changedFrom(previous, next);
422
- if (message !== null)
423
- for (const listener of entry.ready)
424
- listener(message);
425
- for (const listener of entry.fresh) {
426
- entry.ready.add(listener);
427
- listener(next);
428
- }
429
- entry.fresh.clear();
430
- }
431
- function run(entry) {
432
- while (entry.listeners.size > 0 &&
433
- (entry.whole || entry.dirty.size > 0 || entry.stale || entry.fresh.size > 0)) {
434
- entry.stale = false;
435
- const cover = entry.cover();
436
- if ('pending' in cover) {
437
- entry.whole = true;
438
- entry.dirty.clear();
439
- entry.rows.clear();
440
- entry.bodies.clear();
441
- delivered(entry, { result: cover, keys: [] });
442
- break;
443
- }
444
- const whole = entry.whole ||
445
- entry.plan.shape.kind === 'groups' ||
446
- entry.result === undefined ||
447
- 'pending' in entry.result.result;
448
- const dirty = entry.dirty;
449
- entry.dirty = new Set();
450
- entry.whole = false;
451
- const keys = whole ? rebuilt(entry) : refreshed(entry, dirty);
452
- if (keys instanceof Promise) {
453
- void keys
454
- .then((found) => {
455
- if (entry.listeners.size > 0)
456
- delivered(entry, current(entry, found, cover.coverage));
457
- run(entry);
458
- })
459
- .catch(() => {
460
- entry.running = false;
461
- });
462
- return;
463
- }
464
- delivered(entry, current(entry, keys, cover.coverage));
465
- }
466
- entry.running = false;
467
- }
468
- function wake(entry) {
469
- if (entry.subscription === null || entry.running)
470
- return;
471
- entry.running = true;
472
- try {
473
- run(entry);
474
- }
475
- catch (error) {
476
- entry.running = false;
477
- throw error;
478
- }
479
- }
480
- function recover() {
481
- for (const entry of shared.values()) {
482
- if (entry.result === undefined || entry.subscription === null)
483
- continue;
484
- const cover = entry.cover();
485
- const before = entry.result.result;
486
- const held = 'pending' in cover
487
- ? deepEquals(before, cover)
488
- : 'coverage' in before && deepEquals(before.coverage, cover.coverage);
489
- if (held)
490
- continue;
491
- entry.stale = true;
492
- wake(entry);
493
- }
494
- }
495
- return {
496
- apply(set) {
497
- const next = new Map();
498
- for (const change of set.documents) {
499
- for (const row of change.before)
500
- next.set(row.key, null);
501
- for (const row of change.after)
502
- next.set(row.key, row);
503
- }
504
- if (next.size > 0) {
505
- sync.begin();
506
- for (const [key, row] of next) {
507
- if (row === null) {
508
- if (rows.has(key))
509
- sync.write({ type: 'delete', key });
510
- continue;
511
- }
512
- sync.write({ type: rows.has(key) ? 'update' : 'insert', value: row });
513
- }
514
- sync.commit();
515
- }
516
- recover();
517
- },
518
- recover,
519
- async query(plan, at) {
520
- const { live: collection, dispose } = built(rows, plan);
521
- try {
522
- await collection.toArrayWhenReady();
523
- const entries = [...collection.entries()];
524
- const held = at();
525
- const found = await rowsOfPlan(plan, entries, null, structuredClone);
526
- return { rows: found.rows, at: held };
527
- }
528
- finally {
529
- dispose();
530
- }
531
- },
532
- watch(plan, identity, cover, deliverTo) {
533
- let entry = shared.get(identity);
534
- if (entry === undefined) {
535
- const created = {
536
- plan,
537
- built: built(rows, plan),
538
- cover,
539
- result: undefined,
540
- rows: new Map(),
541
- bodies: new Map(),
542
- listeners: new Set(),
543
- fresh: new Set(),
544
- ready: new Set(),
545
- subscription: null,
546
- whole: true,
547
- dirty: new Set(),
548
- stale: false,
549
- running: false,
550
- };
551
- created.built.live.on('status:change', ({ status }) => {
552
- if (status === 'cleaned-up' && created.listeners.size === 0)
553
- shared.delete(identity);
554
- });
555
- shared.set(identity, created);
556
- entry = created;
557
- }
558
- const observed = entry;
559
- observed.listeners.add(deliverTo);
560
- observed.built.live.onFirstReady(() => {
561
- if (!observed.listeners.has(deliverTo))
562
- return;
563
- observed.fresh.add(deliverTo);
564
- if (observed.subscription === null) {
565
- observed.whole = true;
566
- observed.subscription = observed.built.live.subscribeChanges((changes) => {
567
- if (observed.plan.shape.kind === 'groups')
568
- observed.whole = true;
569
- else
570
- for (const { key } of changes)
571
- observed.dirty.add(key);
572
- wake(observed);
573
- }, { includeInitialState: false });
574
- }
575
- wake(observed);
576
- });
577
- return () => {
578
- observed.fresh.delete(deliverTo);
579
- observed.ready.delete(deliverTo);
580
- if (!observed.listeners.delete(deliverTo) || observed.listeners.size > 0)
581
- return;
582
- observed.subscription?.unsubscribe();
583
- observed.subscription = null;
584
- observed.result = undefined;
585
- observed.rows.clear();
586
- observed.bodies.clear();
587
- observed.dirty.clear();
588
- observed.whole = true;
589
- };
590
- },
591
- room(room) {
592
- return rows.toArray.flatMap((row) => row.kind !== 'document' || row.type === null || row.room !== room ? [] : [row.path]);
593
- },
594
- document(room, path) {
595
- const row = rows.get(documentKey(room, path));
596
- return row === undefined || row.type === null ? null : searched(row);
597
- },
598
- close() {
599
- for (const entry of shared.values()) {
600
- entry.listeners.clear();
601
- entry.fresh.clear();
602
- entry.ready.clear();
603
- entry.subscription?.unsubscribe();
604
- entry.built.dispose();
605
- }
606
- shared.clear();
607
- void rows.cleanup();
608
- },
609
- };
610
- }
611
- function changedFrom(previous, next) {
612
- const before = previous.result;
613
- const after = next.result;
614
- if ('pending' in before || 'pending' in after)
615
- return deepEquals(before, after) ? null : next;
616
- const earlier = 'groups' in before ? before.groups : before.documents;
617
- const held = new Map(previous.keys.map((key, index) => [key, earlier[index]]));
618
- const later = 'groups' in after ? after.groups : after.documents;
619
- const changed = [];
620
- next.keys.forEach((key, index) => {
621
- if (held.get(key) !== later[index])
622
- changed.push([key, later[index]]);
623
- });
624
- const present = new Set(next.keys);
625
- const removed = previous.keys.filter((key) => !present.has(key));
626
- const moved = reordered(previous.keys, next.keys, present);
627
- const covered = !deepEquals(before.coverage, after.coverage);
628
- if (changed.length === 0 && removed.length === 0 && !moved && !covered)
629
- return null;
630
- return {
631
- changed,
632
- removed,
633
- order: moved ? next.keys : null,
634
- ...(covered ? { coverage: after.coverage } : {}),
635
- };
636
- }
637
- function rowAt(rows, index) {
638
- return 'groups' in rows ? rows.groups[index] : rows.documents[index];
639
- }