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