@agentshouse/mdruntime 0.1.0-alpha.9 → 0.1.0-c3903a68dcbbf
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 +210 -0
- package/README.md +44 -0
- package/dist/adapter.d.ts +155 -12
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +2 -3
- package/dist/attachment.d.ts +3 -0
- package/dist/attachment.d.ts.map +1 -0
- package/dist/attachment.js +8 -0
- package/dist/bootstrap.d.ts +3 -7
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +29 -27
- package/dist/change-set.d.ts +33 -0
- package/dist/change-set.d.ts.map +1 -0
- package/dist/change-set.js +87 -0
- package/dist/change.d.ts +9 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +6 -5
- package/dist/client.d.ts +40 -28
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +121 -177
- package/dist/collection.d.ts +15 -16
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +54 -87
- package/dist/connection.d.ts +57 -35
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +1475 -964
- package/dist/conversation.d.ts +41 -19
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +483 -327
- package/dist/durability.js +6 -6
- package/dist/file.d.ts +2 -2
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js +48 -71
- package/dist/host.d.ts +7 -2
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +100 -102
- package/dist/identity.d.ts +1 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +10 -9
- package/dist/index.d.ts +12 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/log.js +5 -6
- package/dist/memory.d.ts +6 -3
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +206 -210
- package/dist/model.d.ts +10 -25
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +18 -21
- package/dist/observation.d.ts +25 -0
- package/dist/observation.d.ts.map +1 -0
- package/dist/observation.js +85 -0
- package/dist/outcome.d.ts +17 -20
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +1 -23
- package/dist/overlay.d.ts +9 -2
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +187 -43
- package/dist/paths.d.ts +0 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +12 -19
- package/dist/query.d.ts +210 -10
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +420 -15
- package/dist/read-side.d.ts +14 -0
- package/dist/read-side.d.ts.map +1 -0
- package/dist/read-side.js +371 -0
- package/dist/refresh.d.ts +4 -5
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +45 -30
- package/dist/replica.d.ts +25 -5
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +232 -38
- package/dist/room-draft.d.ts +124 -0
- package/dist/room-draft.d.ts.map +1 -0
- package/dist/room-draft.js +327 -0
- package/dist/rows.d.ts +41 -0
- package/dist/rows.d.ts.map +1 -0
- package/dist/rows.js +100 -0
- package/dist/save.d.ts +8 -4
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +265 -350
- package/dist/search.d.ts +61 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +125 -0
- package/dist/status.d.ts +4 -6
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +9 -13
- package/dist/store.d.ts +68 -30
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +360 -134
- package/dist/transfer.d.ts +5 -0
- package/dist/transfer.d.ts.map +1 -1
- package/dist/transfer.js +1 -5
- package/dist/wire.d.ts +4 -3
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +50 -65
- package/package.json +6 -12
- package/dist/adapter.js.map +0 -1
- package/dist/bootstrap.js.map +0 -1
- package/dist/change.js.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/collection.js.map +0 -1
- package/dist/connection.js.map +0 -1
- package/dist/conversation.js.map +0 -1
- package/dist/durability.js.map +0 -1
- package/dist/file.js.map +0 -1
- package/dist/host.js.map +0 -1
- package/dist/identity.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/log.js.map +0 -1
- package/dist/memory.js.map +0 -1
- package/dist/model.js.map +0 -1
- package/dist/outcome.js.map +0 -1
- package/dist/overlay.js.map +0 -1
- package/dist/paths.js.map +0 -1
- package/dist/query.js.map +0 -1
- package/dist/refresh.js.map +0 -1
- package/dist/replica.js.map +0 -1
- package/dist/save.js.map +0 -1
- package/dist/status.js.map +0 -1
- package/dist/store.js.map +0 -1
- package/dist/transfer.js.map +0 -1
- package/dist/wire.js.map +0 -1
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import { and, BasicIndex, configureIndexDevMode, count, createCollection, createLiveQueryCollection, deepEquals, eq, gt, gte, inArray, isNull, isUndefined, lt, lte, not, or, toArray, } from '@tanstack/db';
|
|
2
|
+
import { rowsOf } from './observation.js';
|
|
3
|
+
import { documentKey } from './rows.js';
|
|
4
|
+
function every(expressions) {
|
|
5
|
+
const [first, second, ...rest] = expressions;
|
|
6
|
+
return second === undefined ? first : and(first, second, ...rest);
|
|
7
|
+
}
|
|
8
|
+
function some(expressions) {
|
|
9
|
+
const [first, second, ...rest] = expressions;
|
|
10
|
+
return second === undefined ? first : or(first, second, ...rest);
|
|
11
|
+
}
|
|
12
|
+
function equal(field, value) {
|
|
13
|
+
return or(eq(field, value), inArray(value, field));
|
|
14
|
+
}
|
|
15
|
+
function tested(test, field, size, written) {
|
|
16
|
+
if (test.op === 'eq')
|
|
17
|
+
return test.value === null ? isNull(field) : equal(field, test.value);
|
|
18
|
+
if (test.op === 'ne') {
|
|
19
|
+
return test.value === null
|
|
20
|
+
? not(isNull(field))
|
|
21
|
+
: or(isUndefined(field), isNull(field), not(equal(field, test.value)));
|
|
22
|
+
}
|
|
23
|
+
if (test.op === 'in' || test.op === 'nin') {
|
|
24
|
+
const matches = test.values.length === 0
|
|
25
|
+
? inArray(field, [])
|
|
26
|
+
: some(test.values.map((value) => (value === null ? isNull(field) : equal(field, value))));
|
|
27
|
+
if (test.op === 'in')
|
|
28
|
+
return matches;
|
|
29
|
+
return some([
|
|
30
|
+
isUndefined(field),
|
|
31
|
+
...(test.values.includes(null) ? [] : [isNull(field)]),
|
|
32
|
+
not(matches),
|
|
33
|
+
]);
|
|
34
|
+
}
|
|
35
|
+
if (test.op === 'range') {
|
|
36
|
+
const compare = { gt, gte, lt, lte };
|
|
37
|
+
return every(test.bounds.map(([operator, bound]) => compare[operator](field, bound)));
|
|
38
|
+
}
|
|
39
|
+
if (test.op === 'all') {
|
|
40
|
+
return every([not(isUndefined(size)), ...test.values.map((value) => inArray(value, field))]);
|
|
41
|
+
}
|
|
42
|
+
if (test.op === 'size')
|
|
43
|
+
return eq(size, test.size);
|
|
44
|
+
return test.exists ? not(isUndefined(written)) : isUndefined(written);
|
|
45
|
+
}
|
|
46
|
+
function conditioned(condition, row) {
|
|
47
|
+
if ('every' in condition)
|
|
48
|
+
return every(condition.every.map((item) => conditioned(item, row)));
|
|
49
|
+
if ('some' in condition)
|
|
50
|
+
return some(condition.some.map((item) => conditioned(item, row)));
|
|
51
|
+
return tested(condition.test, row.values[condition.field], row.sizes[condition.field], row.fields[condition.field]);
|
|
52
|
+
}
|
|
53
|
+
function scoped(scope, row, rooms) {
|
|
54
|
+
return every([
|
|
55
|
+
eq(row.kind, 'document'),
|
|
56
|
+
...(rooms === null ? [] : [inArray(row.room, [...rooms])]),
|
|
57
|
+
...(scope.types === null ? [] : [inArray(row.type, [...scope.types])]),
|
|
58
|
+
...(scope.pathPrefix === null ? [] : [inArray(scope.pathPrefix, row.directories)]),
|
|
59
|
+
...(scope.where === null ? [] : [conditioned(scope.where, row)]),
|
|
60
|
+
]);
|
|
61
|
+
}
|
|
62
|
+
function keyed(key, row) {
|
|
63
|
+
return key.of === 'field' ? row.values[key.field] : row[key.of];
|
|
64
|
+
}
|
|
65
|
+
function live(query) {
|
|
66
|
+
return createLiveQueryCollection({
|
|
67
|
+
query: query,
|
|
68
|
+
startSync: true,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function related(q, rows, scope, field, kept) {
|
|
72
|
+
const matched = kept === 'source' ? 'target' : 'source';
|
|
73
|
+
const from = q.from({ r: rows });
|
|
74
|
+
return from
|
|
75
|
+
.where(({ r }) => every([eq(r.kind, 'reference'), ...(field === null ? [] : [eq(r.field, field)])]))
|
|
76
|
+
.innerJoin({ m: rows }, ({ r, m }) => eq(r[matched], m.key))
|
|
77
|
+
.where(({ m }) => scoped(scope, m, null))
|
|
78
|
+
.groupBy(({ r }) => r[kept])
|
|
79
|
+
.select(({ r }) => ({ key: r[kept] }));
|
|
80
|
+
}
|
|
81
|
+
function filtered(q, rows, plan) {
|
|
82
|
+
const from = q.from({ d: rows });
|
|
83
|
+
let query = from.where(({ d }) => scoped(plan.root, d, plan.rooms));
|
|
84
|
+
if (plan.hop !== null) {
|
|
85
|
+
const hop = related(q, rows, plan.hop, plan.hop.field, 'source');
|
|
86
|
+
query = query.innerJoin({ h: hop }, ({ d, h }) => eq(d.key, h.key));
|
|
87
|
+
}
|
|
88
|
+
if (plan.backlinks !== null) {
|
|
89
|
+
const backlinks = related(q, rows, plan.backlinks, plan.backlinks.field, 'target');
|
|
90
|
+
query = query.innerJoin({ k: backlinks }, ({ d, k }) => eq(d.key, k.key));
|
|
91
|
+
}
|
|
92
|
+
return query;
|
|
93
|
+
}
|
|
94
|
+
function named(prefix, names, source) {
|
|
95
|
+
return Object.fromEntries(names.map((name, index) => [`${prefix}${index}`, source[name]]));
|
|
96
|
+
}
|
|
97
|
+
function documents(q, rows, plan, shape) {
|
|
98
|
+
let query = filtered(q, rows, plan);
|
|
99
|
+
if (shape.sections !== null || shape.preamble || shape.markdown) {
|
|
100
|
+
query = query.leftJoin({ b: rows }, ({ d, b }) => eq(d.body, b.key));
|
|
101
|
+
}
|
|
102
|
+
for (const { key, options } of shape.orderBy) {
|
|
103
|
+
query = query.orderBy(({ d }) => keyed(key, d), options);
|
|
104
|
+
}
|
|
105
|
+
if (shape.orderBy.length === 0 && plan.limit !== null) {
|
|
106
|
+
query = query.orderBy(({ d }) => d.key, { stringSort: 'lexical' });
|
|
107
|
+
}
|
|
108
|
+
if (plan.limit !== null)
|
|
109
|
+
query = query.limit(plan.limit);
|
|
110
|
+
return query.select(({ d, b }) => ({
|
|
111
|
+
room: d.room,
|
|
112
|
+
path: d.path,
|
|
113
|
+
type: d.type,
|
|
114
|
+
...(shape.fields === 'all' ? { fields: d.fields } : {}),
|
|
115
|
+
...(Array.isArray(shape.fields) ? named('field', shape.fields, d.fields) : {}),
|
|
116
|
+
...(shape.sections === 'all' ? { sections: b.sections } : {}),
|
|
117
|
+
...(Array.isArray(shape.sections) ? named('section', shape.sections, b.sections) : {}),
|
|
118
|
+
...(shape.preamble ? { preamble: b.preamble } : {}),
|
|
119
|
+
...(shape.markdown ? { markdown: b.markdown } : {}),
|
|
120
|
+
...(shape.backlinks ? { backlinks: toArray(backlinked(q, rows, d)) } : {}),
|
|
121
|
+
...(shape.change ? { change: d.change } : {}),
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
function backlinked(q, rows, document) {
|
|
125
|
+
const from = q.from({ r: rows });
|
|
126
|
+
return from
|
|
127
|
+
.where(({ r }) => eq(r.target, document.key))
|
|
128
|
+
.orderBy(({ r }) => r.path, { stringSort: 'lexical' })
|
|
129
|
+
.orderBy(({ r }) => r.field, { stringSort: 'lexical' })
|
|
130
|
+
.select(({ r }) => ({ path: r.path, type: r.type, field: r.field }));
|
|
131
|
+
}
|
|
132
|
+
function groups(q, stage, shape, limit) {
|
|
133
|
+
const keys = shape.groupBy.map((_, index) => `key${index}`);
|
|
134
|
+
const from = q.from({ m: stage });
|
|
135
|
+
let query = from.groupBy(({ m }) => keys.map((key) => m[key]));
|
|
136
|
+
for (const { by, direction } of shape.orderBy) {
|
|
137
|
+
query = query.orderBy(({ m }) => (by === 'count' ? count(m.key) : m[keys[by]]), direction);
|
|
138
|
+
}
|
|
139
|
+
if (limit !== null && shape.orderBy.length > 0)
|
|
140
|
+
query = query.limit(limit);
|
|
141
|
+
return query.select(({ m }) => ({
|
|
142
|
+
...Object.fromEntries(keys.map((key) => [key, m[key]])),
|
|
143
|
+
count: count(m.key),
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
function built(rows, plan) {
|
|
147
|
+
const shape = plan.shape;
|
|
148
|
+
if (shape.kind === 'documents') {
|
|
149
|
+
const collection = live((q) => documents(q, rows, plan, shape));
|
|
150
|
+
return { live: collection, dispose: () => void collection.cleanup() };
|
|
151
|
+
}
|
|
152
|
+
const stage = live((q) => filtered(q, rows, plan).select(({ d }) => ({
|
|
153
|
+
key: d.key,
|
|
154
|
+
...Object.fromEntries(shape.groupBy.map((key, index) => [`key${index}`, keyed(key, d)])),
|
|
155
|
+
})));
|
|
156
|
+
const collection = live((q) => groups(q, stage, shape, plan.limit));
|
|
157
|
+
return {
|
|
158
|
+
live: collection,
|
|
159
|
+
dispose: () => {
|
|
160
|
+
void collection.cleanup();
|
|
161
|
+
void stage.cleanup();
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function present(entries) {
|
|
166
|
+
return Object.fromEntries(entries.filter(([, value]) => value !== undefined));
|
|
167
|
+
}
|
|
168
|
+
function part(row, prefix, names, whole) {
|
|
169
|
+
if (names === 'all')
|
|
170
|
+
return whole;
|
|
171
|
+
return present(names.map((name, index) => [name, row[`${prefix}${index}`]]));
|
|
172
|
+
}
|
|
173
|
+
function documentOf(row, shape) {
|
|
174
|
+
if (row.type === null)
|
|
175
|
+
return { room: row.room, path: row.path };
|
|
176
|
+
return {
|
|
177
|
+
room: row.room,
|
|
178
|
+
path: row.path,
|
|
179
|
+
type: row.type,
|
|
180
|
+
...(shape.fields === null
|
|
181
|
+
? {}
|
|
182
|
+
: { fields: part(row, 'field', shape.fields, row.fields) }),
|
|
183
|
+
...(shape.sections === null
|
|
184
|
+
? {}
|
|
185
|
+
: {
|
|
186
|
+
sections: part(row, 'section', shape.sections, row.sections),
|
|
187
|
+
}),
|
|
188
|
+
...(shape.preamble ? { preamble: row.preamble } : {}),
|
|
189
|
+
...(shape.markdown ? { markdown: row.markdown } : {}),
|
|
190
|
+
...(shape.backlinks
|
|
191
|
+
? {
|
|
192
|
+
backlinks: row.backlinks.map(({ path, type, field }) => ({ path, type, field })),
|
|
193
|
+
}
|
|
194
|
+
: {}),
|
|
195
|
+
...(shape.change ? { change: row.change } : {}),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function keyedOf(plan, entries) {
|
|
199
|
+
const shape = plan.shape;
|
|
200
|
+
if (shape.kind === 'documents') {
|
|
201
|
+
return {
|
|
202
|
+
result: structuredClone({ documents: entries.map(([, row]) => documentOf(row, shape)) }),
|
|
203
|
+
keys: entries.map(([key]) => key),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
const bounded = shape.orderBy.length === 0 && plan.limit !== null ? entries.slice(0, plan.limit) : entries;
|
|
207
|
+
return {
|
|
208
|
+
result: structuredClone({
|
|
209
|
+
groups: bounded.map(([, row]) => ({
|
|
210
|
+
key: shape.groupBy.map((_, index) => row[`key${index}`]),
|
|
211
|
+
count: row.count,
|
|
212
|
+
})),
|
|
213
|
+
}),
|
|
214
|
+
keys: bounded.map(([key]) => key),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function reconciled(previous, next) {
|
|
218
|
+
const before = rowsOf(previous.result);
|
|
219
|
+
const held = new Map(previous.keys.map((key, index) => [key, before[index]]));
|
|
220
|
+
const changed = [];
|
|
221
|
+
const rows = rowsOf(next.result).map((row, index) => {
|
|
222
|
+
const key = next.keys[index];
|
|
223
|
+
const kept = held.get(key);
|
|
224
|
+
if (kept !== undefined && deepEquals(kept, row))
|
|
225
|
+
return kept;
|
|
226
|
+
changed.push([key, row]);
|
|
227
|
+
return row;
|
|
228
|
+
});
|
|
229
|
+
const present = new Set(next.keys);
|
|
230
|
+
const survivors = previous.keys.filter((key) => present.has(key));
|
|
231
|
+
const removed = previous.keys.filter((key) => !present.has(key));
|
|
232
|
+
const moved = survivors.length !== next.keys.length ||
|
|
233
|
+
survivors.some((key, index) => key !== next.keys[index]);
|
|
234
|
+
if (changed.length === 0 && removed.length === 0 && !moved)
|
|
235
|
+
return null;
|
|
236
|
+
return {
|
|
237
|
+
keyed: {
|
|
238
|
+
result: 'groups' in next.result
|
|
239
|
+
? { groups: rows }
|
|
240
|
+
: { documents: rows },
|
|
241
|
+
keys: next.keys,
|
|
242
|
+
},
|
|
243
|
+
change: { changed, removed, order: moved ? next.keys : null },
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
export function createReadSide() {
|
|
247
|
+
configureIndexDevMode({ enabled: false });
|
|
248
|
+
let sync;
|
|
249
|
+
const rows = createCollection({
|
|
250
|
+
getKey: (row) => row.key,
|
|
251
|
+
gcTime: 0,
|
|
252
|
+
startSync: true,
|
|
253
|
+
autoIndex: 'eager',
|
|
254
|
+
defaultIndexType: BasicIndex,
|
|
255
|
+
sync: {
|
|
256
|
+
rowUpdateMode: 'full',
|
|
257
|
+
sync: (params) => {
|
|
258
|
+
sync = params;
|
|
259
|
+
params.markReady();
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
const shared = new Map();
|
|
264
|
+
function searched(row) {
|
|
265
|
+
const body = rows.get(row.body);
|
|
266
|
+
return {
|
|
267
|
+
room: row.room,
|
|
268
|
+
path: row.path,
|
|
269
|
+
type: row.type,
|
|
270
|
+
fields: row.fields,
|
|
271
|
+
preamble: body.preamble,
|
|
272
|
+
sections: body.sections,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function publish(entry) {
|
|
276
|
+
const next = reconciled(entry.result, keyedOf(entry.plan, [...entry.built.live.entries()]));
|
|
277
|
+
if (next === null)
|
|
278
|
+
return;
|
|
279
|
+
entry.result = next.keyed;
|
|
280
|
+
for (const listener of entry.listeners)
|
|
281
|
+
listener(next.change);
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
apply(set) {
|
|
285
|
+
const next = new Map();
|
|
286
|
+
for (const change of set.documents) {
|
|
287
|
+
for (const row of change.before)
|
|
288
|
+
next.set(row.key, null);
|
|
289
|
+
for (const row of change.after)
|
|
290
|
+
next.set(row.key, row);
|
|
291
|
+
}
|
|
292
|
+
if (next.size === 0)
|
|
293
|
+
return;
|
|
294
|
+
sync.begin();
|
|
295
|
+
for (const [key, row] of next) {
|
|
296
|
+
if (row === null) {
|
|
297
|
+
if (rows.has(key))
|
|
298
|
+
sync.write({ type: 'delete', key });
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
sync.write({ type: rows.has(key) ? 'update' : 'insert', value: row });
|
|
302
|
+
}
|
|
303
|
+
sync.commit();
|
|
304
|
+
},
|
|
305
|
+
async query(plan) {
|
|
306
|
+
const { live: collection, dispose } = built(rows, plan);
|
|
307
|
+
try {
|
|
308
|
+
await collection.toArrayWhenReady();
|
|
309
|
+
return keyedOf(plan, [...collection.entries()]).result;
|
|
310
|
+
}
|
|
311
|
+
finally {
|
|
312
|
+
dispose();
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
watch(plan, identity, deliver) {
|
|
316
|
+
let entry = shared.get(identity);
|
|
317
|
+
if (entry === undefined) {
|
|
318
|
+
const created = {
|
|
319
|
+
plan,
|
|
320
|
+
built: built(rows, plan),
|
|
321
|
+
result: undefined,
|
|
322
|
+
listeners: new Set(),
|
|
323
|
+
subscription: null,
|
|
324
|
+
};
|
|
325
|
+
created.built.live.on('status:change', ({ status }) => {
|
|
326
|
+
if (status === 'cleaned-up' && created.listeners.size === 0)
|
|
327
|
+
shared.delete(identity);
|
|
328
|
+
});
|
|
329
|
+
shared.set(identity, created);
|
|
330
|
+
entry = created;
|
|
331
|
+
}
|
|
332
|
+
const observed = entry;
|
|
333
|
+
observed.listeners.add(deliver);
|
|
334
|
+
observed.built.live.onFirstReady(() => {
|
|
335
|
+
if (!observed.listeners.has(deliver))
|
|
336
|
+
return;
|
|
337
|
+
if (observed.subscription === null) {
|
|
338
|
+
observed.result = keyedOf(observed.plan, [...observed.built.live.entries()]);
|
|
339
|
+
observed.subscription = observed.built.live.subscribeChanges(() => {
|
|
340
|
+
publish(observed);
|
|
341
|
+
}, { includeInitialState: false });
|
|
342
|
+
}
|
|
343
|
+
deliver(observed.result);
|
|
344
|
+
});
|
|
345
|
+
return () => {
|
|
346
|
+
if (!observed.listeners.delete(deliver) || observed.listeners.size > 0)
|
|
347
|
+
return;
|
|
348
|
+
observed.subscription?.unsubscribe();
|
|
349
|
+
observed.subscription = null;
|
|
350
|
+
};
|
|
351
|
+
},
|
|
352
|
+
documents() {
|
|
353
|
+
return rows.toArray
|
|
354
|
+
.filter((row) => row.kind === 'document' && row.type !== null)
|
|
355
|
+
.map(searched);
|
|
356
|
+
},
|
|
357
|
+
document(room, path) {
|
|
358
|
+
const row = rows.get(documentKey(room, path));
|
|
359
|
+
return row === undefined || row.type === null ? null : searched(row);
|
|
360
|
+
},
|
|
361
|
+
close() {
|
|
362
|
+
for (const entry of shared.values()) {
|
|
363
|
+
entry.listeners.clear();
|
|
364
|
+
entry.subscription?.unsubscribe();
|
|
365
|
+
entry.built.dispose();
|
|
366
|
+
}
|
|
367
|
+
shared.clear();
|
|
368
|
+
void rows.cleanup();
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
}
|
package/dist/refresh.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { Adapter, AdapterFailure, Authorization } from './adapter.js';
|
|
1
|
+
import type { Adapter, AdapterFailure, Authorization, RetryableRefusal } from './adapter.js';
|
|
3
2
|
import { type ConfirmedLayer } from './replica.js';
|
|
4
|
-
import { type Unconfirmed } from './transfer.js';
|
|
3
|
+
import { type Refused, type Unconfirmed } from './transfer.js';
|
|
5
4
|
export type RefreshOutcome = {
|
|
6
5
|
kind: 'still-current';
|
|
7
6
|
} | {
|
|
@@ -9,6 +8,6 @@ export type RefreshOutcome = {
|
|
|
9
8
|
confirmed: ConfirmedLayer;
|
|
10
9
|
} | {
|
|
11
10
|
kind: 'beyond-horizon';
|
|
12
|
-
} | Unconfirmed | AdapterFailure;
|
|
13
|
-
export declare function refreshRoom(adapter: Adapter, authorization: Authorization, confirmed: ConfirmedLayer,
|
|
11
|
+
} | RetryableRefusal | Unconfirmed | Refused | AdapterFailure;
|
|
12
|
+
export declare function refreshRoom(adapter: Adapter, authorization: Authorization, confirmed: ConfirmedLayer, continuing: () => boolean, minPosition: string | undefined): Promise<RefreshOutcome>;
|
|
14
13
|
//# sourceMappingURL=refresh.d.ts.map
|
package/dist/refresh.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,aAAa,EAGb,gBAAgB,EAEjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAe,KAAK,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5E,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,cAAc,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B,gBAAgB,GAChB,WAAW,GACX,OAAO,GACP,cAAc,CAAC;AAEnB,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,cAAc,EACzB,UAAU,EAAE,MAAM,OAAO,EACzB,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,OAAO,CAAC,cAAc,CAAC,CA0EzB"}
|
package/dist/refresh.js
CHANGED
|
@@ -1,65 +1,80 @@
|
|
|
1
|
+
import { declaredAttachments } from './attachment.js';
|
|
1
2
|
import { readStaged } from './replica.js';
|
|
2
3
|
import { unconfirmed } from './transfer.js';
|
|
3
|
-
export async function refreshRoom(adapter, authorization, confirmed,
|
|
4
|
+
export async function refreshRoom(adapter, authorization, confirmed, continuing, minPosition) {
|
|
4
5
|
const locator = confirmed.record.locator;
|
|
5
6
|
const fromRoomVersion = confirmed.record.roomVersion;
|
|
6
7
|
const first = await adapter.refresh(authorization, {
|
|
7
8
|
locator,
|
|
8
9
|
selection: confirmed.record.replica.selection,
|
|
9
|
-
fromRoomVersion
|
|
10
|
+
fromRoomVersion,
|
|
11
|
+
...(minPosition === undefined ? {} : { minPosition }),
|
|
10
12
|
});
|
|
11
|
-
if (first.kind !== 'net-advancement')
|
|
13
|
+
if (first.kind !== 'net-advancement')
|
|
14
|
+
return first;
|
|
12
15
|
const roomVersion = first.roomVersion;
|
|
13
|
-
const documents = {
|
|
14
|
-
|
|
15
|
-
};
|
|
16
|
-
const
|
|
17
|
-
...confirmed.record.revisions
|
|
18
|
-
};
|
|
16
|
+
const documents = { ...confirmed.record.documents };
|
|
17
|
+
const revisions = { ...confirmed.record.revisions };
|
|
18
|
+
const changes = { ...confirmed.record.changes };
|
|
19
|
+
const written = { ...confirmed.record.written };
|
|
19
20
|
const binaryTargets = new Set(confirmed.record.binaryTargets);
|
|
20
|
-
const
|
|
21
|
+
const attachments = [];
|
|
22
|
+
const stage = (page) => {
|
|
23
|
+
if (page.attachments !== undefined)
|
|
24
|
+
attachments.push(page.attachments);
|
|
21
25
|
Object.assign(documents, page.documents);
|
|
22
26
|
Object.assign(revisions, page.revisions);
|
|
23
|
-
for (const path of Object.keys(page.documents))
|
|
24
|
-
|
|
27
|
+
for (const path of Object.keys(page.documents)) {
|
|
28
|
+
binaryTargets.delete(path);
|
|
29
|
+
delete changes[path];
|
|
30
|
+
written[path] = roomVersion;
|
|
31
|
+
}
|
|
32
|
+
for (const target of page.binaryTargets) {
|
|
25
33
|
delete documents[target];
|
|
26
34
|
delete revisions[target];
|
|
35
|
+
delete changes[target];
|
|
36
|
+
delete written[target];
|
|
27
37
|
binaryTargets.add(target);
|
|
28
38
|
}
|
|
29
|
-
|
|
39
|
+
Object.assign(changes, page.changes);
|
|
40
|
+
for (const path of page.removals) {
|
|
30
41
|
delete documents[path];
|
|
31
42
|
delete revisions[path];
|
|
43
|
+
delete changes[path];
|
|
44
|
+
delete written[path];
|
|
32
45
|
binaryTargets.delete(path);
|
|
33
46
|
}
|
|
34
47
|
};
|
|
35
48
|
stage(first);
|
|
36
49
|
let pageToken = first.pageToken;
|
|
37
|
-
while(pageToken !== undefined){
|
|
50
|
+
while (pageToken !== undefined) {
|
|
51
|
+
if (!continuing())
|
|
52
|
+
return unconfirmed;
|
|
38
53
|
const page = await adapter.refresh(authorization, {
|
|
39
54
|
locator,
|
|
40
55
|
selection: confirmed.record.replica.selection,
|
|
41
56
|
fromRoomVersion,
|
|
42
|
-
|
|
57
|
+
...(minPosition === undefined ? {} : { minPosition }),
|
|
58
|
+
pageToken,
|
|
43
59
|
});
|
|
44
|
-
if (page.kind === 'still-current' || page.kind === 'beyond-horizon')
|
|
45
|
-
|
|
46
|
-
if (page.
|
|
60
|
+
if (page.kind === 'still-current' || page.kind === 'beyond-horizon')
|
|
61
|
+
return unconfirmed;
|
|
62
|
+
if (page.kind !== 'net-advancement')
|
|
63
|
+
return page;
|
|
64
|
+
if (page.roomVersion !== roomVersion)
|
|
65
|
+
return unconfirmed;
|
|
47
66
|
stage(page);
|
|
48
67
|
pageToken = page.pageToken;
|
|
49
68
|
}
|
|
50
|
-
const
|
|
69
|
+
const staged = readStaged({
|
|
51
70
|
...confirmed.record,
|
|
52
71
|
roomVersion,
|
|
53
72
|
documents,
|
|
54
|
-
binaryTargets: [
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
confirmed: advanced
|
|
62
|
-
};
|
|
73
|
+
binaryTargets: [...binaryTargets].sort(),
|
|
74
|
+
revisions,
|
|
75
|
+
changes,
|
|
76
|
+
written,
|
|
77
|
+
attachments: attachments.length === 0 ? confirmed.record.attachments : declaredAttachments(attachments),
|
|
78
|
+
}, confirmed);
|
|
79
|
+
return staged.kind === 'staged' ? { kind: 'advanced', confirmed: staged.confirmed } : staged;
|
|
63
80
|
}
|
|
64
|
-
|
|
65
|
-
//# sourceMappingURL=refresh.js.map
|
package/dist/replica.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { AttachedModelBinding } from './model.js';
|
|
2
1
|
import { type ChangeBatch } from './change.js';
|
|
3
2
|
import { type Collection, type Composition } from './collection.js';
|
|
4
3
|
import { type Layer } from './overlay.js';
|
|
4
|
+
import { type Rewriting } from './save.js';
|
|
5
5
|
import type { ReplicaRecord } from './store.js';
|
|
6
|
+
import type { Refused } from './transfer.js';
|
|
6
7
|
export type ConfirmedLayer = {
|
|
7
8
|
record: ReplicaRecord;
|
|
8
9
|
collection: Collection;
|
|
@@ -10,14 +11,33 @@ export type ConfirmedLayer = {
|
|
|
10
11
|
export type VisibleLayer = Layer & {
|
|
11
12
|
collection: Collection;
|
|
12
13
|
};
|
|
14
|
+
export type Staged = {
|
|
15
|
+
kind: 'staged';
|
|
16
|
+
confirmed: ConfirmedLayer;
|
|
17
|
+
} | Refused;
|
|
13
18
|
export type Replica = {
|
|
14
19
|
confirmed: ConfirmedLayer;
|
|
15
20
|
queue: readonly ChangeBatch[];
|
|
16
21
|
visible: VisibleLayer;
|
|
22
|
+
replay: readonly ReplayStep[];
|
|
23
|
+
};
|
|
24
|
+
type ReplayStep = {
|
|
25
|
+
id: string;
|
|
26
|
+
before: Layer;
|
|
27
|
+
after: Layer;
|
|
28
|
+
effective: ChangeBatch;
|
|
29
|
+
collection?: Collection;
|
|
17
30
|
};
|
|
18
31
|
export declare function compositionOf(record: ReplicaRecord): Composition;
|
|
19
|
-
export declare function readConfirmed(record: ReplicaRecord):
|
|
20
|
-
export declare function
|
|
21
|
-
export declare function
|
|
22
|
-
export declare function
|
|
32
|
+
export declare function readConfirmed(record: ReplicaRecord, previous?: ConfirmedLayer): Staged;
|
|
33
|
+
export declare function sameMembership(record: ReplicaRecord, other: ReplicaRecord): boolean;
|
|
34
|
+
export declare function readStaged(record: ReplicaRecord, previous?: ConfirmedLayer): Staged;
|
|
35
|
+
export declare function readReclassified(record: ReplicaRecord, previous: ConfirmedLayer): Staged | {
|
|
36
|
+
kind: 'deferred';
|
|
37
|
+
};
|
|
38
|
+
export declare function applyReturned(confirmed: ConfirmedLayer, documents: Readonly<Record<string, string>>, revisions: Readonly<Record<string, string>>, removals: readonly string[], roomVersion: string): Staged;
|
|
39
|
+
export declare function replicaOf(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[], rewriting: Rewriting, previous?: Replica): Replica;
|
|
40
|
+
export declare function landed(batch: ChangeBatch, confirmed: ConfirmedLayer): boolean;
|
|
41
|
+
export declare function withdrawals(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[], withdrawable: (batch: ChangeBatch) => boolean, rewriting: Rewriting): readonly ChangeBatch[];
|
|
42
|
+
export {};
|
|
23
43
|
//# sourceMappingURL=replica.d.ts.map
|
package/dist/replica.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replica.d.ts","sourceRoot":"","sources":["../src/replica.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"replica.d.ts","sourceRoot":"","sources":["../src/replica.ts"],"names":[],"mappings":"AACA,OAAO,EAA0B,KAAK,WAAW,EAAqB,MAAM,aAAa,CAAC;AAC1F,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAA0C,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AAClF,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAE9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG;IACjC,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,cAAc,CAAA;CAAE,GAAG,OAAO,CAAC;AAE7E,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,cAAc,CAAC;IAC1B,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;IAC9B,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC;CAC/B,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,WAAW,CAAC;IACvB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAShE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,MAAM,CAWtF;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAMnF;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,MAAM,CAkBnF;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,cAAc,GACvB,MAAM,GAAG;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAM/B;AAED,wBAAgB,aAAa,CAC3B,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC3C,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC3C,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,WAAW,EAAE,MAAM,GAClB,MAAM,CA+BR;AAwDD,wBAAgB,SAAS,CACvB,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,SAAS,EAAE,SAAS,EACpB,QAAQ,CAAC,EAAE,OAAO,GACjB,OAAO,CA4CT;AAkFD,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,GAAG,OAAO,CAa7E;AAED,wBAAgB,WAAW,CACzB,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,YAAY,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,EAC7C,SAAS,EAAE,SAAS,GACnB,SAAS,WAAW,EAAE,CAoBxB"}
|