@agentshouse/mdruntime 0.1.0-cc7bd7a53214e → 0.1.0-cd3486bd400ed
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 +106 -31
- package/README.md +11 -10
- package/dist/adapter.d.ts +65 -28
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +1 -9
- package/dist/attached-model.d.ts +11 -0
- package/dist/attached-model.d.ts.map +1 -0
- package/dist/attached-model.js +47 -0
- package/dist/attempt.d.ts +16 -0
- package/dist/attempt.d.ts.map +1 -0
- package/dist/attempt.js +57 -0
- package/dist/bootstrap.d.ts +20 -6
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +89 -35
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +13 -7
- package/dist/change.d.ts +4 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/chat/acts.d.ts +34 -0
- package/dist/chat/acts.d.ts.map +1 -0
- package/dist/chat/acts.js +36 -0
- package/dist/chat/messages.d.ts +21 -0
- package/dist/chat/messages.d.ts.map +1 -0
- package/dist/chat/messages.js +151 -0
- package/dist/chat/overlay.d.ts +31 -0
- package/dist/chat/overlay.d.ts.map +1 -0
- package/dist/chat/overlay.js +97 -0
- package/dist/chat/parts.d.ts +57 -0
- package/dist/chat/parts.d.ts.map +1 -0
- package/dist/chat/parts.js +119 -0
- package/dist/chat/process.d.ts +20 -0
- package/dist/chat/process.d.ts.map +1 -0
- package/dist/chat/process.js +32 -0
- package/dist/chat/provider.d.ts +57 -0
- package/dist/chat/provider.d.ts.map +1 -0
- package/dist/chat/provider.js +637 -0
- package/dist/chat/questions.d.ts +31 -0
- package/dist/chat/questions.d.ts.map +1 -0
- package/dist/chat/questions.js +111 -0
- package/dist/chat/read.d.ts +5 -0
- package/dist/chat/read.d.ts.map +1 -0
- package/dist/chat/read.js +13 -0
- package/dist/chat.d.ts +7 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +2 -0
- package/dist/client.d.ts +11 -7
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +58 -25
- package/dist/collection.d.ts +6 -11
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +56 -19
- package/dist/connection.d.ts +18 -13
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +679 -568
- package/dist/conversation.d.ts +27 -8
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +210 -81
- package/dist/expectation.d.ts +21 -0
- package/dist/expectation.d.ts.map +1 -0
- package/dist/expectation.js +70 -0
- package/dist/failure.d.ts +13 -0
- package/dist/failure.d.ts.map +1 -0
- package/dist/failure.js +19 -0
- package/dist/host.d.ts +1 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +8 -19
- package/dist/identity.d.ts +2 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +10 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/memory.d.ts +12 -5
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +108 -36
- package/dist/model.d.ts +13 -12
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +6 -3
- package/dist/open.d.ts +2 -0
- package/dist/open.d.ts.map +1 -0
- package/dist/open.js +1 -0
- package/dist/outcome.d.ts +22 -3
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +35 -1
- package/dist/overlay.d.ts +1 -1
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +19 -15
- package/dist/paths.d.ts +0 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +0 -16
- package/dist/query.d.ts +3 -1
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +74 -33
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +29 -35
- package/dist/react.d.ts +41 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +64 -0
- package/dist/read-side.d.ts.map +1 -1
- package/dist/read-side.js +102 -46
- package/dist/refresh.d.ts +12 -1
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +35 -22
- package/dist/replica.d.ts +6 -6
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +53 -39
- package/dist/room-draft.d.ts +8 -8
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +13 -22
- package/dist/rows.d.ts +4 -1
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +82 -39
- package/dist/save.d.ts +4 -3
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +127 -68
- package/dist/search.d.ts +3 -2
- package/dist/search.d.ts.map +1 -1
- package/dist/status.d.ts +2 -2
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +0 -8
- package/dist/store.d.ts +26 -2
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +206 -90
- package/dist/wire.d.ts +6 -15
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +14 -17
- package/package.json +14 -2
package/dist/react.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { useCallback, useLayoutEffect, useRef, useState } from 'react';
|
|
2
|
+
import { failed, runtimeError } from './failure.js';
|
|
3
|
+
const LOADING = { state: 'loading' };
|
|
4
|
+
export function useObserve(client, topic, ...input) {
|
|
5
|
+
const key = JSON.stringify([topic, ...input]);
|
|
6
|
+
const [held, setHeld] = useState(null);
|
|
7
|
+
const opened = useRef(input);
|
|
8
|
+
opened.current = input;
|
|
9
|
+
useLayoutEffect(() => {
|
|
10
|
+
if (client === null)
|
|
11
|
+
return;
|
|
12
|
+
let live = true;
|
|
13
|
+
let observation = null;
|
|
14
|
+
const observe = client.observe;
|
|
15
|
+
void observe(topic, ...opened.current).then((open) => {
|
|
16
|
+
if (!live) {
|
|
17
|
+
open.close();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
observation = open;
|
|
21
|
+
const take = (value) => {
|
|
22
|
+
if (live)
|
|
23
|
+
setHeld({ client, key, observed: { state: 'ready', value } });
|
|
24
|
+
};
|
|
25
|
+
take(open.current());
|
|
26
|
+
open.subscribe(take);
|
|
27
|
+
});
|
|
28
|
+
return () => {
|
|
29
|
+
live = false;
|
|
30
|
+
observation?.close();
|
|
31
|
+
};
|
|
32
|
+
}, [client, key]);
|
|
33
|
+
return held !== null && held.client === client && held.key === key ? held.observed : LOADING;
|
|
34
|
+
}
|
|
35
|
+
const IDLE = { busy: false, outcome: null, failure: null };
|
|
36
|
+
export async function saveRoomDrafts(client, room, roomDrafts) {
|
|
37
|
+
const kept = [];
|
|
38
|
+
for (const [path, parts] of roomDrafts) {
|
|
39
|
+
const prior = await client.roomDraft.read(room, path);
|
|
40
|
+
const write = await client.roomDraft.write(room, path, prior?.revision ?? null, parts);
|
|
41
|
+
if (write.outcome !== 'written' || write.roomDraft === null) {
|
|
42
|
+
throw runtimeError(write.outcome === 'stale' ? write.code : 'room-draft-unwritten', `the Room Draft at ${path} was not written`);
|
|
43
|
+
}
|
|
44
|
+
kept.push({ path, revision: write.roomDraft.revision });
|
|
45
|
+
}
|
|
46
|
+
return client.save(room, kept);
|
|
47
|
+
}
|
|
48
|
+
export function useSave(client) {
|
|
49
|
+
const [state, setState] = useState(IDLE);
|
|
50
|
+
const save = useCallback(async (room, roomDrafts) => {
|
|
51
|
+
setState({ busy: true, outcome: null, failure: null });
|
|
52
|
+
try {
|
|
53
|
+
const outcome = await saveRoomDrafts(client, room, roomDrafts);
|
|
54
|
+
setState({ busy: false, outcome, failure: null });
|
|
55
|
+
return outcome;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
const failure = failed(error);
|
|
59
|
+
setState({ busy: false, outcome: null, failure });
|
|
60
|
+
throw failure;
|
|
61
|
+
}
|
|
62
|
+
}, [client]);
|
|
63
|
+
return { ...state, save };
|
|
64
|
+
}
|
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":"
|
|
1
|
+
{"version":3,"file":"read-side.d.ts","sourceRoot":"","sources":["../src/read-side.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAU,KAAK,WAAW,EAAE,KAAK,WAAW,EAAe,MAAM,kBAAkB,CAAC;AAC3F,OAAO,KAAK,EAOV,IAAI,EAIJ,WAAW,EAIZ,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAuDpD,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACxC,KAAK,CACH,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW,KAAK,IAAI,GACpD,MAAM,IAAI,CAAC;IACd,SAAS,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAC9D,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AA+UF,wBAAgB,UAAU,CACxB,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,WAAW,GAChB;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAAG,IAAI,CA4BpD;AAED,wBAAgB,cAAc,IAAI,QAAQ,CA4HzC"}
|
package/dist/read-side.js
CHANGED
|
@@ -1,54 +1,58 @@
|
|
|
1
|
-
import { and, BasicIndex, configureIndexDevMode, count, createCollection, createLiveQueryCollection, deepEquals, eq,
|
|
1
|
+
import { and, BasicIndex, configureIndexDevMode, count, createCollection, createLiveQueryCollection, deepEquals, eq, inArray, or, toArray, } from '@tanstack/db';
|
|
2
|
+
import { ARRAY_INDEX, pointerSegments } from '@agentshouse/mdmodel';
|
|
2
3
|
import { rowsOf } from './observation.js';
|
|
3
4
|
import { documentKey } from './rows.js';
|
|
4
5
|
function every(expressions) {
|
|
5
6
|
const [first, second, ...rest] = expressions;
|
|
6
7
|
return second === undefined ? first : and(first, second, ...rest);
|
|
7
8
|
}
|
|
8
|
-
function
|
|
9
|
-
|
|
10
|
-
return second === undefined ? first : or(first, second, ...rest);
|
|
9
|
+
function same(held, value) {
|
|
10
|
+
return Array.isArray(held) ? held.includes(value) : held === value;
|
|
11
11
|
}
|
|
12
|
-
function
|
|
13
|
-
|
|
12
|
+
function ordered(held, [operator, bound]) {
|
|
13
|
+
if (typeof held !== typeof bound || held === null || typeof held === 'object')
|
|
14
|
+
return false;
|
|
15
|
+
const left = held;
|
|
16
|
+
const right = bound;
|
|
17
|
+
if (operator === 'gt')
|
|
18
|
+
return left > right;
|
|
19
|
+
if (operator === 'gte')
|
|
20
|
+
return left >= right;
|
|
21
|
+
if (operator === 'lt')
|
|
22
|
+
return left < right;
|
|
23
|
+
return left <= right;
|
|
14
24
|
}
|
|
15
|
-
function
|
|
25
|
+
function satisfied(test, held) {
|
|
16
26
|
if (test.op === 'eq')
|
|
17
|
-
return
|
|
18
|
-
if (test.op === 'ne')
|
|
19
|
-
return test.value
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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);
|
|
27
|
+
return same(held, test.value);
|
|
28
|
+
if (test.op === 'ne')
|
|
29
|
+
return !same(held, test.value);
|
|
30
|
+
if (test.op === 'in')
|
|
31
|
+
return test.values.some((value) => same(held, value));
|
|
32
|
+
if (test.op === 'nin')
|
|
33
|
+
return !test.values.some((value) => same(held, value));
|
|
34
|
+
if (test.op === 'range')
|
|
35
|
+
return test.bounds.every((bound) => ordered(held, bound));
|
|
36
|
+
if (test.op === 'all')
|
|
37
|
+
return Array.isArray(held) && test.values.every((value) => same(held, value));
|
|
38
|
+
return Array.isArray(held) && held.length === test.size;
|
|
39
|
+
}
|
|
40
|
+
function tested(test, reached) {
|
|
41
|
+
if (test.op === 'exists')
|
|
42
|
+
return test.exists === (reached !== undefined);
|
|
43
|
+
if (reached === undefined)
|
|
44
|
+
return test.op === 'ne' || test.op === 'nin';
|
|
45
|
+
return reached.some((held) => satisfied(test, held));
|
|
45
46
|
}
|
|
46
47
|
function conditioned(condition, row) {
|
|
47
48
|
if ('every' in condition)
|
|
48
|
-
return
|
|
49
|
+
return condition.every.every((item) => conditioned(item, row));
|
|
49
50
|
if ('some' in condition)
|
|
50
|
-
return
|
|
51
|
-
return tested(condition.test, row.
|
|
51
|
+
return condition.some.some((item) => conditioned(item, row));
|
|
52
|
+
return tested(condition.test, row.reached[condition.field]);
|
|
53
|
+
}
|
|
54
|
+
function narrowed(query, where, alias) {
|
|
55
|
+
return where === null ? query : query.fn.where((row) => conditioned(where, row[alias]));
|
|
52
56
|
}
|
|
53
57
|
function reached(reach, room, document) {
|
|
54
58
|
return reach === null
|
|
@@ -62,7 +66,6 @@ function scoped(scope, row, rooms, reach) {
|
|
|
62
66
|
...reached(reach, row.room, row.key),
|
|
63
67
|
...(scope.types === null ? [] : [inArray(row.type, [...scope.types])]),
|
|
64
68
|
...(scope.pathPrefix === null ? [] : [inArray(scope.pathPrefix, row.directories)]),
|
|
65
|
-
...(scope.where === null ? [] : [conditioned(scope.where, row)]),
|
|
66
69
|
]);
|
|
67
70
|
}
|
|
68
71
|
function keyed(key, row) {
|
|
@@ -77,16 +80,17 @@ function live(query) {
|
|
|
77
80
|
function related(q, rows, scope, field, kept, reach) {
|
|
78
81
|
const matched = kept === 'source' ? 'target' : 'source';
|
|
79
82
|
const from = q.from({ r: rows });
|
|
80
|
-
|
|
81
|
-
.where(({ r }) => every([eq(r.kind, 'reference'), ...(field === null ? [] : [
|
|
83
|
+
const joined = from
|
|
84
|
+
.where(({ r }) => every([eq(r.kind, 'reference'), ...(field === null ? [] : [inArray(field, r.forms)])]))
|
|
82
85
|
.innerJoin({ m: rows }, ({ r, m }) => eq(r[matched], m.key))
|
|
83
|
-
.where(({ m }) => scoped(scope, m, null, reach))
|
|
86
|
+
.where(({ m }) => scoped(scope, m, null, reach));
|
|
87
|
+
return narrowed(joined, scope.where, 'm')
|
|
84
88
|
.groupBy(({ r }) => r[kept])
|
|
85
89
|
.select(({ r }) => ({ key: r[kept] }));
|
|
86
90
|
}
|
|
87
91
|
function filtered(q, rows, plan) {
|
|
88
92
|
const from = q.from({ d: rows });
|
|
89
|
-
let query = from.where(({ d }) => scoped(plan.root, d, plan.rooms, plan.reach));
|
|
93
|
+
let query = narrowed(from.where(({ d }) => scoped(plan.root, d, plan.rooms, plan.reach)), plan.root.where, 'd');
|
|
90
94
|
if (plan.hop !== null) {
|
|
91
95
|
const hop = related(q, rows, plan.hop, plan.hop.field, 'source', plan.reach);
|
|
92
96
|
query = query.innerJoin({ h: hop }, ({ d, h }) => eq(d.key, h.key));
|
|
@@ -117,8 +121,7 @@ function documents(q, rows, plan, shape) {
|
|
|
117
121
|
room: d.room,
|
|
118
122
|
path: d.path,
|
|
119
123
|
type: d.type,
|
|
120
|
-
...(shape.fields ===
|
|
121
|
-
...(Array.isArray(shape.fields) ? named('field', shape.fields, d.fields) : {}),
|
|
124
|
+
...(shape.fields === null ? {} : { fields: d.fields }),
|
|
122
125
|
...(shape.sections === 'all' ? { sections: b.sections } : {}),
|
|
123
126
|
...(Array.isArray(shape.sections) ? named('section', shape.sections, b.sections) : {}),
|
|
124
127
|
...(shape.preamble ? { preamble: b.preamble } : {}),
|
|
@@ -176,6 +179,55 @@ function part(row, prefix, names, whole) {
|
|
|
176
179
|
return whole;
|
|
177
180
|
return present(names.map((name, index) => [name, row[`${prefix}${index}`]]));
|
|
178
181
|
}
|
|
182
|
+
function masked(pointers) {
|
|
183
|
+
const root = { whole: false, members: new Map() };
|
|
184
|
+
for (const pointer of pointers) {
|
|
185
|
+
let mask = root;
|
|
186
|
+
for (const token of pointerSegments(pointer)) {
|
|
187
|
+
const next = mask.members.get(token) ?? { whole: false, members: new Map() };
|
|
188
|
+
mask.members.set(token, next);
|
|
189
|
+
mask = next;
|
|
190
|
+
}
|
|
191
|
+
mask.whole = true;
|
|
192
|
+
}
|
|
193
|
+
return root;
|
|
194
|
+
}
|
|
195
|
+
function merged(left, right) {
|
|
196
|
+
if (left === undefined)
|
|
197
|
+
return right;
|
|
198
|
+
const members = new Map(left.members);
|
|
199
|
+
for (const [token, mask] of right.members)
|
|
200
|
+
members.set(token, merged(members.get(token), mask));
|
|
201
|
+
return { whole: left.whole || right.whole, members };
|
|
202
|
+
}
|
|
203
|
+
function cut(value, mask) {
|
|
204
|
+
if (mask.whole)
|
|
205
|
+
return value;
|
|
206
|
+
if (Array.isArray(value)) {
|
|
207
|
+
const each = {
|
|
208
|
+
whole: false,
|
|
209
|
+
members: new Map([...mask.members].filter(([token]) => !ARRAY_INDEX.test(token))),
|
|
210
|
+
};
|
|
211
|
+
const kept = [];
|
|
212
|
+
value.forEach((item, index) => {
|
|
213
|
+
const part = cut(item, merged(mask.members.get(String(index)), each));
|
|
214
|
+
if (part !== undefined)
|
|
215
|
+
kept[index] = part;
|
|
216
|
+
});
|
|
217
|
+
return kept.length === 0 ? undefined : kept;
|
|
218
|
+
}
|
|
219
|
+
if (typeof value !== 'object' || value === null)
|
|
220
|
+
return undefined;
|
|
221
|
+
const kept = Object.entries(value).flatMap(([key, held]) => {
|
|
222
|
+
const member = mask.members.get(key);
|
|
223
|
+
const part = member === undefined ? undefined : cut(held, member);
|
|
224
|
+
return part === undefined ? [] : [[key, part]];
|
|
225
|
+
});
|
|
226
|
+
return kept.length === 0 ? undefined : Object.fromEntries(kept);
|
|
227
|
+
}
|
|
228
|
+
function selected(fields, pointers) {
|
|
229
|
+
return (cut(fields, masked(pointers)) ?? {});
|
|
230
|
+
}
|
|
179
231
|
function documentOf(row, shape) {
|
|
180
232
|
if (row.type === null)
|
|
181
233
|
return { room: row.room, path: row.path };
|
|
@@ -185,7 +237,11 @@ function documentOf(row, shape) {
|
|
|
185
237
|
type: row.type,
|
|
186
238
|
...(shape.fields === null
|
|
187
239
|
? {}
|
|
188
|
-
: {
|
|
240
|
+
: {
|
|
241
|
+
fields: shape.fields === 'all'
|
|
242
|
+
? row.fields
|
|
243
|
+
: selected(row.fields, shape.fields),
|
|
244
|
+
}),
|
|
189
245
|
...(shape.sections === null
|
|
190
246
|
? {}
|
|
191
247
|
: {
|
package/dist/refresh.d.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import type { Adapter, AdapterFailure, Authorization, RetryableRefusal } from './adapter.js';
|
|
2
|
+
import type { Remodel } from './bootstrap.js';
|
|
2
3
|
import { type ConfirmedLayer } from './replica.js';
|
|
4
|
+
import type { ReplicaRecord } from './store.js';
|
|
3
5
|
import { type Refused, type Unconfirmed } from './transfer.js';
|
|
6
|
+
export type Advancement = {
|
|
7
|
+
kind: 'still-current';
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'advanced';
|
|
10
|
+
record: ReplicaRecord;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'beyond-horizon';
|
|
13
|
+
} | RetryableRefusal | Unconfirmed | AdapterFailure;
|
|
4
14
|
export type RefreshOutcome = {
|
|
5
15
|
kind: 'still-current';
|
|
6
16
|
} | {
|
|
@@ -9,5 +19,6 @@ export type RefreshOutcome = {
|
|
|
9
19
|
} | {
|
|
10
20
|
kind: 'beyond-horizon';
|
|
11
21
|
} | RetryableRefusal | Unconfirmed | Refused | AdapterFailure;
|
|
12
|
-
export declare function
|
|
22
|
+
export declare function advancement(adapter: Adapter, authorization: Authorization, held: ReplicaRecord, remodel: Remodel, continuing: () => boolean): Promise<Advancement>;
|
|
23
|
+
export declare function refreshRoom(adapter: Adapter, authorization: Authorization, confirmed: ConfirmedLayer, remodel: Remodel, continuing: () => boolean): Promise<RefreshOutcome>;
|
|
13
24
|
//# 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,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,
|
|
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,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAe,KAAK,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5E,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B,gBAAgB,GAChB,WAAW,GACX,cAAc,CAAC;AAEnB,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,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,OAAO,GACxB,OAAO,CAAC,WAAW,CAAC,CA4EtB;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,cAAc,EACzB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,OAAO,GACxB,OAAO,CAAC,cAAc,CAAC,CAKzB"}
|
package/dist/refresh.js
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import { declaredAttachments } from './attachment.js';
|
|
2
2
|
import { readStaged } from './replica.js';
|
|
3
3
|
import { unconfirmed } from './transfer.js';
|
|
4
|
-
export async function
|
|
5
|
-
const locator =
|
|
6
|
-
const fromRoomVersion =
|
|
4
|
+
export async function advancement(adapter, authorization, held, remodel, continuing) {
|
|
5
|
+
const locator = held.locator;
|
|
6
|
+
const fromRoomVersion = held.roomVersion;
|
|
7
7
|
const first = await adapter.refresh(authorization, {
|
|
8
8
|
locator,
|
|
9
|
-
selection:
|
|
9
|
+
selection: held.replica.selection,
|
|
10
10
|
fromRoomVersion,
|
|
11
|
-
...(minPosition === undefined ? {} : { minPosition }),
|
|
12
11
|
});
|
|
13
12
|
if (first.kind !== 'net-advancement')
|
|
14
13
|
return first;
|
|
15
14
|
const roomVersion = first.roomVersion;
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
15
|
+
const models = remodel(first.models, {
|
|
16
|
+
collection: held.model,
|
|
17
|
+
selection: held.selectionModel,
|
|
18
|
+
});
|
|
19
|
+
const documents = { ...held.documents };
|
|
20
|
+
const revisions = { ...held.revisions };
|
|
21
|
+
const changes = { ...held.changes };
|
|
22
|
+
const written = { ...held.written };
|
|
23
|
+
const binaryTargets = new Set(held.binaryTargets);
|
|
21
24
|
const attachments = [];
|
|
22
25
|
const stage = (page) => {
|
|
23
26
|
if (page.attachments !== undefined)
|
|
@@ -52,9 +55,8 @@ export async function refreshRoom(adapter, authorization, confirmed, continuing,
|
|
|
52
55
|
return unconfirmed;
|
|
53
56
|
const page = await adapter.refresh(authorization, {
|
|
54
57
|
locator,
|
|
55
|
-
selection:
|
|
58
|
+
selection: held.replica.selection,
|
|
56
59
|
fromRoomVersion,
|
|
57
|
-
...(minPosition === undefined ? {} : { minPosition }),
|
|
58
60
|
pageToken,
|
|
59
61
|
});
|
|
60
62
|
if (page.kind === 'still-current' || page.kind === 'beyond-horizon')
|
|
@@ -66,15 +68,26 @@ export async function refreshRoom(adapter, authorization, confirmed, continuing,
|
|
|
66
68
|
stage(page);
|
|
67
69
|
pageToken = page.pageToken;
|
|
68
70
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
return {
|
|
72
|
+
kind: 'advanced',
|
|
73
|
+
record: {
|
|
74
|
+
...held,
|
|
75
|
+
model: models.collection,
|
|
76
|
+
selectionModel: models.selection,
|
|
77
|
+
roomVersion,
|
|
78
|
+
documents,
|
|
79
|
+
binaryTargets: [...binaryTargets].sort(),
|
|
80
|
+
revisions,
|
|
81
|
+
changes,
|
|
82
|
+
written,
|
|
83
|
+
attachments: attachments.length === 0 ? held.attachments : declaredAttachments(attachments),
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export async function refreshRoom(adapter, authorization, confirmed, remodel, continuing) {
|
|
88
|
+
const advanced = await advancement(adapter, authorization, confirmed.record, remodel, continuing);
|
|
89
|
+
if (advanced.kind !== 'advanced')
|
|
90
|
+
return advanced;
|
|
91
|
+
const staged = readStaged(advanced.record, confirmed);
|
|
79
92
|
return staged.kind === 'staged' ? { kind: 'advanced', confirmed: staged.confirmed } : staged;
|
|
80
93
|
}
|
package/dist/replica.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ChangeBatch } from './change.js';
|
|
2
2
|
import { type Collection, type Composition } from './collection.js';
|
|
3
3
|
import { type Layer } from './overlay.js';
|
|
4
|
-
import {
|
|
4
|
+
import type { HeadChange, RoomAttachment } from './adapter.js';
|
|
5
5
|
import type { ReplicaRecord } from './store.js';
|
|
6
6
|
import type { Refused } from './transfer.js';
|
|
7
7
|
export type ConfirmedLayer = {
|
|
@@ -29,15 +29,15 @@ type ReplayStep = {
|
|
|
29
29
|
collection?: Collection;
|
|
30
30
|
};
|
|
31
31
|
export declare function compositionOf(record: ReplicaRecord): Composition;
|
|
32
|
-
export declare function
|
|
32
|
+
export declare function confirmedOf(record: ReplicaRecord, previous?: ConfirmedLayer): ConfirmedLayer;
|
|
33
33
|
export declare function sameMembership(record: ReplicaRecord, other: ReplicaRecord): boolean;
|
|
34
34
|
export declare function readStaged(record: ReplicaRecord, previous?: ConfirmedLayer): Staged;
|
|
35
35
|
export declare function readReclassified(record: ReplicaRecord, previous: ConfirmedLayer): Staged | {
|
|
36
36
|
kind: 'deferred';
|
|
37
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[],
|
|
40
|
-
export declare function landed(batch: ChangeBatch, confirmed: ConfirmedLayer): boolean;
|
|
41
|
-
export declare function withdrawals(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[], withdrawable: (batch: ChangeBatch) => boolean,
|
|
38
|
+
export declare function applyReturned(confirmed: ConfirmedLayer, documents: Readonly<Record<string, string>>, revisions: Readonly<Record<string, string>>, changes: Readonly<Record<string, HeadChange>>, removals: readonly string[], attachments: readonly RoomAttachment[] | undefined, roomVersion: string, writtenAt: string): Staged;
|
|
39
|
+
export declare function replicaOf(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[], previous?: Replica): Replica;
|
|
40
|
+
export declare function landed(batch: ChangeBatch, confirmed: ConfirmedLayer, current?: Readonly<Record<string, string>>): boolean;
|
|
41
|
+
export declare function withdrawals(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[], withdrawable: (batch: ChangeBatch) => boolean, local: boolean): readonly ChangeBatch[];
|
|
42
42
|
export {};
|
|
43
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":"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;
|
|
1
|
+
{"version":3,"file":"replica.d.ts","sourceRoot":"","sources":["../src/replica.ts"],"names":[],"mappings":"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"}
|
package/dist/replica.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { parse } from '@agentshouse/mdmodel';
|
|
1
|
+
import { equalValue, parse } from '@agentshouse/mdmodel';
|
|
2
2
|
import { immutable } from './change.js';
|
|
3
|
-
import {
|
|
3
|
+
import { collectionOf, unreadable, validateCollection, } from './collection.js';
|
|
4
4
|
import { overlay, overlayChanged, sameLayerText } from './overlay.js';
|
|
5
5
|
import { providerRewritten } from './save.js';
|
|
6
|
-
import {
|
|
6
|
+
import { declaredAttachments } from './attachment.js';
|
|
7
7
|
export function compositionOf(record) {
|
|
8
8
|
return {
|
|
9
9
|
model: record.model,
|
|
@@ -12,52 +12,62 @@ export function compositionOf(record) {
|
|
|
12
12
|
: { roots: record.typedSelection.roots, model: record.selectionModel },
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
-
export function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
:
|
|
19
|
-
|
|
20
|
-
? { kind: 'staged', confirmed: { record, collection: read.collection } }
|
|
21
|
-
: read;
|
|
15
|
+
export function confirmedOf(record, previous) {
|
|
16
|
+
return {
|
|
17
|
+
record,
|
|
18
|
+
collection: collectionOf(record.documents, compositionOf(record), previous?.collection),
|
|
19
|
+
};
|
|
22
20
|
}
|
|
23
21
|
export function sameMembership(record, other) {
|
|
24
22
|
return (JSON.stringify(record.typedSelection?.roots ?? null) ===
|
|
25
23
|
JSON.stringify(other.typedSelection?.roots ?? null));
|
|
26
24
|
}
|
|
27
25
|
export function readStaged(record, previous) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
record.
|
|
26
|
+
const textChanged = previous === undefined || !sameLayerText(record, previous.record);
|
|
27
|
+
const modeled = record.model.status !== 'unavailable' || record.selectionModel.status !== 'unavailable';
|
|
28
|
+
if (modeled &&
|
|
29
|
+
(textChanged ||
|
|
30
|
+
record.model !== previous?.record.model ||
|
|
31
|
+
record.selectionModel !== previous?.record.selectionModel)) {
|
|
33
32
|
const verdict = validateCollection(record.documents, record.binaryTargets, compositionOf(record));
|
|
34
33
|
if (verdict.verdict === 'refuse' && verdict.rule !== 'model-unavailable') {
|
|
35
34
|
return { kind: 'refused', refusal: verdict };
|
|
36
35
|
}
|
|
36
|
+
if (verdict.verdict === 'refuse') {
|
|
37
|
+
const refused = unreadable(record.documents, previous?.record.documents);
|
|
38
|
+
if (refused !== null)
|
|
39
|
+
return refused;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else if (textChanged) {
|
|
43
|
+
const refused = unreadable(record.documents, previous?.record.documents);
|
|
44
|
+
if (refused !== null)
|
|
45
|
+
return refused;
|
|
37
46
|
}
|
|
38
|
-
return
|
|
47
|
+
return { kind: 'staged', confirmed: confirmedOf(record, previous) };
|
|
39
48
|
}
|
|
40
49
|
export function readReclassified(record, previous) {
|
|
41
50
|
const verdict = validateCollection(record.documents, record.binaryTargets, compositionOf(record));
|
|
42
51
|
if (verdict.verdict !== 'refuse')
|
|
43
|
-
return
|
|
52
|
+
return { kind: 'staged', confirmed: confirmedOf(record, previous) };
|
|
44
53
|
return verdict.rule === 'model-unavailable'
|
|
45
54
|
? { kind: 'deferred' }
|
|
46
55
|
: { kind: 'refused', refusal: verdict };
|
|
47
56
|
}
|
|
48
|
-
export function applyReturned(confirmed, documents, revisions, removals, roomVersion) {
|
|
57
|
+
export function applyReturned(confirmed, documents, revisions, changes, removals, attachments, roomVersion, writtenAt) {
|
|
49
58
|
const nextDocuments = { ...confirmed.record.documents, ...documents };
|
|
50
59
|
const nextRevisions = { ...confirmed.record.revisions, ...revisions };
|
|
51
60
|
const nextChanges = { ...confirmed.record.changes };
|
|
52
61
|
const nextWritten = {
|
|
53
62
|
...confirmed.record.written,
|
|
54
|
-
...Object.fromEntries(Object.keys(documents).map((path) => [path,
|
|
63
|
+
...Object.fromEntries(Object.keys(documents).map((path) => [path, writtenAt])),
|
|
55
64
|
};
|
|
56
65
|
const binaryTargets = new Set(confirmed.record.binaryTargets);
|
|
57
66
|
for (const [path, revision] of Object.entries(revisions)) {
|
|
58
67
|
if (confirmed.record.revisions[path] !== revision)
|
|
59
68
|
delete nextChanges[path];
|
|
60
69
|
}
|
|
70
|
+
Object.assign(nextChanges, changes);
|
|
61
71
|
for (const path of removals) {
|
|
62
72
|
delete nextDocuments[path];
|
|
63
73
|
delete nextRevisions[path];
|
|
@@ -73,6 +83,9 @@ export function applyReturned(confirmed, documents, revisions, removals, roomVer
|
|
|
73
83
|
changes: nextChanges,
|
|
74
84
|
written: nextWritten,
|
|
75
85
|
binaryTargets: [...binaryTargets].sort(),
|
|
86
|
+
attachments: attachments === undefined
|
|
87
|
+
? confirmed.record.attachments
|
|
88
|
+
: declaredAttachments([attachments]),
|
|
76
89
|
}, confirmed);
|
|
77
90
|
}
|
|
78
91
|
function predicted(confirmed, batches, previous) {
|
|
@@ -93,9 +106,7 @@ function predicted(confirmed, batches, previous) {
|
|
|
93
106
|
const collection = hasMove
|
|
94
107
|
? reuseRewrite
|
|
95
108
|
? old.collection
|
|
96
|
-
:
|
|
97
|
-
? { text: confirmed.record.documents, collection: confirmed.collection }
|
|
98
|
-
: { text: old.before.documents, collection: old.collection })
|
|
109
|
+
: collectionOf(before.documents, composition, old?.collection ?? confirmed.collection)
|
|
99
110
|
: undefined;
|
|
100
111
|
const effective = collection === undefined
|
|
101
112
|
? batch
|
|
@@ -116,7 +127,7 @@ function predicted(confirmed, batches, previous) {
|
|
|
116
127
|
}
|
|
117
128
|
return { layer, replay };
|
|
118
129
|
}
|
|
119
|
-
export function replicaOf(confirmed, queue,
|
|
130
|
+
export function replicaOf(confirmed, queue, previous) {
|
|
120
131
|
const batches = Object.freeze(queue.map(immutable));
|
|
121
132
|
if (batches.length === 0) {
|
|
122
133
|
return {
|
|
@@ -132,21 +143,14 @@ export function replicaOf(confirmed, queue, rewriting, previous) {
|
|
|
132
143
|
replay: [],
|
|
133
144
|
};
|
|
134
145
|
}
|
|
135
|
-
const
|
|
136
|
-
const layer = rewriting === 'provider'
|
|
137
|
-
? predictedState.layer
|
|
138
|
-
: previous === undefined
|
|
139
|
-
? overlay(confirmed.record, batches)
|
|
140
|
-
: overlayChanged(confirmed.record, batches, previous.confirmed.record, previous.queue, previous.visible);
|
|
146
|
+
const { layer, replay } = predicted(confirmed, batches, previous);
|
|
141
147
|
return {
|
|
142
148
|
confirmed,
|
|
143
149
|
queue: batches,
|
|
144
|
-
replay
|
|
150
|
+
replay,
|
|
145
151
|
visible: {
|
|
146
152
|
...layer,
|
|
147
|
-
collection:
|
|
148
|
-
? undefined
|
|
149
|
-
: { text: previous.visible.documents, collection: previous.visible.collection }),
|
|
153
|
+
collection: collectionOf(layer.documents, compositionOf(confirmed.record), previous?.visible.collection ?? confirmed.collection),
|
|
150
154
|
},
|
|
151
155
|
};
|
|
152
156
|
}
|
|
@@ -172,6 +176,8 @@ function holds(layer, preconditions) {
|
|
|
172
176
|
if (precondition.kind === 'revision') {
|
|
173
177
|
return present(layer, path) && layer.revisions[path] === precondition.revision;
|
|
174
178
|
}
|
|
179
|
+
if (precondition.kind === 'content')
|
|
180
|
+
return layer.documents[path] === precondition.content;
|
|
175
181
|
const document = documentAt(path);
|
|
176
182
|
if (document === null)
|
|
177
183
|
return false;
|
|
@@ -230,8 +236,8 @@ function after(changes, index, path) {
|
|
|
230
236
|
}
|
|
231
237
|
return at;
|
|
232
238
|
}
|
|
233
|
-
export function landed(batch, confirmed) {
|
|
234
|
-
const layer = confirmed.record;
|
|
239
|
+
export function landed(batch, confirmed, current = {}) {
|
|
240
|
+
const layer = { ...confirmed.record, documents: { ...confirmed.record.documents, ...current } };
|
|
235
241
|
return batch.changes.every((change, index) => {
|
|
236
242
|
if (change.kind === 'replace' || (change.kind === 'create' && 'content' in change)) {
|
|
237
243
|
const at = after(batch.changes, index, change.path);
|
|
@@ -245,7 +251,7 @@ export function landed(batch, confirmed) {
|
|
|
245
251
|
});
|
|
246
252
|
});
|
|
247
253
|
}
|
|
248
|
-
export function withdrawals(confirmed, queue, withdrawable,
|
|
254
|
+
export function withdrawals(confirmed, queue, withdrawable, local) {
|
|
249
255
|
if (!queue.some(withdrawable))
|
|
250
256
|
return [];
|
|
251
257
|
const composition = compositionOf(confirmed.record);
|
|
@@ -256,13 +262,21 @@ export function withdrawals(confirmed, queue, withdrawable, rewriting) {
|
|
|
256
262
|
withdrawn.push(batch);
|
|
257
263
|
continue;
|
|
258
264
|
}
|
|
259
|
-
const effective =
|
|
265
|
+
const effective = batch.changes.some((change) => change.kind === 'move')
|
|
260
266
|
? providerRewritten(batch, {
|
|
261
267
|
...layer,
|
|
262
|
-
collection:
|
|
268
|
+
collection: collectionOf(layer.documents, composition),
|
|
263
269
|
})
|
|
264
270
|
: batch;
|
|
265
|
-
|
|
271
|
+
let unapplied = false;
|
|
272
|
+
const next = overlay(layer, [effective], () => {
|
|
273
|
+
unapplied = true;
|
|
274
|
+
});
|
|
275
|
+
if (local && unapplied) {
|
|
276
|
+
withdrawn.push(batch);
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
layer = next;
|
|
266
280
|
}
|
|
267
281
|
return withdrawn;
|
|
268
282
|
}
|