@agentshouse/mdruntime 0.1.0-ca14c49c06d90 → 0.1.0-ca4dc698bd0c4

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 (91) hide show
  1. package/AGENTS.md +260 -259
  2. package/dist/acquisition.d.ts +14 -0
  3. package/dist/acquisition.d.ts.map +1 -0
  4. package/dist/acquisition.js +24 -0
  5. package/dist/adapter.d.ts +6 -1
  6. package/dist/adapter.d.ts.map +1 -1
  7. package/dist/change-set.d.ts +2 -0
  8. package/dist/change-set.d.ts.map +1 -1
  9. package/dist/change-set.js +34 -9
  10. package/dist/client.d.ts +8 -5
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +1 -0
  13. package/dist/collection.d.ts +17 -3
  14. package/dist/collection.d.ts.map +1 -1
  15. package/dist/collection.js +230 -19
  16. package/dist/connection.d.ts +20 -7
  17. package/dist/connection.d.ts.map +1 -1
  18. package/dist/connection.js +926 -175
  19. package/dist/conversation.d.ts +8 -5
  20. package/dist/conversation.d.ts.map +1 -1
  21. package/dist/conversation.js +128 -83
  22. package/dist/durability.d.ts +7 -1
  23. package/dist/durability.d.ts.map +1 -1
  24. package/dist/entry.d.ts +2 -2
  25. package/dist/entry.d.ts.map +1 -1
  26. package/dist/entry.js +3 -3
  27. package/dist/host.d.ts +11 -2
  28. package/dist/host.d.ts.map +1 -1
  29. package/dist/host.js +33 -3
  30. package/dist/identity.d.ts +2 -0
  31. package/dist/identity.d.ts.map +1 -1
  32. package/dist/identity.js +6 -0
  33. package/dist/index.d.ts +5 -4
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/memory.d.ts +2 -1
  36. package/dist/memory.d.ts.map +1 -1
  37. package/dist/memory.js +7 -2
  38. package/dist/model.d.ts +1 -0
  39. package/dist/model.d.ts.map +1 -1
  40. package/dist/model.js +9 -0
  41. package/dist/observation.d.ts +5 -2
  42. package/dist/observation.d.ts.map +1 -1
  43. package/dist/observation.js +22 -11
  44. package/dist/overlay.d.ts +1 -0
  45. package/dist/overlay.d.ts.map +1 -1
  46. package/dist/overlay.js +25 -54
  47. package/dist/query.d.ts +28 -3
  48. package/dist/query.d.ts.map +1 -1
  49. package/dist/reach.d.ts +6 -2
  50. package/dist/reach.d.ts.map +1 -1
  51. package/dist/reach.js +16 -4
  52. package/dist/react.d.ts +5 -3
  53. package/dist/react.d.ts.map +1 -1
  54. package/dist/read-side.d.ts +13 -6
  55. package/dist/read-side.d.ts.map +1 -1
  56. package/dist/read-side.js +282 -83
  57. package/dist/readiness.d.ts +53 -0
  58. package/dist/readiness.d.ts.map +1 -0
  59. package/dist/readiness.js +33 -0
  60. package/dist/recovery.d.ts +25 -0
  61. package/dist/recovery.d.ts.map +1 -0
  62. package/dist/recovery.js +197 -0
  63. package/dist/refresh.d.ts.map +1 -1
  64. package/dist/refresh.js +11 -10
  65. package/dist/replica.d.ts +1 -1
  66. package/dist/replica.d.ts.map +1 -1
  67. package/dist/replica.js +47 -19
  68. package/dist/rows.d.ts +4 -13
  69. package/dist/rows.d.ts.map +1 -1
  70. package/dist/rows.js +2 -12
  71. package/dist/save.d.ts +5 -0
  72. package/dist/save.d.ts.map +1 -1
  73. package/dist/save.js +36 -13
  74. package/dist/search.d.ts +28 -6
  75. package/dist/search.d.ts.map +1 -1
  76. package/dist/search.js +108 -45
  77. package/dist/shared.d.ts +11 -0
  78. package/dist/shared.d.ts.map +1 -0
  79. package/dist/shared.js +368 -0
  80. package/dist/status.d.ts +4 -0
  81. package/dist/status.d.ts.map +1 -1
  82. package/dist/store.d.ts +18 -3
  83. package/dist/store.d.ts.map +1 -1
  84. package/dist/store.js +147 -49
  85. package/dist/turn.d.ts +7 -0
  86. package/dist/turn.d.ts.map +1 -0
  87. package/dist/turn.js +45 -0
  88. package/dist/wire.d.ts +2 -0
  89. package/dist/wire.d.ts.map +1 -1
  90. package/dist/wire.js +2 -0
  91. package/package.json +2 -2
