@agentshouse/mdruntime-adapter 0.1.0-cf22c8563f9f4 → 0.1.0-cf599f631976d
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 +6 -5
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +25 -322
- package/dist/adapter.d.ts +1 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +278 -206
- 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/chunks.d.ts +38 -0
- package/dist/chunks.d.ts.map +1 -0
- package/dist/chunks.js +247 -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 +25 -15
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +104 -52
- 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 +682 -0
- package/dist/house-model.d.ts.map +1 -0
- package/dist/house-model.js +396 -0
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/model.d.ts +5 -4
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +40 -33
- package/dist/read.d.ts +63 -42
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +179 -262
- package/dist/refusal.d.ts +3 -8
- package/dist/refusal.d.ts.map +1 -1
- package/dist/refusal.js +10 -14
- package/dist/room-types.d.ts +5 -0
- package/dist/room-types.d.ts.map +1 -0
- package/dist/room-types.js +120 -0
- 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 +1 -1
- package/dist/site.d.ts.map +1 -1
- package/dist/site.js +120 -105
- package/dist/space-schema.d.ts +7 -0
- package/dist/space-schema.d.ts.map +1 -0
- package/dist/space-schema.js +18 -0
- package/dist/stream.d.ts +15 -12
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +275 -147
- package/dist/transport.d.ts +90 -24
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +55 -9
- package/dist/upload.d.ts +12 -0
- package/dist/upload.d.ts.map +1 -0
- package/dist/upload.js +63 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/write.d.ts +20 -10
- package/dist/write.d.ts.map +1 -1
- package/dist/write.js +165 -59
- package/package.json +9 -6
- package/AGENTS.md +0 -244
- package/dist/gather.d.ts +0 -3
- package/dist/gather.d.ts.map +0 -1
- package/dist/gather.js +0 -40
- package/dist/links.d.ts +0 -20
- package/dist/links.d.ts.map +0 -1
- package/dist/links.js +0 -104
package/dist/adapter.js
CHANGED
|
@@ -1,96 +1,123 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { gathered, selections } from './gather.js';
|
|
1
|
+
import { stepped } from '@agentshouse/mdruntime';
|
|
2
|
+
import { capabilities, discoveredRoom, mapDiscovery, parseAuthorityChange, parseDiscovery, trackedFrom, } from './discovery.js';
|
|
4
3
|
import { createSiteAdapter } from './site.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
4
|
+
import { parseFileAddress, parseGrant } from './read.js';
|
|
5
|
+
import { chunkedHead, chunkLister, chunkPart } from './chunks.js';
|
|
6
|
+
import { spaceSchemas } from './space-schema.js';
|
|
7
|
+
import { finishedUpload, houseUpload } from './upload.js';
|
|
8
|
+
import { houseAction, HOUSE_LEADING_READS, HOUSE_UNKEPT_READS } from './actions.js';
|
|
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
|
+
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
|
+
import { HOUSE_NAMEABLE_ROOM_TYPES, HOUSE_ROOM_TYPES } from './room-types.js';
|
|
16
|
+
import { followsVersion, reachedVersion, roomVersion } from './version.js';
|
|
13
17
|
const UNCERTAIN = { kind: 'transport-uncertainty' };
|
|
14
18
|
const UNCERTAIN_READ = { kind: 'transport-uncertainty' };
|
|
19
|
+
const OCTET_STREAM = 'application/octet-stream';
|
|
20
|
+
const EXPIRED_ADDRESS = 403;
|
|
15
21
|
function lapsedGrant(outcome) {
|
|
16
22
|
return outcome.kind === 'rejected' && outcome.code === 'upload_unavailable';
|
|
17
23
|
}
|
|
18
24
|
export function createAgentsHouseAdapter(options) {
|
|
19
25
|
if ('site' in options)
|
|
20
|
-
return createSiteAdapter(options.site);
|
|
26
|
+
return createSiteAdapter(options.site, options.snapshot === true);
|
|
21
27
|
const transport = options.transport;
|
|
22
|
-
const
|
|
28
|
+
const spaces = spaceSchemas();
|
|
29
|
+
const notifications = houseNotifications(transport, 'credential', {
|
|
30
|
+
opened: async (frame) => (frame === null ? null : opened(frame)),
|
|
31
|
+
changed,
|
|
32
|
+
expired: (authorities) => lister.askAll(authorities.flatMap((authority) => [...tracked.values()].filter((entry) => entry.authority === authority))),
|
|
33
|
+
}, spaces);
|
|
23
34
|
const tracked = new Map();
|
|
24
|
-
const
|
|
35
|
+
const lister = chunkLister(transport, () => declared().max_prefixes);
|
|
36
|
+
const chunked = new Map();
|
|
37
|
+
const renewals = new WeakMap();
|
|
25
38
|
let bounds;
|
|
26
39
|
function declared() {
|
|
27
40
|
if (bounds === undefined)
|
|
28
41
|
throw new Error('no Discovery declared the bounds');
|
|
29
42
|
return bounds;
|
|
30
43
|
}
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
if (
|
|
34
|
-
return
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const answer = refreshFrom(view, ask.fromRoomVersion);
|
|
46
|
-
if (answer.kind !== 'net-advancement')
|
|
47
|
-
return answer;
|
|
48
|
-
handed.set(ask.entry.locator, enumeratedLinks(view, handed.get(ask.entry.locator)));
|
|
49
|
-
const models = await viewModels(view, ask.entry);
|
|
50
|
-
return models === undefined ? answer : { ...answer, models };
|
|
44
|
+
function opened(frame) {
|
|
45
|
+
const document = parseDiscovery(frame);
|
|
46
|
+
if (document === null)
|
|
47
|
+
return null;
|
|
48
|
+
bounds = document.bounds;
|
|
49
|
+
tracked.clear();
|
|
50
|
+
lister.forget();
|
|
51
|
+
for (const entry of trackedFrom(document))
|
|
52
|
+
tracked.set(entry.locator, entry);
|
|
53
|
+
notifications.track([...tracked.values()]);
|
|
54
|
+
return {
|
|
55
|
+
...mapDiscovery(document, document.authorities.map((authority) => discoveredRoom(authority)), capabilities(document.actions)),
|
|
56
|
+
member: document.member,
|
|
57
|
+
};
|
|
51
58
|
}
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
59
|
+
function changed(frame) {
|
|
60
|
+
const change = parseAuthorityChange(frame);
|
|
61
|
+
if (change === null)
|
|
55
62
|
return null;
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
for (const locator of change.left)
|
|
64
|
+
tracked.delete(locator);
|
|
65
|
+
for (const entry of trackedFrom(change))
|
|
66
|
+
tracked.set(entry.locator, entry);
|
|
67
|
+
notifications.track([...tracked.values()]);
|
|
68
|
+
return {
|
|
69
|
+
kind: 'authority-changed',
|
|
70
|
+
rooms: change.authorities.map((authority) => discoveredRoom(authority)),
|
|
71
|
+
left: change.left,
|
|
72
|
+
member: change.member,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async function listedRoom(entry) {
|
|
76
|
+
const listed = await lister.list(entry);
|
|
77
|
+
if ('kind' in listed)
|
|
78
|
+
return listed;
|
|
79
|
+
const head = await chunkedHead(listed, entry, spaces);
|
|
80
|
+
if (head.kind === 'bootstrap')
|
|
81
|
+
chunked.set(entry.locator, listed);
|
|
82
|
+
return head;
|
|
83
|
+
}
|
|
84
|
+
async function chunkRead(entry, id) {
|
|
85
|
+
const room = chunked.get(entry.locator);
|
|
86
|
+
const address = room?.chunks.get(id);
|
|
87
|
+
if (room === undefined || address === undefined)
|
|
58
88
|
return null;
|
|
59
|
-
const
|
|
60
|
-
if (
|
|
89
|
+
const read = await transport.download(address.url);
|
|
90
|
+
if (read.status !== EXPIRED_ADDRESS)
|
|
91
|
+
return { room, read };
|
|
92
|
+
const renewed = await renewal(entry, room);
|
|
93
|
+
if ('kind' in renewed || !renewed.chunks.has(id))
|
|
61
94
|
return null;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return models === undefined ? advanced.page : { ...advanced.page, models };
|
|
95
|
+
chunked.set(entry.locator, renewed);
|
|
96
|
+
return { room: renewed, read: await transport.download(renewed.chunks.get(id).url) };
|
|
65
97
|
}
|
|
66
|
-
function
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
98
|
+
function renewal(entry, stale) {
|
|
99
|
+
const held = renewals.get(stale);
|
|
100
|
+
if (held !== undefined)
|
|
101
|
+
return held;
|
|
102
|
+
const renewed = lister.renew(entry, [...chunked.keys()].flatMap((locator) => tracked.get(locator) ?? []));
|
|
103
|
+
renewals.set(stale, renewed);
|
|
104
|
+
return renewed;
|
|
105
|
+
}
|
|
106
|
+
function hold(rooms) {
|
|
107
|
+
for (const room of rooms) {
|
|
108
|
+
const listed = chunked.get(room.locator);
|
|
109
|
+
if (listed !== undefined &&
|
|
110
|
+
room.roomVersion !== null &&
|
|
111
|
+
reachedVersion(room.roomVersion, roomVersion(listed), listed.logEpoch))
|
|
112
|
+
chunked.delete(room.locator);
|
|
113
|
+
}
|
|
114
|
+
notifications.send(rooms);
|
|
77
115
|
}
|
|
78
|
-
function
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (links === undefined)
|
|
84
|
-
return accepted;
|
|
85
|
-
const follows = followsVersion(links.roomVersion, accepted.roomVersion);
|
|
86
|
-
const relinked = acceptedLinks(links, accepted, follows ? accepted.roomVersion : links.roomVersion, originals);
|
|
87
|
-
handed.set(entry.locator, relinked.links);
|
|
88
|
-
const at = logPosition(accepted.roomVersion);
|
|
89
|
-
if (follows && at !== null)
|
|
90
|
-
notifications.reach(entry.authority, at);
|
|
91
|
-
return relinked.attachments === undefined
|
|
92
|
-
? accepted
|
|
93
|
-
: { ...accepted, attachments: relinked.attachments };
|
|
116
|
+
async function chunkPage(entry, id, arriving) {
|
|
117
|
+
const fetched = await chunkRead(entry, id);
|
|
118
|
+
if (fetched === null || fetched.read.status !== 200)
|
|
119
|
+
return UNCERTAIN_READ;
|
|
120
|
+
return chunkPart(fetched.read.body, fetched.room, id, arriving);
|
|
94
121
|
}
|
|
95
122
|
function authorityFor(locator) {
|
|
96
123
|
return tracked.get(locator);
|
|
@@ -109,194 +136,192 @@ export function createAgentsHouseAdapter(options) {
|
|
|
109
136
|
return result;
|
|
110
137
|
return { ...result, at: { locator, roomVersion: roomVersion({ position, logEpoch }) } };
|
|
111
138
|
}
|
|
112
|
-
async function bundled(body) {
|
|
113
|
-
const grant = parseGrant(body);
|
|
114
|
-
if (grant === null)
|
|
115
|
-
return body;
|
|
116
|
-
if (grant.method !== 'GET')
|
|
117
|
-
return null;
|
|
118
|
-
const answer = await transport.transfer({
|
|
119
|
-
act: 'local_copy_bundle',
|
|
120
|
-
method: 'GET',
|
|
121
|
-
url: grant.url,
|
|
122
|
-
answer: 'json',
|
|
123
|
-
});
|
|
124
|
-
return answer.status === 200 ? answer.body : null;
|
|
125
|
-
}
|
|
126
|
-
function weight(entry) {
|
|
127
|
-
return contentPrefixes(entry).length;
|
|
128
|
-
}
|
|
129
|
-
async function bootstrapped(entries) {
|
|
130
|
-
const answers = [];
|
|
131
|
-
for (const part of selections(entries, weight, declared().max_prefixes)) {
|
|
132
|
-
const answer = await transport.door(DOOR_BOOTSTRAP, {
|
|
133
|
-
prefixes: part.flatMap((entry) => contentPrefixes(entry)),
|
|
134
|
-
});
|
|
135
|
-
const classified = part.map((entry) => classifyDoor(answer.status, answer.body, entry.locator));
|
|
136
|
-
const envelope = classified[0] === null ? parseEnvelope(await bundled(answer.body)) : null;
|
|
137
|
-
for (const [index, entry] of part.entries()) {
|
|
138
|
-
const failure = classified[index];
|
|
139
|
-
if (failure === null || failure === undefined) {
|
|
140
|
-
answers.push(envelope === null ? UNCERTAIN_READ : await bootstrappedRoom(envelope, entry));
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
answers.push(failure);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return answers;
|
|
147
|
-
}
|
|
148
|
-
function layered(asks) {
|
|
149
|
-
const depths = new Map();
|
|
150
|
-
const layers = [];
|
|
151
|
-
for (const ask of asks) {
|
|
152
|
-
const depth = depths.get(ask.entry.authority) ?? 0;
|
|
153
|
-
depths.set(ask.entry.authority, depth + 1);
|
|
154
|
-
(layers[depth] ??= []).push(ask);
|
|
155
|
-
}
|
|
156
|
-
return layers;
|
|
157
|
-
}
|
|
158
|
-
async function enumerated(asks) {
|
|
159
|
-
const answers = new Map();
|
|
160
|
-
const parts = layered(asks).flatMap((layer) => selections(layer, (ask) => weight(ask.entry), declared().max_prefixes));
|
|
161
|
-
for (const part of parts) {
|
|
162
|
-
let open = [...part];
|
|
163
|
-
while (open.length > 0) {
|
|
164
|
-
const answer = await transport.door(DOOR_ENUMERATE, {
|
|
165
|
-
prefixes: open.flatMap((ask) => contentPrefixes(ask.entry)),
|
|
166
|
-
positions: open.map((ask) => presented(ask.entry.authority, ask.from)),
|
|
167
|
-
});
|
|
168
|
-
const classified = open.map((ask) => classifyRead(answer.status, answer.body, ask.entry.locator));
|
|
169
|
-
if (classified[0]?.kind === 'beyond-horizon') {
|
|
170
|
-
const named = doorRefusal(answer.body)?.fields.authority;
|
|
171
|
-
const expired = open.filter((ask) => ask.entry.authority === named);
|
|
172
|
-
const answered = expired.length === 0 ? UNCERTAIN_READ : { kind: 'beyond-horizon' };
|
|
173
|
-
const gone = expired.length === 0 ? open : expired;
|
|
174
|
-
for (const ask of gone)
|
|
175
|
-
answers.set(ask, answered);
|
|
176
|
-
open = open.filter((ask) => !gone.includes(ask));
|
|
177
|
-
continue;
|
|
178
|
-
}
|
|
179
|
-
const enumeration = classified[0] === null ? parseEnumeration(answer.body, 'credential') : null;
|
|
180
|
-
for (const [index, ask] of open.entries()) {
|
|
181
|
-
const failure = classified[index];
|
|
182
|
-
if (failure !== null && failure !== undefined) {
|
|
183
|
-
answers.set(ask, failure);
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
answers.set(ask, enumeration === null ? UNCERTAIN_READ : await enumeratedRoom(enumeration, ask));
|
|
187
|
-
}
|
|
188
|
-
open = [];
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return asks.map((ask) => answers.get(ask) ?? UNCERTAIN_READ);
|
|
192
|
-
}
|
|
193
|
-
const bootstrapTogether = gathered(bootstrapped);
|
|
194
|
-
const enumerateTogether = gathered(enumerated);
|
|
195
139
|
async function uploaded(head, changes, delta, bytes, entry, handed, keep) {
|
|
196
140
|
const paths = batchPaths(changes);
|
|
197
141
|
const sha256 = await deltaDigest(delta);
|
|
198
142
|
if (handed !== undefined && handed.sha256 === sha256) {
|
|
199
143
|
return { body: { ...head, paths, upload: handed, runtime: notifications.runtime } };
|
|
200
144
|
}
|
|
201
|
-
const minted = await transport.door(
|
|
145
|
+
const minted = await transport.door(houseDoorRoute('files/batch-upload'), {
|
|
146
|
+
...head,
|
|
147
|
+
paths,
|
|
148
|
+
bytes,
|
|
149
|
+
sha256,
|
|
150
|
+
});
|
|
202
151
|
if (minted.status !== 200) {
|
|
203
|
-
return {
|
|
152
|
+
return {
|
|
153
|
+
outcome: await stepped(mutationOutcome(minted.status, minted.body, entry.locator, entry.handle)),
|
|
154
|
+
};
|
|
204
155
|
}
|
|
205
156
|
const grant = parseGrant(minted.body);
|
|
206
|
-
if (grant === null
|
|
157
|
+
if (grant === null)
|
|
207
158
|
return { outcome: UNCERTAIN };
|
|
208
159
|
const delivered = await transport.transfer({
|
|
209
160
|
act: 'authored_batch_upload',
|
|
210
|
-
method: 'POST',
|
|
211
161
|
url: grant.url,
|
|
212
|
-
answer: 'json',
|
|
213
162
|
body: `${grant.operation}\n${delta}`,
|
|
214
163
|
});
|
|
215
164
|
if (delivered.status !== 200)
|
|
216
165
|
return { outcome: UNCERTAIN };
|
|
217
166
|
const holding = parseGrant(delivered.body);
|
|
218
|
-
if (holding === null
|
|
167
|
+
if (holding === null)
|
|
219
168
|
return { outcome: UNCERTAIN };
|
|
220
169
|
const upload = { url: holding.url, operation: holding.operation, bytes, sha256 };
|
|
221
170
|
await keep(upload);
|
|
222
171
|
return { body: { ...head, paths, upload, runtime: notifications.runtime } };
|
|
223
172
|
}
|
|
224
|
-
async function
|
|
173
|
+
async function staged(answer, { changeBatch: batch, file }) {
|
|
174
|
+
const refusal = doorRefusal(answer.body);
|
|
175
|
+
if (refusal?.code !== 'files_unstaged')
|
|
176
|
+
return null;
|
|
177
|
+
const uploads = refusal.fields.upload;
|
|
178
|
+
if (!Array.isArray(uploads))
|
|
179
|
+
return false;
|
|
180
|
+
for (const named of uploads) {
|
|
181
|
+
const upload = houseUpload(named);
|
|
182
|
+
const change = batch.changes.find((held) => held.kind === 'binary' && held.sha256 === named.sha256);
|
|
183
|
+
if (upload === null || change === undefined)
|
|
184
|
+
return false;
|
|
185
|
+
const finished = await finishedUpload(transport, upload, await file(change.localId));
|
|
186
|
+
if (finished?.body?.staged !== true)
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
async function submit(request, head, changes, delta, bytes, entry, handed, keep, into) {
|
|
225
192
|
const inline = { ...head, changes, runtime: notifications.runtime };
|
|
226
193
|
const prepared = uploadable(inline, bytes, declared())
|
|
227
194
|
? await uploaded(head, changes, delta, bytes, entry, handed, keep)
|
|
228
195
|
: { body: inline };
|
|
229
196
|
if ('outcome' in prepared)
|
|
230
197
|
return prepared.outcome;
|
|
231
|
-
const answer = await transport.door(
|
|
232
|
-
|
|
198
|
+
const answer = await transport.door(houseDoorRoute('files/batch'), prepared.body);
|
|
199
|
+
const stagedFiles = await staged(answer, request);
|
|
200
|
+
if (stagedFiles === false)
|
|
201
|
+
return UNCERTAIN;
|
|
202
|
+
const settled = stagedFiles === null
|
|
203
|
+
? answer
|
|
204
|
+
: await transport.door(houseDoorRoute('files/batch'), prepared.body);
|
|
205
|
+
if (stagedFiles === true && (await staged(settled, request)) !== null)
|
|
206
|
+
return UNCERTAIN;
|
|
207
|
+
return stepped(mutationOutcome(settled.status, settled.body, entry.locator, entry.handle, into === undefined
|
|
208
|
+
? undefined
|
|
209
|
+
: {
|
|
210
|
+
source: { authority: entry.authority, handle: entry.handle },
|
|
211
|
+
destination: { authority: into.authority, handle: into.handle },
|
|
212
|
+
}));
|
|
213
|
+
}
|
|
214
|
+
function addressed(answer, locator) {
|
|
215
|
+
const failure = classifyDoor(answer.status, answer.body, locator);
|
|
216
|
+
if (failure !== null) {
|
|
217
|
+
return failure.kind === 'scoped-refusal'
|
|
218
|
+
? {
|
|
219
|
+
kind: 'rejected',
|
|
220
|
+
code: failure.code,
|
|
221
|
+
fields: failure.fields,
|
|
222
|
+
retryable: failure.retryable,
|
|
223
|
+
}
|
|
224
|
+
: failure;
|
|
225
|
+
}
|
|
226
|
+
const address = parseFileAddress(answer.body);
|
|
227
|
+
return address === null ? UNCERTAIN_READ : { kind: 'address', ...address };
|
|
228
|
+
}
|
|
229
|
+
function linked(answer, locator) {
|
|
230
|
+
const address = addressed(answer, locator);
|
|
231
|
+
return address.kind === 'address'
|
|
232
|
+
? { kind: 'link', url: address.url, name: address.name, mediaType: address.mediaType }
|
|
233
|
+
: address;
|
|
234
|
+
}
|
|
235
|
+
function refusedAttach(answer, locator) {
|
|
236
|
+
const failure = classifyDoor(answer.status, answer.body, locator);
|
|
237
|
+
if (failure === null)
|
|
238
|
+
return null;
|
|
239
|
+
return failure.kind === 'scoped-refusal'
|
|
240
|
+
? {
|
|
241
|
+
kind: 'rejected',
|
|
242
|
+
code: failure.code,
|
|
243
|
+
fields: failure.fields,
|
|
244
|
+
retryable: failure.retryable,
|
|
245
|
+
}
|
|
246
|
+
: failure;
|
|
247
|
+
}
|
|
248
|
+
async function downloaded(ask, locator) {
|
|
249
|
+
let address = addressed(await ask(), locator);
|
|
250
|
+
if (address.kind !== 'address')
|
|
251
|
+
return address;
|
|
252
|
+
let read = await transport.download(address.url);
|
|
253
|
+
if (read.status === EXPIRED_ADDRESS) {
|
|
254
|
+
address = addressed(await ask(), locator);
|
|
255
|
+
if (address.kind !== 'address')
|
|
256
|
+
return address;
|
|
257
|
+
read = await transport.download(address.url);
|
|
258
|
+
}
|
|
259
|
+
if (read.status !== 200 || read.body === null)
|
|
260
|
+
return UNCERTAIN_READ;
|
|
261
|
+
return {
|
|
262
|
+
kind: 'binary',
|
|
263
|
+
body: read.body,
|
|
264
|
+
mediaType: address.mediaType,
|
|
265
|
+
sha256: address.sha256,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function pathAddress(request) {
|
|
269
|
+
const entry = authorityFor(request.locator);
|
|
270
|
+
if (entry === undefined)
|
|
271
|
+
return null;
|
|
272
|
+
return () => transport.door(houseDoorRoute('files/read'), {
|
|
273
|
+
room_ref: entry.authority,
|
|
274
|
+
path: request.path,
|
|
275
|
+
revision: request.revision,
|
|
276
|
+
});
|
|
233
277
|
}
|
|
234
278
|
return {
|
|
279
|
+
roomTypes: HOUSE_ROOM_TYPES,
|
|
280
|
+
nameableRoomTypes: HOUSE_NAMEABLE_ROOM_TYPES,
|
|
281
|
+
typedPaths: HOUSE_TYPED_PATHS,
|
|
282
|
+
unkeptReads: HOUSE_UNKEPT_READS,
|
|
283
|
+
leadingReads: HOUSE_LEADING_READS,
|
|
235
284
|
async authorize() {
|
|
236
285
|
return options.authorize();
|
|
237
286
|
},
|
|
238
|
-
async discover(_authorization) {
|
|
239
|
-
const answer = await transport.door(DOOR_DISCOVER, { prefixes: [...DISCOVER_PREFIXES] });
|
|
240
|
-
const failed = discoveryFailure(answer.status, answer.body);
|
|
241
|
-
if (failed !== null)
|
|
242
|
-
return failed;
|
|
243
|
-
const document = parseDiscovery(answer.body);
|
|
244
|
-
if (document === null)
|
|
245
|
-
return { kind: 'transport-uncertainty' };
|
|
246
|
-
bounds = document.bounds;
|
|
247
|
-
const entries = trackedFrom(document);
|
|
248
|
-
tracked.clear();
|
|
249
|
-
for (const entry of entries)
|
|
250
|
-
tracked.set(entry.locator, entry);
|
|
251
|
-
for (const locator of handed.keys())
|
|
252
|
-
if (!tracked.has(locator))
|
|
253
|
-
handed.delete(locator);
|
|
254
|
-
notifications.track(entries);
|
|
255
|
-
return mapDiscovery(document, document.authorities.map((authority) => discoveredRoom(authority)), capabilities(document));
|
|
256
|
-
},
|
|
257
287
|
async bootstrap(_authorization, request) {
|
|
258
288
|
const entry = authorityFor(request.locator);
|
|
259
289
|
if (entry === undefined)
|
|
260
290
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
},
|
|
265
|
-
async refresh(_authorization, request) {
|
|
266
|
-
const entry = authorityFor(request.locator);
|
|
267
|
-
if (entry === undefined)
|
|
268
|
-
return { kind: 'room-not-readable', locator: request.locator };
|
|
269
|
-
if (request.pageToken !== undefined)
|
|
270
|
-
return { kind: 'transport-uncertainty' };
|
|
271
|
-
const from = logPosition(request.fromRoomVersion);
|
|
272
|
-
if (from === null)
|
|
273
|
-
return { kind: 'beyond-horizon' };
|
|
274
|
-
const answered = await streamed(entry, request, from);
|
|
275
|
-
if (answered !== null)
|
|
276
|
-
return answered;
|
|
277
|
-
return enumerateTogether({ entry, from, fromRoomVersion: request.fromRoomVersion });
|
|
291
|
+
return request.pageToken === undefined
|
|
292
|
+
? listedRoom(entry)
|
|
293
|
+
: chunkPage(entry, request.pageToken, request.arriving);
|
|
278
294
|
},
|
|
279
295
|
async mutate(_authorization, request, keep) {
|
|
280
296
|
const entry = authorityFor(request.locator);
|
|
281
297
|
if (entry === undefined)
|
|
282
298
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
283
|
-
const
|
|
299
|
+
const batch = request.changeBatch;
|
|
300
|
+
const destination = batch.between?.destination.room;
|
|
301
|
+
const into = destination === undefined ? undefined : authorityFor(destination);
|
|
302
|
+
if (destination !== undefined && into === undefined) {
|
|
303
|
+
return { kind: 'room-not-readable', locator: destination };
|
|
304
|
+
}
|
|
305
|
+
const mapped = into === undefined
|
|
306
|
+
? houseChanges(batch, entry.handle)
|
|
307
|
+
: houseMove(batch, entry.handle, into.handle);
|
|
284
308
|
if (mapped.kind === 'unmapped')
|
|
285
309
|
return rejectedMapping(mapped);
|
|
286
|
-
const head = operationHead(
|
|
310
|
+
const head = operationHead(batch, entry.authority);
|
|
287
311
|
const delta = deltaBody(mapped.changes);
|
|
288
312
|
const bytes = deltaBytes(delta);
|
|
289
313
|
const handed = request.upload;
|
|
290
|
-
const
|
|
314
|
+
const answer = (upload) => submit(request, head, mapped.changes, delta, bytes, entry, upload, keep, into);
|
|
315
|
+
const outcome = await answer(handed);
|
|
291
316
|
if (handed === undefined || !lapsedGrant(outcome))
|
|
292
|
-
return
|
|
293
|
-
return
|
|
317
|
+
return outcome;
|
|
318
|
+
return answer(undefined);
|
|
294
319
|
},
|
|
295
320
|
async history(_authorization, request) {
|
|
296
321
|
const entry = authorityFor(request.locator);
|
|
297
322
|
if (entry === undefined)
|
|
298
323
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
299
|
-
const answer = await transport.door(
|
|
324
|
+
const answer = await transport.door(houseDoorRoute('files/revisions/list'), revisionBody({
|
|
300
325
|
path: request.path,
|
|
301
326
|
handle: entry.handle,
|
|
302
327
|
...(request.revision === undefined ? {} : { revision: request.revision }),
|
|
@@ -307,6 +332,47 @@ export function createAgentsHouseAdapter(options) {
|
|
|
307
332
|
...(request.revision === undefined ? {} : { revision: request.revision }),
|
|
308
333
|
});
|
|
309
334
|
},
|
|
335
|
+
async binary(_authorization, request) {
|
|
336
|
+
const ask = pathAddress(request);
|
|
337
|
+
if (ask === null)
|
|
338
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
339
|
+
return downloaded(ask, request.locator);
|
|
340
|
+
},
|
|
341
|
+
async link(_authorization, request) {
|
|
342
|
+
const ask = pathAddress(request);
|
|
343
|
+
if (ask === null)
|
|
344
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
345
|
+
return linked(await ask(), request.locator);
|
|
346
|
+
},
|
|
347
|
+
async attach(_authorization, request) {
|
|
348
|
+
const entry = authorityFor(request.locator);
|
|
349
|
+
if (entry === undefined)
|
|
350
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
351
|
+
const declared = await transport.door(houseDoorRoute('files/attach'), {
|
|
352
|
+
room_ref: entry.authority,
|
|
353
|
+
name: request.name,
|
|
354
|
+
bytes: request.byteLength,
|
|
355
|
+
sha256: request.sha256,
|
|
356
|
+
media_type: request.mediaType.length > 0 ? request.mediaType : OCTET_STREAM,
|
|
357
|
+
});
|
|
358
|
+
const refused = refusedAttach(declared, request.locator);
|
|
359
|
+
if (refused !== null)
|
|
360
|
+
return refused;
|
|
361
|
+
const upload = houseUpload(declared.body?.upload);
|
|
362
|
+
if (upload === null)
|
|
363
|
+
return UNCERTAIN_READ;
|
|
364
|
+
const finished = await finishedUpload(transport, upload, request.blob);
|
|
365
|
+
if (finished === null)
|
|
366
|
+
return UNCERTAIN_READ;
|
|
367
|
+
const unfinished = refusedAttach(finished, request.locator);
|
|
368
|
+
if (unfinished !== null)
|
|
369
|
+
return unfinished;
|
|
370
|
+
const { path, revision } = (finished.body ?? {});
|
|
371
|
+
const root = `/rooms/${entry.handle}/`;
|
|
372
|
+
return typeof path === 'string' && path.startsWith(root) && typeof revision === 'string'
|
|
373
|
+
? { kind: 'attached', path: path.slice(root.length), revision }
|
|
374
|
+
: UNCERTAIN_READ;
|
|
375
|
+
},
|
|
310
376
|
reached(locator, version, target) {
|
|
311
377
|
return reachedVersion(version, target, authorityFor(locator)?.logEpoch);
|
|
312
378
|
},
|
|
@@ -316,7 +382,13 @@ export function createAgentsHouseAdapter(options) {
|
|
|
316
382
|
async action(_authorization, request) {
|
|
317
383
|
return withAt(await houseAction(transport, request));
|
|
318
384
|
},
|
|
319
|
-
|
|
385
|
+
search(_authorization, request) {
|
|
386
|
+
return houseSearch(transport, [...tracked.values()], request);
|
|
387
|
+
},
|
|
388
|
+
roomStream: {
|
|
389
|
+
hold,
|
|
390
|
+
observe: notifications.observe,
|
|
391
|
+
},
|
|
320
392
|
conversations: notifications.conversations,
|
|
321
393
|
serviceMode: notifications.serviceMode,
|
|
322
394
|
};
|
|
@@ -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"}
|
package/dist/chunks.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type AdapterFailure, type BootstrapPart, type BootstrapResult } from '@agentshouse/mdruntime';
|
|
2
|
+
import type { TrackedAuthority } from './discovery.js';
|
|
3
|
+
import { type HouseModels, type HouseScope } from './read.js';
|
|
4
|
+
import type { SpaceSchemas } from './space-schema.js';
|
|
5
|
+
import { type HouseDoor, type HouseMode } from './transport.js';
|
|
6
|
+
import { type LogPosition } from './version.js';
|
|
7
|
+
export type ChunkAddress = {
|
|
8
|
+
readonly url: string;
|
|
9
|
+
readonly bytes: number;
|
|
10
|
+
};
|
|
11
|
+
export type ChunkedRoom = LogPosition & {
|
|
12
|
+
readonly anchor: string;
|
|
13
|
+
readonly mode: HouseMode;
|
|
14
|
+
readonly chunks: ReadonlyMap<string, ChunkAddress>;
|
|
15
|
+
readonly parts: readonly BootstrapPart[];
|
|
16
|
+
readonly names: ReadonlyMap<string, string>;
|
|
17
|
+
readonly models: HouseModels;
|
|
18
|
+
};
|
|
19
|
+
export type Listed = ChunkedRoom | {
|
|
20
|
+
readonly kind: 'not-ready';
|
|
21
|
+
} | AdapterFailure;
|
|
22
|
+
type Answered = {
|
|
23
|
+
readonly status: number;
|
|
24
|
+
readonly body: unknown;
|
|
25
|
+
};
|
|
26
|
+
export declare function partId(logEpoch: string, hash: string): string;
|
|
27
|
+
export declare function siteChunkList(answer: Answered, locator: string): Listed;
|
|
28
|
+
export declare function chunkedHead(listed: ChunkedRoom, entry: TrackedAuthority, spaces: SpaceSchemas): Promise<BootstrapResult>;
|
|
29
|
+
export declare function chunkPart(body: ReadableStream<Uint8Array> | null, room: ChunkedRoom, id: string, arriving: ((bytes: number) => void) | undefined): Promise<BootstrapResult>;
|
|
30
|
+
export declare function chunkLister(transport: HouseDoor, most: () => number): {
|
|
31
|
+
askAll: (entries: readonly TrackedAuthority[]) => void;
|
|
32
|
+
list: (entry: TrackedAuthority) => Promise<Listed>;
|
|
33
|
+
renew(entry: TrackedAuthority, installing: readonly TrackedAuthority[]): Promise<Listed>;
|
|
34
|
+
forget(): void;
|
|
35
|
+
};
|
|
36
|
+
export declare function chunkScope(body: ReadableStream<Uint8Array>, room: ChunkedRoom, arriving: ((bytes: number) => void) | undefined): Promise<HouseScope | null>;
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=chunks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunks.d.ts","sourceRoot":"","sources":["../src/chunks.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,EACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,EAML,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAkB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAA6B,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3E,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,WAAW,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAAG,cAAc,CAAC;AAEnF,KAAK,QAAQ,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAoCpE,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7D;AA4BD,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAIvE;AAED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,eAAe,CAAC,CAuB1B;AAED,wBAAsB,SAAS,CAC7B,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,IAAI,EACvC,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,GAC9C,OAAO,CAAC,eAAe,CAAC,CAM1B;AAgBD,wBAAgB,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,MAAM;sBAwCzC,SAAS,gBAAgB,EAAE;kBAU/B,gBAAgB,KAAG,OAAO,CAAC,MAAM,CAAC;iBASxC,gBAAgB,cAAc,SAAS,gBAAgB,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;;EAc3F;AAuCD,wBAAsB,UAAU,CAC9B,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,EAChC,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,GAC9C,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAgC5B"}
|