@agentshouse/mdruntime-adapter 0.1.0-cc1bdabaf4e28 → 0.1.0-cc34762b70bb0
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/dist/actions.d.ts +4 -59
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +7 -289
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +134 -327
- package/dist/discovery.d.ts +19 -6
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +63 -30
- package/dist/history.d.ts +12 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +92 -0
- package/dist/house-model.d.ts +718 -1
- package/dist/house-model.d.ts.map +1 -1
- package/dist/house-model.js +393 -442
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/model.d.ts +2 -3
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +0 -17
- package/dist/part.d.ts +11 -12
- package/dist/part.d.ts.map +1 -1
- package/dist/part.js +63 -55
- package/dist/read.d.ts +10 -58
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +37 -220
- package/dist/refusal.d.ts +0 -3
- package/dist/refusal.d.ts.map +1 -1
- package/dist/refusal.js +0 -5
- package/dist/room-stream.d.ts +19 -0
- package/dist/room-stream.d.ts.map +1 -0
- package/dist/room-stream.js +57 -0
- package/dist/room-types.d.ts +3 -3
- package/dist/room-types.d.ts.map +1 -1
- package/dist/room-types.js +8 -7
- package/dist/search.d.ts +5 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +47 -0
- package/dist/site.d.ts.map +1 -1
- package/dist/site.js +75 -158
- package/dist/stream.d.ts +13 -14
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +163 -425
- package/dist/transport.d.ts +48 -35
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +54 -11
- package/dist/upload.d.ts.map +1 -1
- package/dist/upload.js +2 -2
- package/dist/write.d.ts +6 -1
- package/dist/write.d.ts.map +1 -1
- package/dist/write.js +17 -24
- package/package.json +2 -2
- package/dist/gather.d.ts +0 -4
- package/dist/gather.d.ts.map +0 -1
- package/dist/gather.js +0 -35
package/dist/adapter.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { stepped } from '@agentshouse/mdruntime';
|
|
2
|
-
import {
|
|
3
|
-
import { manifestedModels, partModels, streamedModels, viewModels } from './model.js';
|
|
4
|
-
import { gathered, gatheredEach, selections } from './gather.js';
|
|
2
|
+
import { capabilities, discoveredRoom, mapDiscovery, parseAuthorityChange, parseDiscovery, trackedFrom, } from './discovery.js';
|
|
5
3
|
import { createSiteAdapter } from './site.js';
|
|
6
|
-
import { authorityRoot, bootstrapping,
|
|
7
|
-
import {
|
|
4
|
+
import { authorityRoot, bootstrapping, parseFileAddress, parseGrant, } from './read.js';
|
|
5
|
+
import { roomStreams } from './room-stream.js';
|
|
8
6
|
import { sha256Hex } from './digest.js';
|
|
9
7
|
import { finishedUpload, houseUpload } from './upload.js';
|
|
10
8
|
import { houseAction } from './actions.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
9
|
+
import { houseSearch } from './search.js';
|
|
10
|
+
import { classifyDoor, doorRefusal } from './refusal.js';
|
|
11
|
+
import { houseNotifications, } from './stream.js';
|
|
12
|
+
import { houseDoorRoute, } from './transport.js';
|
|
14
13
|
import { batchPaths, deltaBody, deltaBytes, deltaDigest, historyOutcome, houseChanges, houseMove, mutationOutcome, operationHead, rejectedMapping, revisionBody, uploadable, } from './write.js';
|
|
14
|
+
import { HOUSE_TYPED_PATHS } from './house-model.js';
|
|
15
15
|
import { HOUSE_NAMEABLE_ROOM_TYPES, HOUSE_ROOM_TYPES } from './room-types.js';
|
|
16
|
-
import { followsVersion, logPosition, presented, reachedVersion, roomVersion
|
|
16
|
+
import { followsVersion, logPosition, presented, reachedVersion, roomVersion } from './version.js';
|
|
17
17
|
const UNCERTAIN = { kind: 'transport-uncertainty' };
|
|
18
18
|
const UNCERTAIN_READ = { kind: 'transport-uncertainty' };
|
|
19
|
+
const OCTET_STREAM = 'application/octet-stream';
|
|
19
20
|
const EXPIRED_ADDRESS = 403;
|
|
20
21
|
function lapsedGrant(outcome) {
|
|
21
22
|
return outcome.kind === 'rejected' && outcome.code === 'upload_unavailable';
|
|
@@ -50,161 +51,85 @@ export function createAgentsHouseAdapter(options) {
|
|
|
50
51
|
if ('site' in options)
|
|
51
52
|
return createSiteAdapter(options.site, options.snapshot === true);
|
|
52
53
|
const transport = options.transport;
|
|
53
|
-
const notifications = houseNotifications(transport, 'credential'
|
|
54
|
+
const notifications = houseNotifications(transport, 'credential', {
|
|
55
|
+
opened: async (frame) => (frame === null ? null : opened(frame)),
|
|
56
|
+
changed,
|
|
57
|
+
});
|
|
54
58
|
const tracked = new Map();
|
|
55
|
-
const
|
|
56
|
-
|
|
59
|
+
const rooms = roomStreams('credential');
|
|
60
|
+
const unreused = new Set();
|
|
57
61
|
let bounds;
|
|
58
62
|
function declared() {
|
|
59
63
|
if (bounds === undefined)
|
|
60
64
|
throw new Error('no Discovery declared the bounds');
|
|
61
65
|
return bounds;
|
|
62
66
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const failure = classifyRead(answered.status, answered.body, entry.locator);
|
|
77
|
-
if (failure !== null)
|
|
78
|
-
return failure;
|
|
79
|
-
const frame = partFrame(answered.body);
|
|
80
|
-
if (frame === null)
|
|
81
|
-
continue;
|
|
82
|
-
const scope = await housePart(continued.room, frame, listed, 'credential');
|
|
83
|
-
if (scope !== null)
|
|
84
|
-
return 'kind' in scope ? scope : { scope, frame };
|
|
85
|
-
}
|
|
86
|
-
return unverifiedPart(entry.locator);
|
|
67
|
+
function opened(frame) {
|
|
68
|
+
const document = parseDiscovery(frame);
|
|
69
|
+
if (document === null)
|
|
70
|
+
return null;
|
|
71
|
+
bounds = document.bounds;
|
|
72
|
+
tracked.clear();
|
|
73
|
+
for (const entry of trackedFrom(document))
|
|
74
|
+
tracked.set(entry.locator, entry);
|
|
75
|
+
notifications.track([...tracked.values()]);
|
|
76
|
+
return {
|
|
77
|
+
...mapDiscovery(document, document.authorities.map((authority) => discoveredRoom(authority)), capabilities(document.actions)),
|
|
78
|
+
member: document.member,
|
|
79
|
+
};
|
|
87
80
|
}
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
81
|
+
function changed(frame) {
|
|
82
|
+
const change = parseAuthorityChange(frame);
|
|
83
|
+
if (change === null)
|
|
84
|
+
return null;
|
|
85
|
+
for (const locator of change.left)
|
|
86
|
+
tracked.delete(locator);
|
|
87
|
+
for (const entry of trackedFrom(change))
|
|
88
|
+
tracked.set(entry.locator, entry);
|
|
89
|
+
notifications.track([...tracked.values()]);
|
|
90
|
+
return {
|
|
91
|
+
kind: 'authority-changed',
|
|
92
|
+
rooms: change.authorities.map((authority) => discoveredRoom(authority)),
|
|
93
|
+
left: change.left,
|
|
94
|
+
member: change.member,
|
|
95
|
+
};
|
|
96
96
|
}
|
|
97
|
-
async function
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
: await fetchedPart(entry, continued, listed, received, arriving);
|
|
103
|
-
if ('kind' in sent)
|
|
104
|
-
return sent;
|
|
105
|
-
const scope = await reused(sent.scope, asked.held);
|
|
97
|
+
async function streamedPage(entry, token, held) {
|
|
98
|
+
const part = await rooms.part(entry, token);
|
|
99
|
+
if ('kind' in part)
|
|
100
|
+
return part;
|
|
101
|
+
const scope = await reused(part.scope, held);
|
|
106
102
|
if (scope === null) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
: bootstrapTogether({ entry, held: undefined });
|
|
103
|
+
unreused.add(entry.locator);
|
|
104
|
+
return UNCERTAIN_READ;
|
|
110
105
|
}
|
|
111
|
-
const next = continued.next + 1;
|
|
112
|
-
const more = next < continued.room.parts.length;
|
|
113
|
-
if (continued.next === 0 && !more)
|
|
114
|
-
handed.set(entry.locator, roomVersion(scope));
|
|
115
|
-
else
|
|
116
|
-
handed.delete(entry.locator);
|
|
117
|
-
notifications.reach(entry.authority, scope);
|
|
118
|
-
const seen = [
|
|
119
|
-
...continued.seen,
|
|
120
|
-
...(scope.files.some((file) => file.path === entry.schema) ? [entry.schema] : []),
|
|
121
|
-
];
|
|
122
|
-
const models = await partModels(scope, entry, new Set(seen), !more);
|
|
123
106
|
return {
|
|
124
107
|
...(await stepped(bootstrapping(scope))),
|
|
125
|
-
...(models === undefined ? {} : { models }),
|
|
126
|
-
...(
|
|
127
|
-
|
|
108
|
+
...(part.models === undefined ? {} : { models: part.models }),
|
|
109
|
+
...(part.pageToken === undefined ? {} : { pageToken: part.pageToken }),
|
|
110
|
+
bytes: part.bytes,
|
|
128
111
|
};
|
|
129
112
|
}
|
|
130
|
-
async function
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
],
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const enumeration = parseEnumeration(answer.body, 'credential');
|
|
144
|
-
if (enumeration === null)
|
|
145
|
-
return UNCERTAIN_READ;
|
|
146
|
-
return (viewOf(enumeration, ask.entry) ?? { kind: 'room-not-readable', locator: ask.entry.locator });
|
|
147
|
-
}
|
|
148
|
-
async function enumeratedRoom(enumeration, ask) {
|
|
149
|
-
const first = viewOf(enumeration, ask.entry);
|
|
150
|
-
if (first === undefined)
|
|
151
|
-
return { kind: 'room-not-readable', locator: ask.entry.locator };
|
|
152
|
-
const view = await wholeView(first, (page) => enumeratedPage(ask, page));
|
|
153
|
-
if ('kind' in view)
|
|
154
|
-
return view;
|
|
155
|
-
notifications.reach(ask.entry.authority, view);
|
|
156
|
-
const answer = await refreshFrom(view, ask.fromRoomVersion);
|
|
157
|
-
if (answer.kind !== 'net-advancement')
|
|
158
|
-
return answer;
|
|
159
|
-
handed.set(ask.entry.locator, roomVersion(view));
|
|
160
|
-
const models = await viewModels(view, ask.entry);
|
|
161
|
-
return models === undefined ? answer : { ...answer, models };
|
|
162
|
-
}
|
|
163
|
-
async function streamed(entry, request, from) {
|
|
164
|
-
if (handed.get(entry.locator) !== request.fromRoomVersion)
|
|
165
|
-
return null;
|
|
166
|
-
const asked = notifications.edited(entry, from);
|
|
167
|
-
const kept = asked.length === 0 || heldRevisions === undefined
|
|
168
|
-
? new Map()
|
|
169
|
-
: await heldRevisions(entry.locator, asked);
|
|
170
|
-
const advanced = await stepped(notifications.advance(entry, from, (path, revision) => kept.get(path) === revision));
|
|
171
|
-
if (advanced === null)
|
|
172
|
-
return null;
|
|
173
|
-
handed.set(entry.locator, advanced.page.roomVersion);
|
|
174
|
-
const models = await streamedModels(advanced.schemas, entry, 'credential');
|
|
175
|
-
return models === undefined ? advanced.page : { ...advanced.page, models };
|
|
113
|
+
async function openedRoom(entry, request) {
|
|
114
|
+
const reusing = unreused.delete(entry.locator) ? undefined : request.held;
|
|
115
|
+
const files = reusing === undefined
|
|
116
|
+
? null
|
|
117
|
+
: await heldFiles(entry.authority, reusing, declared().max_held_files);
|
|
118
|
+
const answered = await transport.streamed(houseDoorRoute('bootstrap'), {
|
|
119
|
+
room_ref: entry.authority,
|
|
120
|
+
prefixes: [authorityRoot(entry.handle)],
|
|
121
|
+
...(files === null ? {} : { held: [files] }),
|
|
122
|
+
}, request.signal ?? new AbortController().signal);
|
|
123
|
+
if (answered.room === null)
|
|
124
|
+
return classifyDoor(answered.status, answered.body, entry.locator) ?? UNCERTAIN_READ;
|
|
125
|
+
return rooms.head(entry, answered.room, request.arriving, request.signal);
|
|
176
126
|
}
|
|
177
127
|
function held(rooms) {
|
|
178
|
-
|
|
128
|
+
notifications.send(rooms.flatMap((room) => {
|
|
179
129
|
const entry = tracked.get(room.locator);
|
|
180
130
|
const at = logPosition(room.roomVersion);
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
handed.set(room.locator, room.roomVersion);
|
|
184
|
-
notifications.reach(entry.authority, at);
|
|
185
|
-
return [presented(entry.authority, at)];
|
|
186
|
-
});
|
|
187
|
-
notifications.send(kept);
|
|
188
|
-
}
|
|
189
|
-
async function adoptedMove(entry, into, outcome) {
|
|
190
|
-
if (outcome.kind === 'accepted' && outcome.destination !== undefined) {
|
|
191
|
-
await adopted(into, { kind: 'accepted', ...outcome.destination });
|
|
192
|
-
}
|
|
193
|
-
return adopted(entry, outcome);
|
|
194
|
-
}
|
|
195
|
-
async function adopted(entry, outcome) {
|
|
196
|
-
if (outcome.kind !== 'accepted')
|
|
197
|
-
return outcome;
|
|
198
|
-
const held = handed.get(entry.locator);
|
|
199
|
-
if (held === undefined)
|
|
200
|
-
return outcome;
|
|
201
|
-
const follows = followsVersion(held, outcome.roomVersion);
|
|
202
|
-
if (follows)
|
|
203
|
-
handed.set(entry.locator, outcome.roomVersion);
|
|
204
|
-
const at = logPosition(outcome.roomVersion);
|
|
205
|
-
if (follows && at !== null)
|
|
206
|
-
notifications.reach(entry.authority, at);
|
|
207
|
-
return outcome;
|
|
131
|
+
return entry === undefined || at === null ? [] : [presented(entry.authority, at)];
|
|
132
|
+
}));
|
|
208
133
|
}
|
|
209
134
|
function authorityFor(locator) {
|
|
210
135
|
return tracked.get(locator);
|
|
@@ -223,116 +148,18 @@ export function createAgentsHouseAdapter(options) {
|
|
|
223
148
|
return result;
|
|
224
149
|
return { ...result, at: { locator, roomVersion: roomVersion({ position, logEpoch }) } };
|
|
225
150
|
}
|
|
226
|
-
async function holding(asks) {
|
|
227
|
-
const bound = Math.floor(declared().max_held_files / Math.max(1, asks.filter((ask) => ask.held !== undefined).length));
|
|
228
|
-
const held = [];
|
|
229
|
-
for (const ask of asks) {
|
|
230
|
-
if (ask.held === undefined || bound === 0)
|
|
231
|
-
continue;
|
|
232
|
-
const files = await heldFiles(ask.entry.authority, ask.held, bound);
|
|
233
|
-
if (files !== null)
|
|
234
|
-
held.push(files);
|
|
235
|
-
}
|
|
236
|
-
return held;
|
|
237
|
-
}
|
|
238
|
-
async function bootstrapped(asks, answer) {
|
|
239
|
-
let open = asks.map((asked, ask) => ({ entry: asked.entry, asked, ask }));
|
|
240
|
-
while (open.length > 0) {
|
|
241
|
-
const unreached = [];
|
|
242
|
-
for (const part of selections(open, declared().max_prefixes)) {
|
|
243
|
-
const held = await holding(part.map(({ asked }) => asked));
|
|
244
|
-
const answered = await transport.door(DOOR_BOOTSTRAP, {
|
|
245
|
-
prefixes: part.map(({ entry }) => authorityRoot(entry.handle)),
|
|
246
|
-
...(held.length === 0 ? {} : { held }),
|
|
247
|
-
});
|
|
248
|
-
const classified = part.map(({ entry }) => classifyDoor(answered.status, answered.body, entry.locator));
|
|
249
|
-
const parted = classified[0] === null ? parseParted(answered.body) : null;
|
|
250
|
-
for (const [index, asked] of part.entries()) {
|
|
251
|
-
const failure = classified[index];
|
|
252
|
-
if (failure !== null && failure !== undefined) {
|
|
253
|
-
answer(asked.ask, failure);
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
if (parted === null) {
|
|
257
|
-
answer(asked.ask, UNCERTAIN_READ);
|
|
258
|
-
continue;
|
|
259
|
-
}
|
|
260
|
-
const room = parted.rooms.find((candidate) => candidate.anchor === asked.entry.authority);
|
|
261
|
-
if (room === undefined && parted.next !== undefined) {
|
|
262
|
-
unreached.push(asked);
|
|
263
|
-
continue;
|
|
264
|
-
}
|
|
265
|
-
if (room === undefined) {
|
|
266
|
-
answer(asked.ask, { kind: 'room-not-readable', locator: asked.entry.locator });
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
const kept = held.find((files) => files.room === asked.entry.authority);
|
|
270
|
-
answer(asked.ask, await manifestPage(asked.asked, {
|
|
271
|
-
room,
|
|
272
|
-
next: 0,
|
|
273
|
-
seen: [],
|
|
274
|
-
...(kept === undefined ? {} : { held: kept }),
|
|
275
|
-
}));
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
open = unreached;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
function layered(asks) {
|
|
282
|
-
const depths = new Map();
|
|
283
|
-
const layers = [];
|
|
284
|
-
for (const ask of asks) {
|
|
285
|
-
const depth = depths.get(ask.ask.entry.authority) ?? 0;
|
|
286
|
-
depths.set(ask.ask.entry.authority, depth + 1);
|
|
287
|
-
(layers[depth] ??= []).push(ask);
|
|
288
|
-
}
|
|
289
|
-
return layers;
|
|
290
|
-
}
|
|
291
|
-
async function enumerated(asks) {
|
|
292
|
-
const answers = [];
|
|
293
|
-
const parts = layered(asks.map((ask, index) => ({ ask, index }))).flatMap((layer) => selections(layer, declared().max_prefixes));
|
|
294
|
-
for (const part of parts) {
|
|
295
|
-
let open = [...part];
|
|
296
|
-
while (open.length > 0) {
|
|
297
|
-
const answer = await transport.door(DOOR_ENUMERATE, {
|
|
298
|
-
prefixes: open.map(({ ask }) => authorityRoot(ask.entry.handle)),
|
|
299
|
-
positions: open.map(({ ask }) => presented(ask.entry.authority, ask.from)),
|
|
300
|
-
});
|
|
301
|
-
const classified = open.map(({ ask }) => classifyRead(answer.status, answer.body, ask.entry.locator));
|
|
302
|
-
if (classified[0]?.kind === 'beyond-horizon') {
|
|
303
|
-
const named = doorRefusal(answer.body)?.fields.authority;
|
|
304
|
-
const expired = open.filter(({ ask }) => ask.entry.authority === named);
|
|
305
|
-
const answered = expired.length === 0 ? UNCERTAIN_READ : { kind: 'beyond-horizon' };
|
|
306
|
-
const gone = expired.length === 0 ? open : expired;
|
|
307
|
-
for (const ask of gone)
|
|
308
|
-
answers[ask.index] = answered;
|
|
309
|
-
open = open.filter((ask) => !gone.includes(ask));
|
|
310
|
-
continue;
|
|
311
|
-
}
|
|
312
|
-
const enumeration = classified[0] === null ? parseEnumeration(answer.body, 'credential') : null;
|
|
313
|
-
for (const [answerIndex, { ask, index }] of open.entries()) {
|
|
314
|
-
const failure = classified[answerIndex];
|
|
315
|
-
if (failure !== null && failure !== undefined) {
|
|
316
|
-
answers[index] = failure;
|
|
317
|
-
continue;
|
|
318
|
-
}
|
|
319
|
-
answers[index] =
|
|
320
|
-
enumeration === null ? UNCERTAIN_READ : await enumeratedRoom(enumeration, ask);
|
|
321
|
-
}
|
|
322
|
-
open = [];
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
return answers;
|
|
326
|
-
}
|
|
327
|
-
const bootstrapTogether = gatheredEach(bootstrapped);
|
|
328
|
-
const enumerateTogether = gathered(enumerated);
|
|
329
151
|
async function uploaded(head, changes, delta, bytes, entry, handed, keep) {
|
|
330
152
|
const paths = batchPaths(changes);
|
|
331
153
|
const sha256 = await deltaDigest(delta);
|
|
332
154
|
if (handed !== undefined && handed.sha256 === sha256) {
|
|
333
155
|
return { body: { ...head, paths, upload: handed, runtime: notifications.runtime } };
|
|
334
156
|
}
|
|
335
|
-
const minted = await transport.door(
|
|
157
|
+
const minted = await transport.door(houseDoorRoute('batch-upload'), {
|
|
158
|
+
...head,
|
|
159
|
+
paths,
|
|
160
|
+
bytes,
|
|
161
|
+
sha256,
|
|
162
|
+
});
|
|
336
163
|
if (minted.status !== 200) {
|
|
337
164
|
return {
|
|
338
165
|
outcome: await stepped(mutationOutcome(minted.status, minted.body, entry.locator, entry.handle)),
|
|
@@ -380,11 +207,11 @@ export function createAgentsHouseAdapter(options) {
|
|
|
380
207
|
: { body: inline };
|
|
381
208
|
if ('outcome' in prepared)
|
|
382
209
|
return prepared.outcome;
|
|
383
|
-
const answer = await transport.door(
|
|
210
|
+
const answer = await transport.door(houseDoorRoute('batch'), prepared.body);
|
|
384
211
|
const stagedFiles = await staged(answer, request);
|
|
385
212
|
if (stagedFiles === false)
|
|
386
213
|
return UNCERTAIN;
|
|
387
|
-
const settled = stagedFiles === null ? answer : await transport.door(
|
|
214
|
+
const settled = stagedFiles === null ? answer : await transport.door(houseDoorRoute('batch'), prepared.body);
|
|
388
215
|
if (stagedFiles === true && (await staged(settled, request)) !== null)
|
|
389
216
|
return UNCERTAIN;
|
|
390
217
|
return stepped(mutationOutcome(settled.status, settled.body, entry.locator, entry.handle, into === undefined
|
|
@@ -412,9 +239,22 @@ export function createAgentsHouseAdapter(options) {
|
|
|
412
239
|
function linked(answer, locator) {
|
|
413
240
|
const address = addressed(answer, locator);
|
|
414
241
|
return address.kind === 'address'
|
|
415
|
-
? { kind: 'link', url: address.url, name: address.name }
|
|
242
|
+
? { kind: 'link', url: address.url, name: address.name, mediaType: address.mediaType }
|
|
416
243
|
: address;
|
|
417
244
|
}
|
|
245
|
+
function refusedAttach(answer, locator) {
|
|
246
|
+
const failure = classifyDoor(answer.status, answer.body, locator);
|
|
247
|
+
if (failure === null)
|
|
248
|
+
return null;
|
|
249
|
+
return failure.kind === 'scoped-refusal'
|
|
250
|
+
? {
|
|
251
|
+
kind: 'rejected',
|
|
252
|
+
code: failure.code,
|
|
253
|
+
fields: failure.fields,
|
|
254
|
+
retryable: failure.retryable,
|
|
255
|
+
}
|
|
256
|
+
: failure;
|
|
257
|
+
}
|
|
418
258
|
async function downloaded(ask, locator) {
|
|
419
259
|
let address = addressed(await ask(), locator);
|
|
420
260
|
if (address.kind !== 'address')
|
|
@@ -439,7 +279,7 @@ export function createAgentsHouseAdapter(options) {
|
|
|
439
279
|
const entry = authorityFor(request.locator);
|
|
440
280
|
if (entry === undefined)
|
|
441
281
|
return null;
|
|
442
|
-
return () => transport.door(
|
|
282
|
+
return () => transport.door(houseDoorRoute('files/get'), {
|
|
443
283
|
room_ref: entry.authority,
|
|
444
284
|
path: request.path,
|
|
445
285
|
revision: request.revision,
|
|
@@ -448,72 +288,17 @@ export function createAgentsHouseAdapter(options) {
|
|
|
448
288
|
return {
|
|
449
289
|
roomTypes: HOUSE_ROOM_TYPES,
|
|
450
290
|
nameableRoomTypes: HOUSE_NAMEABLE_ROOM_TYPES,
|
|
291
|
+
typedPaths: HOUSE_TYPED_PATHS,
|
|
451
292
|
async authorize() {
|
|
452
293
|
return options.authorize();
|
|
453
294
|
},
|
|
454
|
-
async discover(_authorization, scope) {
|
|
455
|
-
const answer = await transport.door(DOOR_DISCOVER, {
|
|
456
|
-
prefixes: [...DISCOVER_PREFIXES],
|
|
457
|
-
...(scope === undefined ? {} : { rooms: scope.authorities }),
|
|
458
|
-
});
|
|
459
|
-
const failed = discoveryFailure(answer.status, answer.body);
|
|
460
|
-
if (failed !== null)
|
|
461
|
-
return failed;
|
|
462
|
-
const document = parseDiscovery(answer.body);
|
|
463
|
-
if (document === null)
|
|
464
|
-
return { kind: 'transport-uncertainty' };
|
|
465
|
-
bounds = document.bounds;
|
|
466
|
-
const entries = trackedFrom(document);
|
|
467
|
-
const covered = scope === undefined
|
|
468
|
-
? null
|
|
469
|
-
: [
|
|
470
|
-
...new Set([
|
|
471
|
-
...[...tracked.values()]
|
|
472
|
-
.filter((entry) => scope.authorities.includes(entry.authority))
|
|
473
|
-
.map((entry) => entry.locator),
|
|
474
|
-
...entries.map((entry) => entry.locator),
|
|
475
|
-
]),
|
|
476
|
-
];
|
|
477
|
-
if (covered === null)
|
|
478
|
-
tracked.clear();
|
|
479
|
-
else
|
|
480
|
-
for (const locator of covered)
|
|
481
|
-
tracked.delete(locator);
|
|
482
|
-
for (const entry of entries)
|
|
483
|
-
tracked.set(entry.locator, entry);
|
|
484
|
-
for (const locator of handed.keys())
|
|
485
|
-
if (!tracked.has(locator))
|
|
486
|
-
handed.delete(locator);
|
|
487
|
-
notifications.track([...tracked.values()]);
|
|
488
|
-
return {
|
|
489
|
-
...mapDiscovery(document, document.authorities.map((authority) => discoveredRoom(authority)), capabilities(document.actions, [...tracked.values()])),
|
|
490
|
-
member: document.member,
|
|
491
|
-
...(covered === null ? {} : { covered }),
|
|
492
|
-
};
|
|
493
|
-
},
|
|
494
295
|
async bootstrap(_authorization, request) {
|
|
495
296
|
const entry = authorityFor(request.locator);
|
|
496
297
|
if (entry === undefined)
|
|
497
298
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
}
|
|
502
|
-
return bootstrapTogether(asked);
|
|
503
|
-
},
|
|
504
|
-
async refresh(_authorization, request) {
|
|
505
|
-
const entry = authorityFor(request.locator);
|
|
506
|
-
if (entry === undefined)
|
|
507
|
-
return { kind: 'room-not-readable', locator: request.locator };
|
|
508
|
-
if (request.pageToken !== undefined)
|
|
509
|
-
return { kind: 'transport-uncertainty' };
|
|
510
|
-
const from = logPosition(request.fromRoomVersion);
|
|
511
|
-
if (from === null)
|
|
512
|
-
return { kind: 'beyond-horizon' };
|
|
513
|
-
const answered = await streamed(entry, request, from);
|
|
514
|
-
if (answered !== null)
|
|
515
|
-
return answered;
|
|
516
|
-
return enumerateTogether({ entry, from, fromRoomVersion: request.fromRoomVersion });
|
|
299
|
+
return request.pageToken === undefined
|
|
300
|
+
? openedRoom(entry, request)
|
|
301
|
+
: streamedPage(entry, request.pageToken, request.held);
|
|
517
302
|
},
|
|
518
303
|
async mutate(_authorization, request, keep) {
|
|
519
304
|
const entry = authorityFor(request.locator);
|
|
@@ -530,22 +315,21 @@ export function createAgentsHouseAdapter(options) {
|
|
|
530
315
|
: houseMove(batch, entry.handle, into.handle);
|
|
531
316
|
if (mapped.kind === 'unmapped')
|
|
532
317
|
return rejectedMapping(mapped);
|
|
533
|
-
const head = operationHead(batch);
|
|
318
|
+
const head = operationHead(batch, entry.authority);
|
|
534
319
|
const delta = deltaBody(mapped.changes);
|
|
535
320
|
const bytes = deltaBytes(delta);
|
|
536
321
|
const handed = request.upload;
|
|
537
322
|
const answer = (upload) => submit(request, head, mapped.changes, delta, bytes, entry, upload, keep, into);
|
|
538
|
-
const settle = (outcome) => into === undefined ? adopted(entry, outcome) : adoptedMove(entry, into, outcome);
|
|
539
323
|
const outcome = await answer(handed);
|
|
540
324
|
if (handed === undefined || !lapsedGrant(outcome))
|
|
541
|
-
return
|
|
542
|
-
return
|
|
325
|
+
return outcome;
|
|
326
|
+
return answer(undefined);
|
|
543
327
|
},
|
|
544
328
|
async history(_authorization, request) {
|
|
545
329
|
const entry = authorityFor(request.locator);
|
|
546
330
|
if (entry === undefined)
|
|
547
331
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
548
|
-
const answer = await transport.door(
|
|
332
|
+
const answer = await transport.door(houseDoorRoute('revisions'), revisionBody({
|
|
549
333
|
path: request.path,
|
|
550
334
|
handle: entry.handle,
|
|
551
335
|
...(request.revision === undefined ? {} : { revision: request.revision }),
|
|
@@ -568,6 +352,35 @@ export function createAgentsHouseAdapter(options) {
|
|
|
568
352
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
569
353
|
return linked(await ask(), request.locator);
|
|
570
354
|
},
|
|
355
|
+
async attach(_authorization, request) {
|
|
356
|
+
const entry = authorityFor(request.locator);
|
|
357
|
+
if (entry === undefined)
|
|
358
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
359
|
+
const declared = await transport.door(houseDoorRoute('files/attach'), {
|
|
360
|
+
room_ref: entry.authority,
|
|
361
|
+
name: request.name,
|
|
362
|
+
bytes: request.byteLength,
|
|
363
|
+
sha256: request.sha256,
|
|
364
|
+
media_type: request.mediaType.length > 0 ? request.mediaType : OCTET_STREAM,
|
|
365
|
+
});
|
|
366
|
+
const refused = refusedAttach(declared, request.locator);
|
|
367
|
+
if (refused !== null)
|
|
368
|
+
return refused;
|
|
369
|
+
const upload = houseUpload(declared.body?.upload);
|
|
370
|
+
if (upload === null)
|
|
371
|
+
return UNCERTAIN_READ;
|
|
372
|
+
const finished = await finishedUpload(transport, upload, request.blob);
|
|
373
|
+
if (finished === null)
|
|
374
|
+
return UNCERTAIN_READ;
|
|
375
|
+
const unfinished = refusedAttach(finished, request.locator);
|
|
376
|
+
if (unfinished !== null)
|
|
377
|
+
return unfinished;
|
|
378
|
+
const { path, revision } = (finished.body ?? {});
|
|
379
|
+
const root = `/rooms/${entry.handle}/`;
|
|
380
|
+
return typeof path === 'string' && path.startsWith(root) && typeof revision === 'string'
|
|
381
|
+
? { kind: 'attached', path: path.slice(root.length), revision }
|
|
382
|
+
: UNCERTAIN_READ;
|
|
383
|
+
},
|
|
571
384
|
reached(locator, version, target) {
|
|
572
385
|
return reachedVersion(version, target, authorityFor(locator)?.logEpoch);
|
|
573
386
|
},
|
|
@@ -577,18 +390,12 @@ export function createAgentsHouseAdapter(options) {
|
|
|
577
390
|
async action(_authorization, request) {
|
|
578
391
|
return withAt(await houseAction(transport, request));
|
|
579
392
|
},
|
|
393
|
+
search(_authorization, request) {
|
|
394
|
+
return houseSearch(transport, [...tracked.values()], request);
|
|
395
|
+
},
|
|
580
396
|
roomStream: {
|
|
581
397
|
hold: held,
|
|
582
|
-
|
|
583
|
-
observe(notify, receipts, revisions) {
|
|
584
|
-
heldRevisions = revisions;
|
|
585
|
-
return notifications.observe(notify, receipts);
|
|
586
|
-
},
|
|
587
|
-
published(locator, roomVersion) {
|
|
588
|
-
const at = logPosition(roomVersion);
|
|
589
|
-
if (at !== null)
|
|
590
|
-
notifications.published(locator, at);
|
|
591
|
-
},
|
|
398
|
+
observe: notifications.observe,
|
|
592
399
|
},
|
|
593
400
|
conversations: notifications.conversations,
|
|
594
401
|
serviceMode: notifications.serviceMode,
|
package/dist/discovery.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { Capability, DiscoveredRoom, Discovery, Member, ProviderLimit, Retention } from '@agentshouse/mdruntime';
|
|
2
2
|
import { type LogPosition } from './version.js';
|
|
3
3
|
export declare const PROVIDER_ACTIONS = "provider-actions";
|
|
4
|
-
export declare const DISCOVER_PREFIXES: readonly string[];
|
|
5
4
|
export type HouseBounds = {
|
|
6
5
|
max_authored_file_bytes: number;
|
|
7
6
|
max_batch_operations: number;
|
|
@@ -15,14 +14,13 @@ export type HouseBounds = {
|
|
|
15
14
|
max_prefixes: number;
|
|
16
15
|
max_held_files: number;
|
|
17
16
|
change_retention_seconds: number;
|
|
18
|
-
operation_retention_seconds: number;
|
|
19
17
|
max_move_documents?: number;
|
|
20
18
|
};
|
|
21
19
|
export type HouseOperations = {
|
|
22
20
|
write: readonly string[];
|
|
23
21
|
delete: readonly string[];
|
|
24
22
|
};
|
|
25
|
-
export type
|
|
23
|
+
export type HouseAccessLevel = 'search' | 'open' | 'keep';
|
|
26
24
|
export type HouseAuthority = LogPosition & {
|
|
27
25
|
roomRef: string;
|
|
28
26
|
roomHandle: string;
|
|
@@ -31,7 +29,7 @@ export type HouseAuthority = LogPosition & {
|
|
|
31
29
|
typedSelection: readonly string[] | null;
|
|
32
30
|
managedReplication: 'admitted' | 'unavailable';
|
|
33
31
|
protectedPaths: readonly string[];
|
|
34
|
-
|
|
32
|
+
level: HouseAccessLevel;
|
|
35
33
|
operations: HouseOperations;
|
|
36
34
|
};
|
|
37
35
|
export type HouseDiscoveryDocument = {
|
|
@@ -40,6 +38,11 @@ export type HouseDiscoveryDocument = {
|
|
|
40
38
|
authorities: readonly HouseAuthority[];
|
|
41
39
|
actions: readonly string[];
|
|
42
40
|
};
|
|
41
|
+
export type HouseAuthorityChange = {
|
|
42
|
+
member: Member;
|
|
43
|
+
authorities: readonly HouseAuthority[];
|
|
44
|
+
left: readonly string[];
|
|
45
|
+
};
|
|
43
46
|
export type TrackedAuthority = LogPosition & {
|
|
44
47
|
locator: string;
|
|
45
48
|
authority: string;
|
|
@@ -56,14 +59,24 @@ export type HouseSiteDiscovery = {
|
|
|
56
59
|
bounds: HouseBounds;
|
|
57
60
|
authorities: readonly HouseSiteAuthority[];
|
|
58
61
|
};
|
|
62
|
+
type RoomOwn = 'room_ref' | 'room_handle' | 'name' | 'position';
|
|
63
|
+
type Folded<A extends Record<RoomOwn, unknown>> = {
|
|
64
|
+
readonly shapes: readonly Omit<A, RoomOwn>[];
|
|
65
|
+
readonly rooms: readonly (Pick<A, RoomOwn> & {
|
|
66
|
+
readonly shape: number;
|
|
67
|
+
})[];
|
|
68
|
+
};
|
|
69
|
+
export declare function foldedAuthorities<A extends Record<RoomOwn, unknown>>(authorities: readonly A[]): Folded<A>;
|
|
59
70
|
export declare function parseDiscovery(body: unknown): HouseDiscoveryDocument | null;
|
|
71
|
+
export declare function parseAuthorityChange(body: unknown): HouseAuthorityChange | null;
|
|
60
72
|
export declare function parseSiteDiscovery(body: unknown): HouseSiteDiscovery | null;
|
|
61
73
|
export declare function siteTracked(document: HouseSiteDiscovery): TrackedAuthority[];
|
|
62
|
-
export declare function trackedFrom(document: HouseDiscoveryDocument): TrackedAuthority[];
|
|
74
|
+
export declare function trackedFrom(document: Pick<HouseDiscoveryDocument, 'authorities'>): TrackedAuthority[];
|
|
63
75
|
export declare function providerLimits(bounds: HouseBounds): readonly ProviderLimit[];
|
|
64
76
|
export declare function declaredRetention(bounds: HouseBounds): Retention;
|
|
65
|
-
export declare function capabilities(actions: HouseDiscoveryDocument['actions']
|
|
77
|
+
export declare function capabilities(actions: HouseDiscoveryDocument['actions']): readonly Capability[];
|
|
66
78
|
export declare function siteCapabilities(): readonly Capability[];
|
|
67
79
|
export declare function discoveredRoom(authority: HouseAuthority): DiscoveredRoom;
|
|
68
80
|
export declare function mapDiscovery(document: Pick<HouseDiscoveryDocument, 'bounds'>, rooms: readonly DiscoveredRoom[], declared: readonly Capability[]): Discovery;
|
|
81
|
+
export {};
|
|
69
82
|
//# sourceMappingURL=discovery.d.ts.map
|