package/dist/reach.js CHANGED
@@ -122,7 +122,7 @@ function savedWithin(reach, room, result) {
122
122
  function statusWithin(reach, status) {
123
123
  return {
124
124
  ...status,
125
- attentionRequired: status.attentionRequired.filter((entry) => covers(reach, entry.room, entry.path)),
125
+ attentionRequired: status.attentionRequired.filter((entry) => 'refusal' in entry ? wholly(reach, entry.room) : covers(reach, entry.room, entry.path)),
126
126
  };
127
127
  }
128
128
  function queueWithin(reach, room, entries) {
@@ -132,9 +132,10 @@ function queueWithin(reach, room, entries) {
132
132
  function unreached(room) {
133
133
  return runtimeError('room-not-held', `No Local Replica for ${room}`);
134
134
  }
135
- export function narrowed(runtime, given) {
135
+ export function narrowed(runtime, given, told) {
136
136
  const { md, watch } = runtime;
137
137
  let reach = given;
138
+ let port = told;
138
139
  const open = new Set();
139
140
  function following(begin) {
140
141
  let stop = begin();
@@ -152,6 +153,9 @@ export function narrowed(runtime, given) {
152
153
  if (topic === 'rooms') {
153
154
  return following(() => watch(topic, input, (rooms) => deliver(roomsWithin(reach, rooms))));
154
155
  }
156
+ if (topic === 'readiness') {
157
+ return following(() => runtime.watchReadiness(port, reach, deliver));
158
+ }
155
159
  if (topic === 'sync-status') {
156
160
  return following(() => watch(topic, input, (status) => deliver(statusWithin(reach, status))));
157
161
  }
@@ -189,7 +193,7 @@ export function narrowed(runtime, given) {
189
193
  if (next === null)
190
194
  return;
191
195
  held = next.keyed;
192
- deliver(next.change);
196
+ deliver(next.message);
193
197
  });
194
198
  });
195
199
  }
@@ -217,7 +221,10 @@ export function narrowed(runtime, given) {
217
221
  ...md,
218
222
  rooms: () => roomsWithin(reach, md.rooms()),
219
223
  query: ((input) => runtime.query(runtime.plan(input, reach))),
220
- search: (input) => runtime.search(input, reach),
224
+ search(input) {
225
+ runtime.searching(port.target);
226
+ return runtime.search(input, reach);
227
+ },
221
228
  types(room) {
222
229
  if (wholly(reach, room))
223
230
  return md.types(room);
@@ -290,5 +297,10 @@ export function narrowed(runtime, given) {
290
297
  for (const restart of [...open])
291
298
  restart();
292
299
  },
300
+ facts(next) {
301
+ port = next;
302
+ for (const restart of [...open])
303
+ restart();
304
+ },
293
305
  };
294
306
  }
package/dist/react.d.ts CHANGED
@@ -4,7 +4,8 @@ import type { Member, ServiceMode } from './adapter.js';
4
4
  import type { ConversationAgent, ConversationEntry, ConversationOptions, ConversationView } from './conversation.js';
5
5
  import { type RuntimeError } from './failure.js';
6
6
  import type { QueueEntry } from './outcome.js';
7
- import type { DocumentQuery, DocumentResult, GroupQuery, GroupResult } from './query.js';
7
+ import type { DocumentQuery, DocumentResult, GroupQuery, GroupResult, PendingResult } from './query.js';
8
+ import type { Readiness } from './readiness.js';
8
9
  import type { RoomDraft, RoomDraftParts } from './room-draft.js';
9
10
  import type { SyncStatus } from './status.js';
10
11
  type Client = MdRuntimeClient | null;
@@ -16,13 +17,14 @@ export type Observed<T> = {
16
17
  };
17
18
  export declare function useObserve(client: Client, topic: 'deployment-facts'): Observed<unknown>;
18
19
  export declare function useObserve(client: Client, topic: 'rooms'): Observed<readonly AppRoom[]>;
20
+ export declare function useObserve(client: Client, topic: 'readiness'): Observed<Readiness>;
19
21
  export declare function useObserve(client: Client, topic: 'connection-refusal'): Observed<ConnectionRefusal | null>;
20
22
  export declare function useObserve(client: Client, topic: 'storage-loss'): Observed<string | null>;
21
23
  export declare function useObserve(client: Client, topic: 'sync-status'): Observed<SyncStatus>;
22
24
  export declare function useObserve(client: Client, topic: 'service-mode'): Observed<ServiceMode>;
23
25
  export declare function useObserve(client: Client, topic: 'member'): Observed<Member | null>;
24
- export declare function useObserve(client: Client, topic: 'query', query: DocumentQuery): Observed<DocumentResult>;
25
- export declare function useObserve(client: Client, topic: 'query', query: GroupQuery): Observed<GroupResult>;
26
+ export declare function useObserve(client: Client, topic: 'query', query: DocumentQuery): Observed<DocumentResult | PendingResult>;
27
+ export declare function useObserve(client: Client, topic: 'query', query: GroupQuery): Observed<GroupResult | PendingResult>;
26
28
  export declare function useObserve(client: Client, topic: 'queue', locator: string): Observed<readonly QueueEntry[]>;
27
29
  export declare function useObserve(client: Client, topic: 'room-drafts'): Observed<readonly RoomDraft[]>;
28
30
  export declare function useObserve(client: Client, topic: 'presentation'): Observed<unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"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"}
@@ -1,18 +1,25 @@
1
1
  import type { ChangeSet } from './change-set.js';
2
- import { type KeyedResult, type QueryChange } from './observation.js';
3
- import type { Plan, QueryResult } from './query.js';
2
+ import { type KeyedResult, type QueryMessage } from './observation.js';
3
+ import type { PendingResult, Plan, QueryCoverage, QueryRows } from './query.js';
4
4
  import type { SearchedDocument } from './search.js';
5
+ export type Cover = {
6
+ coverage: QueryCoverage;
7
+ } | PendingResult;
5
8
  export type ReadSide = {
6
9
  apply(set: ChangeSet): void;
7
- query(plan: Plan): Promise<QueryResult>;
8
- watch(plan: Plan, identity: string, deliver: (message: KeyedResult | QueryChange) => void): () => void;
9
- documents(): readonly SearchedDocument[];
10
+ recover(): void;
11
+ query<T>(plan: Plan, at: () => T): Promise<{
12
+ rows: QueryRows;
13
+ at: T;
14
+ }>;
15
+ watch(plan: Plan, identity: string, cover: () => Cover, deliver: (message: QueryMessage) => void): () => void;
16
+ room(room: string): readonly string[];
10
17
  document(room: string, path: string): SearchedDocument | null;
11
18
  close(): void;
12
19
  };
13
20
  export declare function reconciled(previous: KeyedResult, next: KeyedResult): {
14
21
  keyed: KeyedResult;
15
- change: QueryChange;
22
+ message: QueryMessage;
16
23
  } | null;
17
24
  export declare function createReadSide(): ReadSide;
18
25
  //# sourceMappingURL=read-side.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"read-side.d.ts","sourceRoot":"","sources":["../src/read-side.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAU,KAAK,WAAW,EAAE,KAAK,WAAW,EAAe,MAAM,kBAAkB,CAAC;AAC3F,OAAO,KAAK,EAOV,IAAI,EAIJ,WAAW,EAIZ,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAuDpD,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACxC,KAAK,CACH,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW,KAAK,IAAI,GACpD,MAAM,IAAI,CAAC;IACd,SAAS,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAC9D,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAuVF,wBAAgB,UAAU,CACxB,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,WAAW,GAChB;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAAG,IAAI,CA4BpD;AAED,wBAAgB,cAAc,IAAI,QAAQ,CA4HzC"}
1
+ {"version":3,"file":"read-side.d.ts","sourceRoot":"","sources":["../src/read-side.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAe,MAAM,kBAAkB,CAAC;AACpF,OAAO,KAAK,EAOV,aAAa,EACb,IAAI,EAEJ,aAAa,EAGb,SAAS,EAIV,MAAM,YAAY,CAAC;AAGpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA4CpD,MAAM,MAAM,KAAK,GAAG;IAAE,QAAQ,EAAE,aAAa,CAAA;CAAE,GAAG,aAAa,CAAC;AAuBhE,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,OAAO,IAAI,IAAI,CAAC;IAChB,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,EAAE,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IACvE,KAAK,CACH,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,KAAK,EAClB,OAAO,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,GACvC,MAAM,IAAI,CAAC;IACd,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAC9D,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAqWF,wBAAgB,UAAU,CACxB,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,WAAW,GAChB;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,GAAG,IAAI,CAuCtD;AAgBD,wBAAgB,cAAc,IAAI,QAAQ,CA+QzC"}
package/dist/read-side.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { and, BasicIndex, configureIndexDevMode, count, createCollection, createLiveQueryCollection, deepEquals, eq, inArray, or, toArray, } from '@tanstack/db';
2
- import { ARRAY_INDEX, pointerSegments } from '@agentshouse/mdmodel';
3
- import { rowsOf } from './observation.js';
2
+ import { ARRAY_INDEX, parse, pointerSegments } from '@agentshouse/mdmodel';
4
3
  import { documentKey } from './rows.js';
4
+ import { after, inUnits, ROW_WEIGHT } from './turn.js';
5
5
  function every(expressions) {
6
6
  const [first, second, ...rest] = expressions;
7
7
  return second === undefined ? first : and(first, second, ...rest);
@@ -101,14 +101,11 @@ function filtered(q, rows, plan) {
101
101
  }
102
102
  return query;
103
103
  }
104
- function named(prefix, names, source) {
105
- return Object.fromEntries(names.map((name, index) => [`${prefix}${index}`, source[name]]));
104
+ function bodied(shape) {
105
+ return shape.sections !== null || shape.preamble || shape.markdown;
106
106
  }
107
107
  function documents(q, rows, plan, shape) {
108
108
  let query = filtered(q, rows, plan);
109
- if (shape.sections !== null || shape.preamble || shape.markdown) {
110
- query = query.leftJoin({ b: rows }, ({ d, b }) => eq(d.body, b.key));
111
- }
112
109
  for (const { key, options } of shape.orderBy) {
113
110
  query = query.orderBy(({ d }) => keyed(key, d), options);
114
111
  }
@@ -117,16 +114,13 @@ function documents(q, rows, plan, shape) {
117
114
  }
118
115
  if (plan.limit !== null)
119
116
  query = query.limit(plan.limit);
120
- return query.select(({ d, b }) => ({
117
+ return query.select(({ d }) => ({
121
118
  room: d.room,
122
119
  path: d.path,
123
120
  type: d.type,
124
121
  binary: d.binary,
125
122
  ...(shape.fields === null ? {} : { fields: d.fields }),
126
- ...(shape.sections === 'all' ? { sections: b.sections } : {}),
127
- ...(Array.isArray(shape.sections) ? named('section', shape.sections, b.sections) : {}),
128
- ...(shape.preamble ? { preamble: b.preamble } : {}),
129
- ...(shape.markdown ? { markdown: b.markdown } : {}),
123
+ ...(bodied(shape) ? { text: d.text } : {}),
130
124
  ...(shape.backlinks ? { backlinks: toArray(backlinked(q, rows, d, plan.reach)) } : {}),
131
125
  ...(shape.change ? { change: d.change } : {}),
132
126
  }));
@@ -172,13 +166,22 @@ function built(rows, plan) {
172
166
  },
173
167
  };
174
168
  }
175
- function present(entries) {
176
- return Object.fromEntries(entries.filter(([, value]) => value !== undefined));
177
- }
178
- function part(row, prefix, names, whole) {
169
+ function sectionsOf(sections, names) {
179
170
  if (names === 'all')
180
- return whole;
181
- return present(names.map((name, index) => [name, row[`${prefix}${index}`]]));
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;
182
185
  }
183
186
  function masked(pointers) {
184
187
  const root = { whole: false, members: new Map() };
@@ -229,7 +232,7 @@ function cut(value, mask) {
229
232
  function selected(fields, pointers) {
230
233
  return (cut(fields, masked(pointers)) ?? {});
231
234
  }
232
- function documentOf(row, shape) {
235
+ function documentOf(key, row, shape, bodies) {
233
236
  if (row.type === null) {
234
237
  const binary = row.binary;
235
238
  return {
@@ -238,6 +241,7 @@ function documentOf(row, shape) {
238
241
  ...(binary === null ? {} : { binaryFile: binary }),
239
242
  };
240
243
  }
244
+ const body = bodied(shape) ? bodyOf(row, key, bodies) : null;
241
245
  return {
242
246
  room: row.room,
243
247
  path: row.path,
@@ -249,13 +253,11 @@ function documentOf(row, shape) {
249
253
  ? row.fields
250
254
  : selected(row.fields, shape.fields),
251
255
  }),
252
- ...(shape.sections === null
256
+ ...(shape.sections === null || body === null
253
257
  ? {}
254
- : {
255
- sections: part(row, 'section', shape.sections, row.sections),
256
- }),
257
- ...(shape.preamble ? { preamble: row.preamble } : {}),
258
- ...(shape.markdown ? { markdown: row.markdown } : {}),
258
+ : { sections: sectionsOf(body.sections, shape.sections) }),
259
+ ...(shape.preamble && body !== null ? { preamble: body.preamble } : {}),
260
+ ...(shape.markdown && body !== null ? { markdown: body.content } : {}),
259
261
  ...(shape.backlinks
260
262
  ? {
261
263
  backlinks: row.backlinks.map(({ path, type, field }) => ({ path, type, field })),
@@ -264,30 +266,40 @@ function documentOf(row, shape) {
264
266
  ...(shape.change ? { change: row.change } : {}),
265
267
  };
266
268
  }
267
- function keyedOf(plan, entries) {
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) {
268
273
  const shape = plan.shape;
269
274
  if (shape.kind === 'documents') {
270
- return {
271
- result: structuredClone({ documents: entries.map(([, row]) => documentOf(row, shape)) }),
272
- keys: entries.map(([key]) => key),
273
- };
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) }));
274
280
  }
275
281
  const bounded = shape.orderBy.length === 0 && plan.limit !== null ? entries.slice(0, plan.limit) : entries;
276
- return {
277
- result: structuredClone({
278
- groups: bounded.map(([, row]) => ({
279
- key: shape.groupBy.map((_, index) => row[`key${index}`]),
280
- count: row.count,
281
- })),
282
- }),
283
- keys: bounded.map(([key]) => key),
284
- };
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) }));
285
290
  }
286
291
  export function reconciled(previous, next) {
287
- const before = rowsOf(previous.result);
288
- const held = new Map(previous.keys.map((key, index) => [key, before[index]]));
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]]));
289
301
  const changed = [];
290
- const rows = rowsOf(next.result).map((row, index) => {
302
+ const rows = ('groups' in after ? after.groups : after.documents).map((row, index) => {
291
303
  const key = next.keys[index];
292
304
  const kept = held.get(key);
293
305
  if (kept !== undefined && deepEquals(kept, row))
@@ -296,22 +308,37 @@ export function reconciled(previous, next) {
296
308
  return row;
297
309
  });
298
310
  const present = new Set(next.keys);
299
- const survivors = previous.keys.filter((key) => present.has(key));
300
311
  const removed = previous.keys.filter((key) => !present.has(key));
301
- const moved = survivors.length !== next.keys.length ||
302
- survivors.some((key, index) => key !== next.keys[index]);
303
- if (changed.length === 0 && removed.length === 0 && !moved)
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)
304
315
  return null;
305
316
  return {
306
317
  keyed: {
307
- result: 'groups' in next.result
308
- ? { groups: rows }
309
- : { documents: rows },
318
+ result: 'groups' in after
319
+ ? { groups: rows, coverage: after.coverage }
320
+ : { documents: rows, coverage: after.coverage },
310
321
  keys: next.keys,
311
322
  },
312
- change: { changed, removed, order: moved ? next.keys : null },
323
+ message: {
324
+ changed,
325
+ removed,
326
+ order: moved ? next.keys : null,
327
+ ...(covered ? { coverage: after.coverage } : {}),
328
+ },
313
329
  };
314
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
+ }
315
342
  export function createReadSide() {
316
343
  configureIndexDevMode({ enabled: false });
317
344
  let sync;
@@ -331,23 +358,139 @@ export function createReadSide() {
331
358
  });
332
359
  const shared = new Map();
333
360
  function searched(row) {
334
- const body = rows.get(row.body);
361
+ const read = row.text === null ? null : parse(row.text, row.path);
362
+ if (read === null || !read.ok)
363
+ return null;
335
364
  return {
336
365
  room: row.room,
337
366
  path: row.path,
338
367
  type: row.type,
339
368
  fields: row.fields,
340
- preamble: body.preamble,
341
- sections: body.sections,
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,
342
416
  };
343
417
  }
344
- function publish(entry) {
345
- const next = reconciled(entry.result, keyedOf(entry.plan, [...entry.built.live.entries()]));
346
- if (next === null)
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)
347
470
  return;
348
- entry.result = next.keyed;
349
- for (const listener of entry.listeners)
350
- listener(next.change);
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
+ }
351
494
  }
352
495
  return {
353
496
  apply(set) {
@@ -358,38 +501,52 @@ export function createReadSide() {
358
501
  for (const row of change.after)
359
502
  next.set(row.key, row);
360
503
  }
361
- if (next.size === 0)
362
- return;
363
- sync.begin();
364
- for (const [key, row] of next) {
365
- if (row === null) {
366
- if (rows.has(key))
367
- sync.write({ type: 'delete', key });
368
- continue;
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 });
369
513
  }
370
- sync.write({ type: rows.has(key) ? 'update' : 'insert', value: row });
514
+ sync.commit();
371
515
  }
372
- sync.commit();
516
+ recover();
373
517
  },
