@agentshouse/mdruntime 0.1.0-cb0eb0d87ff49 → 0.1.0-cb1f56e16291b

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 (231) hide show
  1. package/README.md +19 -16
  2. package/dist/adapter.d.ts +147 -70
  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 +26 -10
  11. package/dist/bootstrap.d.ts.map +1 -1
  12. package/dist/bootstrap.js +180 -99
  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 +22 -10
  23. package/dist/client.d.ts.map +1 -1
  24. package/dist/client.js +97 -11
  25. package/dist/collection.d.ts +10 -21
  26. package/dist/collection.d.ts.map +1 -1
  27. package/dist/collection.js +39 -291
  28. package/dist/compile.d.ts +16 -0
  29. package/dist/compile.d.ts.map +1 -0
  30. package/dist/compile.js +789 -0
  31. package/dist/connection.d.ts +37 -12
  32. package/dist/connection.d.ts.map +1 -1
  33. package/dist/connection.js +3429 -1114
  34. package/dist/context.d.ts +2 -0
  35. package/dist/context.d.ts.map +1 -0
  36. package/dist/{chat/context.js → context.js} +1 -4
  37. package/dist/conversation.d.ts +32 -14
  38. package/dist/conversation.d.ts.map +1 -1
  39. package/dist/conversation.js +525 -203
  40. package/dist/digest.d.ts +7 -0
  41. package/dist/digest.d.ts.map +1 -0
  42. package/dist/digest.js +113 -0
  43. package/dist/durability.d.ts +4 -1
  44. package/dist/durability.d.ts.map +1 -1
  45. package/dist/durability.js +5 -0
  46. package/dist/entry.d.ts +4 -1
  47. package/dist/entry.d.ts.map +1 -1
  48. package/dist/entry.js +19 -23
  49. package/dist/file.d.ts +2 -19
  50. package/dist/file.d.ts.map +1 -1
  51. package/dist/file.js +7 -122
  52. package/dist/host.d.ts +10 -3
  53. package/dist/host.d.ts.map +1 -1
  54. package/dist/host.js +125 -19
  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 +17 -10
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +8 -1
  61. package/dist/job.d.ts +14 -0
  62. package/dist/job.d.ts.map +1 -0
  63. package/dist/job.js +28 -0
  64. package/dist/live.d.ts +23 -0
  65. package/dist/live.d.ts.map +1 -0
  66. package/dist/live.js +127 -0
  67. package/dist/media.d.ts +8 -0
  68. package/dist/media.d.ts.map +1 -0
  69. package/dist/media.js +218 -0
  70. package/dist/memory.d.ts +16 -6
  71. package/dist/memory.d.ts.map +1 -1
  72. package/dist/memory.js +207 -96
  73. package/dist/messages.d.ts +28 -0
  74. package/dist/messages.d.ts.map +1 -0
  75. package/dist/messages.js +89 -0
  76. package/dist/model.d.ts +9 -3
  77. package/dist/model.d.ts.map +1 -1
  78. package/dist/model.js +8 -11
  79. package/dist/name.d.ts +4 -0
  80. package/dist/name.d.ts.map +1 -0
  81. package/dist/name.js +122 -0
  82. package/dist/observation.d.ts +17 -2
  83. package/dist/observation.d.ts.map +1 -1
  84. package/dist/observation.js +100 -5
  85. package/dist/opened.d.ts +22 -0
  86. package/dist/opened.d.ts.map +1 -0
  87. package/dist/opened.js +107 -0
  88. package/dist/outcome.d.ts +45 -7
  89. package/dist/outcome.d.ts.map +1 -1
  90. package/dist/outcome.js +39 -0
  91. package/dist/overlay.d.ts +3 -5
  92. package/dist/overlay.d.ts.map +1 -1
  93. package/dist/overlay.js +95 -156
  94. package/dist/paths.d.ts +1 -0
  95. package/dist/paths.d.ts.map +1 -1
  96. package/dist/paths.js +4 -0
  97. package/dist/phrase.d.ts +3 -0
  98. package/dist/phrase.d.ts.map +1 -0
  99. package/dist/phrase.js +8 -0
  100. package/dist/query.d.ts +43 -2
  101. package/dist/query.d.ts.map +1 -1
  102. package/dist/query.js +67 -7
  103. package/dist/reach.d.ts +19 -6
  104. package/dist/reach.d.ts.map +1 -1
  105. package/dist/reach.js +226 -79
  106. package/dist/react.d.ts +6 -3
  107. package/dist/react.d.ts.map +1 -1
  108. package/dist/react.js +7 -17
  109. package/dist/readiness.d.ts +50 -0
  110. package/dist/readiness.d.ts.map +1 -0
  111. package/dist/readiness.js +27 -0
  112. package/dist/recovery.d.ts +3 -2
  113. package/dist/recovery.d.ts.map +1 -1
  114. package/dist/recovery.js +34 -7
  115. package/dist/refresh.d.ts +17 -14
  116. package/dist/refresh.d.ts.map +1 -1
  117. package/dist/refresh.js +155 -52
  118. package/dist/replica.d.ts +55 -33
  119. package/dist/replica.d.ts.map +1 -1
  120. package/dist/replica.js +300 -182
  121. package/dist/room-draft.d.ts +36 -5
  122. package/dist/room-draft.d.ts.map +1 -1
  123. package/dist/room-draft.js +161 -74
  124. package/dist/rows.d.ts +39 -29
  125. package/dist/rows.d.ts.map +1 -1
  126. package/dist/rows.js +178 -94
  127. package/dist/save.d.ts +53 -14
  128. package/dist/save.d.ts.map +1 -1
  129. package/dist/save.js +529 -185
  130. package/dist/search.d.ts +15 -77
  131. package/dist/search.d.ts.map +1 -1
  132. package/dist/search.js +10 -186
  133. package/dist/seed.d.ts +16 -0
  134. package/dist/seed.d.ts.map +1 -0
  135. package/dist/seed.js +75 -0
  136. package/dist/shared.d.ts +7 -3
  137. package/dist/shared.d.ts.map +1 -1
  138. package/dist/shared.js +119 -66
  139. package/dist/status.d.ts +5 -0
  140. package/dist/status.d.ts.map +1 -1
  141. package/dist/status.js +3 -1
  142. package/dist/store.d.ts +104 -94
  143. package/dist/store.d.ts.map +1 -1
  144. package/dist/store.js +337 -637
  145. package/dist/stored.d.ts +162 -0
  146. package/dist/stored.d.ts.map +1 -0
  147. package/dist/stored.js +549 -0
  148. package/dist/tables.d.ts +353 -0
  149. package/dist/tables.d.ts.map +1 -0
  150. package/dist/tables.js +585 -0
  151. package/dist/transfer.d.ts +0 -5
  152. package/dist/transfer.d.ts.map +1 -1
  153. package/dist/turn.d.ts +5 -3
  154. package/dist/turn.d.ts.map +1 -1
  155. package/dist/turn.js +51 -21
  156. package/dist/validation.d.ts +29 -0
  157. package/dist/validation.d.ts.map +1 -0
  158. package/dist/validation.js +101 -0
  159. package/dist/windows.d.ts +22 -0
  160. package/dist/windows.d.ts.map +1 -0
  161. package/dist/windows.js +89 -0
  162. package/dist/wire.d.ts +165 -32
  163. package/dist/wire.d.ts.map +1 -1
  164. package/dist/wire.js +56 -31
  165. package/package.json +18 -19
  166. package/AGENTS.md +0 -309
  167. package/dist/chat/acts.d.ts +0 -33
  168. package/dist/chat/acts.d.ts.map +0 -1
  169. package/dist/chat/acts.js +0 -36
  170. package/dist/chat/context.d.ts +0 -3
  171. package/dist/chat/context.d.ts.map +0 -1
  172. package/dist/chat/input.d.ts +0 -9
  173. package/dist/chat/input.d.ts.map +0 -1
  174. package/dist/chat/input.js +0 -99
  175. package/dist/chat/kit.d.ts +0 -60
  176. package/dist/chat/kit.d.ts.map +0 -1
  177. package/dist/chat/kit.js +0 -123
  178. package/dist/chat/lasting.d.ts +0 -6
  179. package/dist/chat/lasting.d.ts.map +0 -1
  180. package/dist/chat/lasting.js +0 -19
  181. package/dist/chat/list.d.ts +0 -26
  182. package/dist/chat/list.d.ts.map +0 -1
  183. package/dist/chat/list.js +0 -62
  184. package/dist/chat/markdown.d.ts +0 -20
  185. package/dist/chat/markdown.d.ts.map +0 -1
  186. package/dist/chat/markdown.js +0 -188
  187. package/dist/chat/message.d.ts +0 -6
  188. package/dist/chat/message.d.ts.map +0 -1
  189. package/dist/chat/message.js +0 -192
  190. package/dist/chat/messages.d.ts +0 -21
  191. package/dist/chat/messages.d.ts.map +0 -1
  192. package/dist/chat/messages.js +0 -151
  193. package/dist/chat/name.d.ts +0 -6
  194. package/dist/chat/name.d.ts.map +0 -1
  195. package/dist/chat/name.js +0 -37
  196. package/dist/chat/opened.d.ts +0 -11
  197. package/dist/chat/opened.d.ts.map +0 -1
  198. package/dist/chat/opened.js +0 -17
  199. package/dist/chat/overlay.d.ts +0 -31
  200. package/dist/chat/overlay.d.ts.map +0 -1
  201. package/dist/chat/overlay.js +0 -97
  202. package/dist/chat/parts.d.ts +0 -57
  203. package/dist/chat/parts.d.ts.map +0 -1
  204. package/dist/chat/parts.js +0 -119
  205. package/dist/chat/process.d.ts +0 -20
  206. package/dist/chat/process.d.ts.map +0 -1
  207. package/dist/chat/process.js +0 -32
  208. package/dist/chat/provider.d.ts +0 -63
  209. package/dist/chat/provider.d.ts.map +0 -1
  210. package/dist/chat/provider.js +0 -620
  211. package/dist/chat/question.d.ts +0 -9
  212. package/dist/chat/question.d.ts.map +0 -1
  213. package/dist/chat/question.js +0 -80
  214. package/dist/chat/questions.d.ts +0 -31
  215. package/dist/chat/questions.d.ts.map +0 -1
  216. package/dist/chat/questions.js +0 -111
  217. package/dist/chat/read.d.ts +0 -5
  218. package/dist/chat/read.d.ts.map +0 -1
  219. package/dist/chat/read.js +0 -13
  220. package/dist/chat/ready.d.ts +0 -33
  221. package/dist/chat/ready.d.ts.map +0 -1
  222. package/dist/chat/ready.js +0 -91
  223. package/dist/chat/style.d.ts +0 -4
  224. package/dist/chat/style.d.ts.map +0 -1
  225. package/dist/chat/style.js +0 -302
  226. package/dist/chat.d.ts +0 -14
  227. package/dist/chat.d.ts.map +0 -1
  228. package/dist/chat.js +0 -8
  229. package/dist/read-side.d.ts +0 -25
  230. package/dist/read-side.d.ts.map +0 -1
  231. 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
- }