@agentshouse/mdruntime-adapter 0.1.0-ccda1a2da11c3 → 0.1.0-ccdfb41af2abb
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/actions.d.ts +3 -71
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +1 -317
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +171 -336
- package/dist/app-reference.d.ts +2 -0
- package/dist/app-reference.d.ts.map +1 -0
- package/dist/app-reference.js +2 -0
- package/dist/crockford.d.ts +4 -0
- package/dist/crockford.d.ts.map +1 -0
- package/dist/crockford.js +3 -0
- package/dist/discovery.d.ts +12 -12
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +44 -51
- package/dist/history.d.ts +12 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +91 -0
- package/dist/house-model.d.ts +892 -0
- package/dist/house-model.d.ts.map +1 -0
- package/dist/house-model.js +482 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/model.d.ts +5 -2
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +10 -29
- package/dist/part.d.ts +12 -11
- package/dist/part.d.ts.map +1 -1
- package/dist/part.js +66 -56
- package/dist/read.d.ts +19 -56
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +138 -297
- 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 +2 -1
- package/dist/room-types.d.ts.map +1 -1
- package/dist/room-types.js +62 -3
- 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 +79 -177
- package/dist/stream.d.ts +13 -14
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +168 -426
- package/dist/transport.d.ts +48 -38
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +55 -11
- package/dist/upload.d.ts +12 -0
- package/dist/upload.d.ts.map +1 -0
- package/dist/upload.js +63 -0
- package/dist/write.d.ts +6 -1
- package/dist/write.d.ts.map +1 -1
- package/dist/write.js +19 -32
- package/package.json +8 -4
- package/AGENTS.md +0 -309
- package/dist/gather.d.ts +0 -4
- package/dist/gather.d.ts.map +0 -1
- package/dist/gather.js +0 -35
- package/dist/referrer.d.ts +0 -9
- package/dist/referrer.d.ts.map +0 -1
- package/dist/referrer.js +0 -41
package/dist/adapter.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { stepped } from '@agentshouse/mdruntime';
|
|
2
|
-
import {
|
|
3
|
-
import { 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';
|
|
7
|
+
import { finishedUpload, houseUpload } from './upload.js';
|
|
9
8
|
import { houseAction } from './actions.js';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
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';
|
|
13
13
|
import { batchPaths, deltaBody, deltaBytes, deltaDigest, historyOutcome, houseChanges, houseMove, mutationOutcome, operationHead, rejectedMapping, revisionBody, uploadable, } from './write.js';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { followsVersion, logPosition, presented, reachedVersion, roomVersion, } from './version.js';
|
|
14
|
+
import { HOUSE_NAMEABLE_ROOM_TYPES, HOUSE_ROOM_TYPES } from './room-types.js';
|
|
15
|
+
import { followsVersion, logPosition, presented, reachedVersion, roomVersion } from './version.js';
|
|
17
16
|
const UNCERTAIN = { kind: 'transport-uncertainty' };
|
|
18
17
|
const UNCERTAIN_READ = { kind: 'transport-uncertainty' };
|
|
18
|
+
const OCTET_STREAM = 'application/octet-stream';
|
|
19
19
|
const EXPIRED_ADDRESS = 403;
|
|
20
20
|
function lapsedGrant(outcome) {
|
|
21
21
|
return outcome.kind === 'rejected' && outcome.code === 'upload_unavailable';
|
|
@@ -29,7 +29,7 @@ async function heldFiles(authority, held, bound) {
|
|
|
29
29
|
async function reused(scope, held) {
|
|
30
30
|
const sent = new Set(scope.contents.map((entry) => entry.path));
|
|
31
31
|
const contents = [...scope.contents];
|
|
32
|
-
const asked = scope.files.filter((file) => file.binary === undefined && !sent.has(file.path));
|
|
32
|
+
const asked = scope.files.filter((file) => file.binary === undefined && file.outline === undefined && !sent.has(file.path));
|
|
33
33
|
if (asked.length === 0)
|
|
34
34
|
return scope;
|
|
35
35
|
if (held === undefined)
|
|
@@ -50,142 +50,108 @@ export function createAgentsHouseAdapter(options) {
|
|
|
50
50
|
if ('site' in options)
|
|
51
51
|
return createSiteAdapter(options.site, options.snapshot === true);
|
|
52
52
|
const transport = options.transport;
|
|
53
|
-
const notifications = houseNotifications(transport, 'credential'
|
|
53
|
+
const notifications = houseNotifications(transport, 'credential', {
|
|
54
|
+
opened: async (frame) => (frame === null ? null : opened(frame)),
|
|
55
|
+
changed,
|
|
56
|
+
});
|
|
54
57
|
const tracked = new Map();
|
|
55
|
-
const
|
|
56
|
-
|
|
58
|
+
const rooms = roomStreams('credential');
|
|
59
|
+
const unreused = new Set();
|
|
57
60
|
let bounds;
|
|
58
61
|
function declared() {
|
|
59
62
|
if (bounds === undefined)
|
|
60
63
|
throw new Error('no Discovery declared the bounds');
|
|
61
64
|
return bounds;
|
|
62
65
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
return unverifiedPart(entry.locator);
|
|
66
|
+
function opened(frame) {
|
|
67
|
+
const document = parseDiscovery(frame);
|
|
68
|
+
if (document === null)
|
|
69
|
+
return null;
|
|
70
|
+
bounds = document.bounds;
|
|
71
|
+
tracked.clear();
|
|
72
|
+
for (const entry of trackedFrom(document))
|
|
73
|
+
tracked.set(entry.locator, entry);
|
|
74
|
+
notifications.track([...tracked.values()]);
|
|
75
|
+
return {
|
|
76
|
+
...mapDiscovery(document, document.authorities.map((authority) => discoveredRoom(authority)), capabilities(document.actions)),
|
|
77
|
+
member: document.member,
|
|
78
|
+
};
|
|
78
79
|
}
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
80
|
+
function changed(frame) {
|
|
81
|
+
const change = parseAuthorityChange(frame);
|
|
82
|
+
if (change === null)
|
|
83
|
+
return null;
|
|
84
|
+
for (const locator of change.left)
|
|
85
|
+
tracked.delete(locator);
|
|
86
|
+
for (const entry of trackedFrom(change))
|
|
87
|
+
tracked.set(entry.locator, entry);
|
|
88
|
+
notifications.track([...tracked.values()]);
|
|
89
|
+
return {
|
|
90
|
+
kind: 'authority-changed',
|
|
91
|
+
rooms: change.authorities.map((authority) => discoveredRoom(authority)),
|
|
92
|
+
left: change.left,
|
|
93
|
+
member: change.member,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async function streamedPage(entry, token, held) {
|
|
97
|
+
const part = await rooms.part(entry, token);
|
|
98
|
+
if ('kind' in part)
|
|
99
|
+
return part;
|
|
100
|
+
const scope = await reused(part.scope, held);
|
|
88
101
|
if (scope === null) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
: bootstrapTogether({ entry, held: undefined });
|
|
102
|
+
unreused.add(entry.locator);
|
|
103
|
+
return UNCERTAIN_READ;
|
|
92
104
|
}
|
|
93
|
-
const next = continued.next + 1;
|
|
94
|
-
const more = next < continued.room.parts.length;
|
|
95
|
-
if (continued.next === 0 && !more)
|
|
96
|
-
handed.set(entry.locator, roomVersion(scope));
|
|
97
|
-
else
|
|
98
|
-
handed.delete(entry.locator);
|
|
99
|
-
notifications.reach(entry.authority, scope);
|
|
100
|
-
const seen = [
|
|
101
|
-
...continued.seen,
|
|
102
|
-
...entry.schemas.filter((schema) => scope.files.some((file) => file.path === schema)),
|
|
103
|
-
];
|
|
104
|
-
const models = await partModels(scope, entry, new Set(seen), !more);
|
|
105
105
|
return {
|
|
106
106
|
...(await stepped(bootstrapping(scope))),
|
|
107
|
-
...(models === undefined ? {} : { models }),
|
|
108
|
-
...(
|
|
107
|
+
...(part.models === undefined ? {} : { models: part.models }),
|
|
108
|
+
...(part.pageToken === undefined ? {} : { pageToken: part.pageToken }),
|
|
109
|
+
bytes: part.bytes,
|
|
109
110
|
};
|
|
110
111
|
}
|
|
111
|
-
async function
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
112
|
+
async function namedDocument(entry, path, signal) {
|
|
113
|
+
const answered = await transport.streamed(houseDoorRoute('bootstrap'), { room_ref: entry.authority, prefixes: [`${authorityRoot(entry.handle)}/${path}`] }, signal ?? new AbortController().signal);
|
|
114
|
+
if (answered.room === null)
|
|
115
|
+
return classifyDoor(answered.status, answered.body, entry.locator) ?? UNCERTAIN_READ;
|
|
116
|
+
const opened = await rooms.head(entry, answered.room, undefined, signal);
|
|
117
|
+
if (opened.kind !== 'bootstrap')
|
|
118
|
+
return opened;
|
|
119
|
+
const files = [];
|
|
120
|
+
const contents = [];
|
|
121
|
+
let last = null;
|
|
122
|
+
for (let token = opened.pageToken; token !== undefined;) {
|
|
123
|
+
const part = await rooms.part(entry, token);
|
|
124
|
+
if ('kind' in part)
|
|
125
|
+
return part;
|
|
126
|
+
files.push(...part.scope.files);
|
|
127
|
+
contents.push(...part.scope.contents);
|
|
128
|
+
last = part.scope;
|
|
129
|
+
token = part.pageToken;
|
|
130
|
+
}
|
|
131
|
+
if (last === null)
|
|
126
132
|
return UNCERTAIN_READ;
|
|
127
|
-
return (
|
|
133
|
+
return stepped(bootstrapping({ ...last, files, contents }));
|
|
128
134
|
}
|
|
129
|
-
async function
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return models === undefined ? answer : { ...answer, models };
|
|
143
|
-
}
|
|
144
|
-
async function streamed(entry, request, from) {
|
|
145
|
-
if (handed.get(entry.locator) !== request.fromRoomVersion)
|
|
146
|
-
return null;
|
|
147
|
-
const asked = notifications.edited(entry, from);
|
|
148
|
-
const kept = asked.length === 0 || heldRevisions === undefined
|
|
149
|
-
? new Map()
|
|
150
|
-
: await heldRevisions(entry.locator, asked);
|
|
151
|
-
const advanced = await stepped(notifications.advance(entry, from, (path, revision) => kept.get(path) === revision));
|
|
152
|
-
if (advanced === null)
|
|
153
|
-
return null;
|
|
154
|
-
handed.set(entry.locator, advanced.page.roomVersion);
|
|
155
|
-
const models = await streamedModels(advanced.schemas, entry, 'credential');
|
|
156
|
-
return models === undefined ? advanced.page : { ...advanced.page, models };
|
|
135
|
+
async function openedRoom(entry, request) {
|
|
136
|
+
const reusing = unreused.delete(entry.locator) ? undefined : request.held;
|
|
137
|
+
const files = reusing === undefined
|
|
138
|
+
? null
|
|
139
|
+
: await heldFiles(entry.authority, reusing, declared().max_held_files);
|
|
140
|
+
const answered = await transport.streamed(houseDoorRoute('bootstrap'), {
|
|
141
|
+
room_ref: entry.authority,
|
|
142
|
+
prefixes: [authorityRoot(entry.handle)],
|
|
143
|
+
...(files === null ? {} : { held: [files] }),
|
|
144
|
+
}, request.signal ?? new AbortController().signal);
|
|
145
|
+
if (answered.room === null)
|
|
146
|
+
return classifyDoor(answered.status, answered.body, entry.locator) ?? UNCERTAIN_READ;
|
|
147
|
+
return rooms.head(entry, answered.room, request.arriving, request.signal);
|
|
157
148
|
}
|
|
158
149
|
function held(rooms) {
|
|
159
|
-
|
|
150
|
+
notifications.send(rooms.flatMap((room) => {
|
|
160
151
|
const entry = tracked.get(room.locator);
|
|
161
152
|
const at = logPosition(room.roomVersion);
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
handed.set(room.locator, room.roomVersion);
|
|
165
|
-
notifications.reach(entry.authority, at);
|
|
166
|
-
return [presented(entry.authority, at)];
|
|
167
|
-
});
|
|
168
|
-
notifications.send(kept);
|
|
169
|
-
}
|
|
170
|
-
async function adoptedMove(entry, into, outcome) {
|
|
171
|
-
if (outcome.kind === 'accepted' && outcome.destination !== undefined) {
|
|
172
|
-
await adopted(into, { kind: 'accepted', ...outcome.destination });
|
|
173
|
-
}
|
|
174
|
-
return adopted(entry, outcome);
|
|
175
|
-
}
|
|
176
|
-
async function adopted(entry, outcome) {
|
|
177
|
-
if (outcome.kind !== 'accepted')
|
|
178
|
-
return outcome;
|
|
179
|
-
const held = handed.get(entry.locator);
|
|
180
|
-
if (held === undefined)
|
|
181
|
-
return outcome;
|
|
182
|
-
const follows = followsVersion(held, outcome.roomVersion);
|
|
183
|
-
if (follows)
|
|
184
|
-
handed.set(entry.locator, outcome.roomVersion);
|
|
185
|
-
const at = logPosition(outcome.roomVersion);
|
|
186
|
-
if (follows && at !== null)
|
|
187
|
-
notifications.reach(entry.authority, at);
|
|
188
|
-
return outcome;
|
|
153
|
+
return entry === undefined || at === null ? [] : [presented(entry.authority, at)];
|
|
154
|
+
}));
|
|
189
155
|
}
|
|
190
156
|
function authorityFor(locator) {
|
|
191
157
|
return tracked.get(locator);
|
|
@@ -204,116 +170,18 @@ export function createAgentsHouseAdapter(options) {
|
|
|
204
170
|
return result;
|
|
205
171
|
return { ...result, at: { locator, roomVersion: roomVersion({ position, logEpoch }) } };
|
|
206
172
|
}
|
|
207
|
-
async function holding(asks) {
|
|
208
|
-
const bound = Math.floor(declared().max_held_files / Math.max(1, asks.filter((ask) => ask.held !== undefined).length));
|
|
209
|
-
const held = [];
|
|
210
|
-
for (const ask of asks) {
|
|
211
|
-
if (ask.held === undefined || bound === 0)
|
|
212
|
-
continue;
|
|
213
|
-
const files = await heldFiles(ask.entry.authority, ask.held, bound);
|
|
214
|
-
if (files !== null)
|
|
215
|
-
held.push(files);
|
|
216
|
-
}
|
|
217
|
-
return held;
|
|
218
|
-
}
|
|
219
|
-
async function bootstrapped(asks, answer) {
|
|
220
|
-
let open = asks.map((asked, ask) => ({ entry: asked.entry, asked, ask }));
|
|
221
|
-
while (open.length > 0) {
|
|
222
|
-
const unreached = [];
|
|
223
|
-
for (const part of selections(open, declared().max_prefixes)) {
|
|
224
|
-
const held = await holding(part.map(({ asked }) => asked));
|
|
225
|
-
const answered = await transport.door(DOOR_BOOTSTRAP, {
|
|
226
|
-
prefixes: part.map(({ entry }) => authorityRoot(entry.handle)),
|
|
227
|
-
...(held.length === 0 ? {} : { held }),
|
|
228
|
-
});
|
|
229
|
-
const classified = part.map(({ entry }) => classifyDoor(answered.status, answered.body, entry.locator));
|
|
230
|
-
const parted = classified[0] === null ? parseParted(answered.body) : null;
|
|
231
|
-
for (const [index, asked] of part.entries()) {
|
|
232
|
-
const failure = classified[index];
|
|
233
|
-
if (failure !== null && failure !== undefined) {
|
|
234
|
-
answer(asked.ask, failure);
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
if (parted === null) {
|
|
238
|
-
answer(asked.ask, UNCERTAIN_READ);
|
|
239
|
-
continue;
|
|
240
|
-
}
|
|
241
|
-
const room = parted.rooms.find((candidate) => candidate.anchor === asked.entry.authority);
|
|
242
|
-
if (room === undefined && parted.next !== undefined) {
|
|
243
|
-
unreached.push(asked);
|
|
244
|
-
continue;
|
|
245
|
-
}
|
|
246
|
-
if (room === undefined) {
|
|
247
|
-
answer(asked.ask, { kind: 'room-not-readable', locator: asked.entry.locator });
|
|
248
|
-
continue;
|
|
249
|
-
}
|
|
250
|
-
const kept = held.find((files) => files.room === asked.entry.authority);
|
|
251
|
-
answer(asked.ask, await partPage(asked.asked, {
|
|
252
|
-
room,
|
|
253
|
-
next: 0,
|
|
254
|
-
seen: [],
|
|
255
|
-
...(kept === undefined ? {} : { held: kept }),
|
|
256
|
-
}));
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
open = unreached;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
function layered(asks) {
|
|
263
|
-
const depths = new Map();
|
|
264
|
-
const layers = [];
|
|
265
|
-
for (const ask of asks) {
|
|
266
|
-
const depth = depths.get(ask.ask.entry.authority) ?? 0;
|
|
267
|
-
depths.set(ask.ask.entry.authority, depth + 1);
|
|
268
|
-
(layers[depth] ??= []).push(ask);
|
|
269
|
-
}
|
|
270
|
-
return layers;
|
|
271
|
-
}
|
|
272
|
-
async function enumerated(asks) {
|
|
273
|
-
const answers = [];
|
|
274
|
-
const parts = layered(asks.map((ask, index) => ({ ask, index }))).flatMap((layer) => selections(layer, declared().max_prefixes));
|
|
275
|
-
for (const part of parts) {
|
|
276
|
-
let open = [...part];
|
|
277
|
-
while (open.length > 0) {
|
|
278
|
-
const answer = await transport.door(DOOR_ENUMERATE, {
|
|
279
|
-
prefixes: open.map(({ ask }) => authorityRoot(ask.entry.handle)),
|
|
280
|
-
positions: open.map(({ ask }) => presented(ask.entry.authority, ask.from)),
|
|
281
|
-
});
|
|
282
|
-
const classified = open.map(({ ask }) => classifyRead(answer.status, answer.body, ask.entry.locator));
|
|
283
|
-
if (classified[0]?.kind === 'beyond-horizon') {
|
|
284
|
-
const named = doorRefusal(answer.body)?.fields.authority;
|
|
285
|
-
const expired = open.filter(({ ask }) => ask.entry.authority === named);
|
|
286
|
-
const answered = expired.length === 0 ? UNCERTAIN_READ : { kind: 'beyond-horizon' };
|
|
287
|
-
const gone = expired.length === 0 ? open : expired;
|
|
288
|
-
for (const ask of gone)
|
|
289
|
-
answers[ask.index] = answered;
|
|
290
|
-
open = open.filter((ask) => !gone.includes(ask));
|
|
291
|
-
continue;
|
|
292
|
-
}
|
|
293
|
-
const enumeration = classified[0] === null ? parseEnumeration(answer.body, 'credential') : null;
|
|
294
|
-
for (const [answerIndex, { ask, index }] of open.entries()) {
|
|
295
|
-
const failure = classified[answerIndex];
|
|
296
|
-
if (failure !== null && failure !== undefined) {
|
|
297
|
-
answers[index] = failure;
|
|
298
|
-
continue;
|
|
299
|
-
}
|
|
300
|
-
answers[index] =
|
|
301
|
-
enumeration === null ? UNCERTAIN_READ : await enumeratedRoom(enumeration, ask);
|
|
302
|
-
}
|
|
303
|
-
open = [];
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
return answers;
|
|
307
|
-
}
|
|
308
|
-
const bootstrapTogether = gatheredEach(bootstrapped);
|
|
309
|
-
const enumerateTogether = gathered(enumerated);
|
|
310
173
|
async function uploaded(head, changes, delta, bytes, entry, handed, keep) {
|
|
311
174
|
const paths = batchPaths(changes);
|
|
312
175
|
const sha256 = await deltaDigest(delta);
|
|
313
176
|
if (handed !== undefined && handed.sha256 === sha256) {
|
|
314
177
|
return { body: { ...head, paths, upload: handed, runtime: notifications.runtime } };
|
|
315
178
|
}
|
|
316
|
-
const minted = await transport.door(
|
|
179
|
+
const minted = await transport.door(houseDoorRoute('batch-upload'), {
|
|
180
|
+
...head,
|
|
181
|
+
paths,
|
|
182
|
+
bytes,
|
|
183
|
+
sha256,
|
|
184
|
+
});
|
|
317
185
|
if (minted.status !== 200) {
|
|
318
186
|
return {
|
|
319
187
|
outcome: await stepped(mutationOutcome(minted.status, minted.body, entry.locator, entry.handle)),
|
|
@@ -340,21 +208,16 @@ export function createAgentsHouseAdapter(options) {
|
|
|
340
208
|
const refusal = doorRefusal(answer.body);
|
|
341
209
|
if (refusal?.code !== 'files_unstaged')
|
|
342
210
|
return null;
|
|
343
|
-
const
|
|
344
|
-
if (!Array.isArray(
|
|
211
|
+
const uploads = refusal.fields.upload;
|
|
212
|
+
if (!Array.isArray(uploads))
|
|
345
213
|
return false;
|
|
346
|
-
for (const
|
|
347
|
-
const
|
|
348
|
-
const change = batch.changes.find((held) => held.kind === 'binary' && held.sha256 === sha256);
|
|
349
|
-
if (
|
|
214
|
+
for (const named of uploads) {
|
|
215
|
+
const upload = houseUpload(named);
|
|
216
|
+
const change = batch.changes.find((held) => held.kind === 'binary' && held.sha256 === named.sha256);
|
|
217
|
+
if (upload === null || change === undefined)
|
|
350
218
|
return false;
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
url,
|
|
354
|
-
body: await file(change.localId),
|
|
355
|
-
operation,
|
|
356
|
-
});
|
|
357
|
-
if (delivered.status !== 200)
|
|
219
|
+
const finished = await finishedUpload(transport, upload, await file(change.localId));
|
|
220
|
+
if (finished?.body?.staged !== true)
|
|
358
221
|
return false;
|
|
359
222
|
}
|
|
360
223
|
return true;
|
|
@@ -366,11 +229,11 @@ export function createAgentsHouseAdapter(options) {
|
|
|
366
229
|
: { body: inline };
|
|
367
230
|
if ('outcome' in prepared)
|
|
368
231
|
return prepared.outcome;
|
|
369
|
-
const answer = await transport.door(
|
|
232
|
+
const answer = await transport.door(houseDoorRoute('batch'), prepared.body);
|
|
370
233
|
const stagedFiles = await staged(answer, request);
|
|
371
234
|
if (stagedFiles === false)
|
|
372
235
|
return UNCERTAIN;
|
|
373
|
-
const settled = stagedFiles === null ? answer : await transport.door(
|
|
236
|
+
const settled = stagedFiles === null ? answer : await transport.door(houseDoorRoute('batch'), prepared.body);
|
|
374
237
|
if (stagedFiles === true && (await staged(settled, request)) !== null)
|
|
375
238
|
return UNCERTAIN;
|
|
376
239
|
return stepped(mutationOutcome(settled.status, settled.body, entry.locator, entry.handle, into === undefined
|
|
@@ -398,9 +261,22 @@ export function createAgentsHouseAdapter(options) {
|
|
|
398
261
|
function linked(answer, locator) {
|
|
399
262
|
const address = addressed(answer, locator);
|
|
400
263
|
return address.kind === 'address'
|
|
401
|
-
? { kind: 'link', url: address.url, name: address.name }
|
|
264
|
+
? { kind: 'link', url: address.url, name: address.name, mediaType: address.mediaType }
|
|
402
265
|
: address;
|
|
403
266
|
}
|
|
267
|
+
function refusedAttach(answer, locator) {
|
|
268
|
+
const failure = classifyDoor(answer.status, answer.body, locator);
|
|
269
|
+
if (failure === null)
|
|
270
|
+
return null;
|
|
271
|
+
return failure.kind === 'scoped-refusal'
|
|
272
|
+
? {
|
|
273
|
+
kind: 'rejected',
|
|
274
|
+
code: failure.code,
|
|
275
|
+
fields: failure.fields,
|
|
276
|
+
retryable: failure.retryable,
|
|
277
|
+
}
|
|
278
|
+
: failure;
|
|
279
|
+
}
|
|
404
280
|
async function downloaded(ask, locator) {
|
|
405
281
|
let address = addressed(await ask(), locator);
|
|
406
282
|
if (address.kind !== 'address')
|
|
@@ -425,7 +301,7 @@ export function createAgentsHouseAdapter(options) {
|
|
|
425
301
|
const entry = authorityFor(request.locator);
|
|
426
302
|
if (entry === undefined)
|
|
427
303
|
return null;
|
|
428
|
-
return () => transport.door(
|
|
304
|
+
return () => transport.door(houseDoorRoute('files/get'), {
|
|
429
305
|
room_ref: entry.authority,
|
|
430
306
|
path: request.path,
|
|
431
307
|
revision: request.revision,
|
|
@@ -433,72 +309,19 @@ export function createAgentsHouseAdapter(options) {
|
|
|
433
309
|
}
|
|
434
310
|
return {
|
|
435
311
|
roomTypes: HOUSE_ROOM_TYPES,
|
|
312
|
+
nameableRoomTypes: HOUSE_NAMEABLE_ROOM_TYPES,
|
|
436
313
|
async authorize() {
|
|
437
314
|
return options.authorize();
|
|
438
315
|
},
|
|
439
|
-
async discover(_authorization, scope) {
|
|
440
|
-
const answer = await transport.door(DOOR_DISCOVER, {
|
|
441
|
-
prefixes: [...DISCOVER_PREFIXES],
|
|
442
|
-
...(scope === undefined ? {} : { rooms: scope.authorities }),
|
|
443
|
-
});
|
|
444
|
-
const failed = discoveryFailure(answer.status, answer.body);
|
|
445
|
-
if (failed !== null)
|
|
446
|
-
return failed;
|
|
447
|
-
const document = parseDiscovery(answer.body);
|
|
448
|
-
if (document === null)
|
|
449
|
-
return { kind: 'transport-uncertainty' };
|
|
450
|
-
bounds = document.bounds;
|
|
451
|
-
const entries = trackedFrom(document);
|
|
452
|
-
const covered = scope === undefined
|
|
453
|
-
? null
|
|
454
|
-
: [
|
|
455
|
-
...new Set([
|
|
456
|
-
...[...tracked.values()]
|
|
457
|
-
.filter((entry) => scope.authorities.includes(entry.authority))
|
|
458
|
-
.map((entry) => entry.locator),
|
|
459
|
-
...entries.map((entry) => entry.locator),
|
|
460
|
-
]),
|
|
461
|
-
];
|
|
462
|
-
if (covered === null)
|
|
463
|
-
tracked.clear();
|
|
464
|
-
else
|
|
465
|
-
for (const locator of covered)
|
|
466
|
-
tracked.delete(locator);
|
|
467
|
-
for (const entry of entries)
|
|
468
|
-
tracked.set(entry.locator, entry);
|
|
469
|
-
for (const locator of handed.keys())
|
|
470
|
-
if (!tracked.has(locator))
|
|
471
|
-
handed.delete(locator);
|
|
472
|
-
notifications.track([...tracked.values()]);
|
|
473
|
-
return {
|
|
474
|
-
...mapDiscovery(document, document.authorities.map((authority) => discoveredRoom(authority)), capabilities(document.actions, [...tracked.values()])),
|
|
475
|
-
member: document.member,
|
|
476
|
-
...(covered === null ? {} : { covered }),
|
|
477
|
-
};
|
|
478
|
-
},
|
|
479
316
|
async bootstrap(_authorization, request) {
|
|
480
317
|
const entry = authorityFor(request.locator);
|
|
481
318
|
if (entry === undefined)
|
|
482
319
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
},
|
|
489
|
-
async refresh(_authorization, request) {
|
|
490
|
-
const entry = authorityFor(request.locator);
|
|
491
|
-
if (entry === undefined)
|
|
492
|
-
return { kind: 'room-not-readable', locator: request.locator };
|
|
493
|
-
if (request.pageToken !== undefined)
|
|
494
|
-
return { kind: 'transport-uncertainty' };
|
|
495
|
-
const from = logPosition(request.fromRoomVersion);
|
|
496
|
-
if (from === null)
|
|
497
|
-
return { kind: 'beyond-horizon' };
|
|
498
|
-
const answered = await streamed(entry, request, from);
|
|
499
|
-
if (answered !== null)
|
|
500
|
-
return answered;
|
|
501
|
-
return enumerateTogether({ entry, from, fromRoomVersion: request.fromRoomVersion });
|
|
320
|
+
if (request.path !== undefined)
|
|
321
|
+
return namedDocument(entry, request.path, request.signal);
|
|
322
|
+
return request.pageToken === undefined
|
|
323
|
+
? openedRoom(entry, request)
|
|
324
|
+
: streamedPage(entry, request.pageToken, request.held);
|
|
502
325
|
},
|
|
503
326
|
async mutate(_authorization, request, keep) {
|
|
504
327
|
const entry = authorityFor(request.locator);
|
|
@@ -515,22 +338,21 @@ export function createAgentsHouseAdapter(options) {
|
|
|
515
338
|
: houseMove(batch, entry.handle, into.handle);
|
|
516
339
|
if (mapped.kind === 'unmapped')
|
|
517
340
|
return rejectedMapping(mapped);
|
|
518
|
-
const head = operationHead(batch);
|
|
341
|
+
const head = operationHead(batch, entry.authority);
|
|
519
342
|
const delta = deltaBody(mapped.changes);
|
|
520
343
|
const bytes = deltaBytes(delta);
|
|
521
344
|
const handed = request.upload;
|
|
522
345
|
const answer = (upload) => submit(request, head, mapped.changes, delta, bytes, entry, upload, keep, into);
|
|
523
|
-
const settle = (outcome) => into === undefined ? adopted(entry, outcome) : adoptedMove(entry, into, outcome);
|
|
524
346
|
const outcome = await answer(handed);
|
|
525
347
|
if (handed === undefined || !lapsedGrant(outcome))
|
|
526
|
-
return
|
|
527
|
-
return
|
|
348
|
+
return outcome;
|
|
349
|
+
return answer(undefined);
|
|
528
350
|
},
|
|
529
351
|
async history(_authorization, request) {
|
|
530
352
|
const entry = authorityFor(request.locator);
|
|
531
353
|
if (entry === undefined)
|
|
532
354
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
533
|
-
const answer = await transport.door(
|
|
355
|
+
const answer = await transport.door(houseDoorRoute('revisions'), revisionBody({
|
|
534
356
|
path: request.path,
|
|
535
357
|
handle: entry.handle,
|
|
536
358
|
...(request.revision === undefined ? {} : { revision: request.revision }),
|
|
@@ -542,17 +364,10 @@ export function createAgentsHouseAdapter(options) {
|
|
|
542
364
|
});
|
|
543
365
|
},
|
|
544
366
|
async binary(_authorization, request) {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
return downloaded(ask, request.locator);
|
|
550
|
-
}
|
|
551
|
-
const referrer = houseReferrer(request.referrer, tracked);
|
|
552
|
-
if (referrer === null) {
|
|
553
|
-
return { kind: 'rejected', code: 'referrer_unknown', fields: {}, retryable: false };
|
|
554
|
-
}
|
|
555
|
-
return downloaded(() => transport.door(DOOR_FILES_GET, { file: request.fileRef, referrer: referrer.referrer }), referrer.locator);
|
|
367
|
+
const ask = pathAddress(request);
|
|
368
|
+
if (ask === null)
|
|
369
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
370
|
+
return downloaded(ask, request.locator);
|
|
556
371
|
},
|
|
557
372
|
async link(_authorization, request) {
|
|
558
373
|
const ask = pathAddress(request);
|
|
@@ -560,8 +375,34 @@ export function createAgentsHouseAdapter(options) {
|
|
|
560
375
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
561
376
|
return linked(await ask(), request.locator);
|
|
562
377
|
},
|
|
563
|
-
|
|
564
|
-
|
|
378
|
+
async attach(_authorization, request) {
|
|
379
|
+
const entry = authorityFor(request.locator);
|
|
380
|
+
if (entry === undefined)
|
|
381
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
382
|
+
const declared = await transport.door(houseDoorRoute('files/attach'), {
|
|
383
|
+
room_ref: entry.authority,
|
|
384
|
+
name: request.name,
|
|
385
|
+
bytes: request.byteLength,
|
|
386
|
+
sha256: request.sha256,
|
|
387
|
+
media_type: request.mediaType.length > 0 ? request.mediaType : OCTET_STREAM,
|
|
388
|
+
});
|
|
389
|
+
const refused = refusedAttach(declared, request.locator);
|
|
390
|
+
if (refused !== null)
|
|
391
|
+
return refused;
|
|
392
|
+
const upload = houseUpload(declared.body?.upload);
|
|
393
|
+
if (upload === null)
|
|
394
|
+
return UNCERTAIN_READ;
|
|
395
|
+
const finished = await finishedUpload(transport, upload, request.blob);
|
|
396
|
+
if (finished === null)
|
|
397
|
+
return UNCERTAIN_READ;
|
|
398
|
+
const unfinished = refusedAttach(finished, request.locator);
|
|
399
|
+
if (unfinished !== null)
|
|
400
|
+
return unfinished;
|
|
401
|
+
const { path, revision } = (finished.body ?? {});
|
|
402
|
+
const root = `/rooms/${entry.handle}/`;
|
|
403
|
+
return typeof path === 'string' && path.startsWith(root) && typeof revision === 'string'
|
|
404
|
+
? { kind: 'attached', path: path.slice(root.length), revision }
|
|
405
|
+
: UNCERTAIN_READ;
|
|
565
406
|
},
|
|
566
407
|
reached(locator, version, target) {
|
|
567
408
|
return reachedVersion(version, target, authorityFor(locator)?.logEpoch);
|
|
@@ -572,18 +413,12 @@ export function createAgentsHouseAdapter(options) {
|
|
|
572
413
|
async action(_authorization, request) {
|
|
573
414
|
return withAt(await houseAction(transport, request));
|
|
574
415
|
},
|
|
416
|
+
search(_authorization, request) {
|
|
417
|
+
return houseSearch(transport, [...tracked.values()], request);
|
|
418
|
+
},
|
|
575
419
|
roomStream: {
|
|
576
420
|
hold: held,
|
|
577
|
-
|
|
578
|
-
observe(notify, receipts, revisions) {
|
|
579
|
-
heldRevisions = revisions;
|
|
580
|
-
return notifications.observe(notify, receipts);
|
|
581
|
-
},
|
|
582
|
-
published(locator, roomVersion) {
|
|
583
|
-
const at = logPosition(roomVersion);
|
|
584
|
-
if (at !== null)
|
|
585
|
-
notifications.published(locator, at);
|
|
586
|
-
},
|
|
421
|
+
observe: notifications.observe,
|
|
587
422
|
},
|
|
588
423
|
conversations: notifications.conversations,
|
|
589
424
|
serviceMode: notifications.serviceMode,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-reference.d.ts","sourceRoot":"","sources":["../src/app-reference.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,qBAAqB,QAEjC,CAAC"}
|