374
- async query(plan) {
518
+ recover,
519
+ async query(plan, at) {
375
520
  const { live: collection, dispose } = built(rows, plan);
376
521
  try {
377
522
  await collection.toArrayWhenReady();
378
- return keyedOf(plan, [...collection.entries()]).result;
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 };
379
527
  }
380
528
  finally {
381
529
  dispose();
382
530
  }
383
531
  },
384
- watch(plan, identity, deliver) {
532
+ watch(plan, identity, cover, deliverTo) {
385
533
  let entry = shared.get(identity);
386
534
  if (entry === undefined) {
387
535
  const created = {
388
536
  plan,
389
537
  built: built(rows, plan),
538
+ cover,
390
539
  result: undefined,
540
+ rows: new Map(),
541
+ bodies: new Map(),
391
542
  listeners: new Set(),
543
+ fresh: new Set(),
544
+ ready: new Set(),
392
545
  subscription: null,
546
+ whole: true,
547
+ dirty: new Set(),
548
+ stale: false,
549
+ running: false,
393
550
  };
394
551
  created.built.live.on('status:change', ({ status }) => {
395
552
  if (status === 'cleaned-up' && created.listeners.size === 0)
@@ -399,29 +556,40 @@ export function createReadSide() {
399
556
  entry = created;
400
557
  }
401
558
  const observed = entry;
402
- observed.listeners.add(deliver);
559
+ observed.listeners.add(deliverTo);
403
560
  observed.built.live.onFirstReady(() => {
404
- if (!observed.listeners.has(deliver))
561
+ if (!observed.listeners.has(deliverTo))
405
562
  return;
563
+ observed.fresh.add(deliverTo);
406
564
  if (observed.subscription === null) {
407
- observed.result = keyedOf(observed.plan, [...observed.built.live.entries()]);
408
- observed.subscription = observed.built.live.subscribeChanges(() => {
409
- publish(observed);
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);
410
573
  }, { includeInitialState: false });
411
574
  }
412
- deliver(observed.result);
575
+ wake(observed);
413
576
  });
414
577
  return () => {
415
- if (!observed.listeners.delete(deliver) || observed.listeners.size > 0)
578
+ observed.fresh.delete(deliverTo);
579
+ observed.ready.delete(deliverTo);
580
+ if (!observed.listeners.delete(deliverTo) || observed.listeners.size > 0)
416
581
  return;
417
582
  observed.subscription?.unsubscribe();
418
583
  observed.subscription = null;
584
+ observed.result = undefined;
585
+ observed.rows.clear();
586
+ observed.bodies.clear();
587
+ observed.dirty.clear();
588
+ observed.whole = true;
419
589
  };
420
590
  },
421
- documents() {
422
- return rows.toArray
423
- .filter((row) => row.kind === 'document' && row.type !== null)
424
- .map(searched);
591
+ room(room) {
592
+ return rows.toArray.flatMap((row) => row.kind !== 'document' || row.type === null || row.room !== room ? [] : [row.path]);
425
593
  },
426
594
  document(room, path) {
427
595
  const row = rows.get(documentKey(room, path));
@@ -430,6 +598,8 @@ export function createReadSide() {
430
598
  close() {
431
599
  for (const entry of shared.values()) {
432
600
  entry.listeners.clear();
601
+ entry.fresh.clear();
602
+ entry.ready.clear();
433
603
  entry.subscription?.unsubscribe();
434
604
  entry.built.dispose();
435
605
  }
@@ -438,3 +608,32 @@ export function createReadSide() {
438
608
  },
439
609
  };
440
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
+ }