@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.
- package/AGENTS.md +260 -259
- package/dist/acquisition.d.ts +14 -0
- package/dist/acquisition.d.ts.map +1 -0
- package/dist/acquisition.js +24 -0
- package/dist/adapter.d.ts +6 -1
- package/dist/adapter.d.ts.map +1 -1
- package/dist/change-set.d.ts +2 -0
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +34 -9
- package/dist/client.d.ts +8 -5
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1 -0
- package/dist/collection.d.ts +17 -3
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +230 -19
- package/dist/connection.d.ts +20 -7
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +926 -175
- package/dist/conversation.d.ts +8 -5
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +128 -83
- package/dist/durability.d.ts +7 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.d.ts +2 -2
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +3 -3
- package/dist/host.d.ts +11 -2
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +33 -3
- package/dist/identity.d.ts +2 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +6 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/memory.d.ts +2 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +7 -2
- package/dist/model.d.ts +1 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +9 -0
- package/dist/observation.d.ts +5 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +22 -11
- package/dist/overlay.d.ts +1 -0
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +25 -54
- package/dist/query.d.ts +28 -3
- package/dist/query.d.ts.map +1 -1
- package/dist/reach.d.ts +6 -2
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +16 -4
- package/dist/react.d.ts +5 -3
- package/dist/react.d.ts.map +1 -1
- package/dist/read-side.d.ts +13 -6
- package/dist/read-side.d.ts.map +1 -1
- package/dist/read-side.js +282 -83
- package/dist/readiness.d.ts +53 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +33 -0
- package/dist/recovery.d.ts +25 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +197 -0
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +11 -10
- package/dist/replica.d.ts +1 -1
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +47 -19
- package/dist/rows.d.ts +4 -13
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +2 -12
- package/dist/save.d.ts +5 -0
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +36 -13
- package/dist/search.d.ts +28 -6
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +108 -45
- package/dist/shared.d.ts +11 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +368 -0
- package/dist/status.d.ts +4 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/store.d.ts +18 -3
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +147 -49
- package/dist/turn.d.ts +7 -0
- package/dist/turn.d.ts.map +1 -0
- package/dist/turn.js +45 -0
- package/dist/wire.d.ts +2 -0
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +2 -0
- 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.
|
|
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
|
|
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>;
|
package/dist/react.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAkB,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAEvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"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"}
|
package/dist/read-side.d.ts
CHANGED
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
import type { ChangeSet } from './change-set.js';
|
|
2
|
-
import { type KeyedResult, type
|
|
3
|
-
import type { Plan,
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
22
|
+
message: QueryMessage;
|
|
16
23
|
} | null;
|
|
17
24
|
export declare function createReadSide(): ReadSide;
|
|
18
25
|
//# sourceMappingURL=read-side.d.ts.map
|
package/dist/read-side.d.ts.map
CHANGED
|
@@ -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,
|
|
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
|
|
105
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
181
|
-
return
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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 =
|
|
288
|
-
const
|
|
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 =
|
|
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 =
|
|
302
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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:
|
|
341
|
-
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
|
|
345
|
-
const
|
|
346
|
-
|
|
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.
|
|
349
|
-
|
|
350
|
-
|
|
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
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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.
|
|
514
|
+
sync.commit();
|
|
371
515
|
}
|
|
372
|
-
|
|
516
|
+
recover();
|
|
373
517
|
},
|
|
374
|
-
|
|
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
|
-
|
|
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,
|
|
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(
|
|
559
|
+
observed.listeners.add(deliverTo);
|
|
403
560
|
observed.built.live.onFirstReady(() => {
|
|
404
|
-
if (!observed.listeners.has(
|
|
561
|
+
if (!observed.listeners.has(deliverTo))
|
|
405
562
|
return;
|
|
563
|
+
observed.fresh.add(deliverTo);
|
|
406
564
|
if (observed.subscription === null) {
|
|
407
|
-
observed.
|
|
408
|
-
observed.subscription = observed.built.live.subscribeChanges(() => {
|
|
409
|
-
|
|
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
|
-
|
|
575
|
+
wake(observed);
|
|
413
576
|
});
|
|
414
577
|
return () => {
|
|
415
|
-
|
|
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
|
-
|
|
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
|
+
}
|