@agentshouse/mdruntime-adapter 0.1.0-cacce09fc82c6 → 0.1.0-cad35e1fe3a03
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 +4 -5
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +13 -322
- package/dist/adapter.d.ts +1 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +275 -208
- 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 +23 -14
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +94 -53
- 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 +394 -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 +34 -37
- package/dist/read.d.ts +62 -42
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +176 -261
- package/dist/refusal.d.ts +2 -8
- package/dist/refusal.d.ts.map +1 -1
- package/dist/refusal.js +6 -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 -106
- 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 -13
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +275 -152
- package/dist/transport.d.ts +89 -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 +158 -58
- package/package.json +9 -6
- package/AGENTS.md +0 -253
- 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 {
|
|
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';
|
|
7
8
|
import { houseAction } from './actions.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
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
|
+
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,197 +136,190 @@ 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,
|
|
235
282
|
async authorize() {
|
|
236
283
|
return options.authorize();
|
|
237
284
|
},
|
|
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 {
|
|
256
|
-
...mapDiscovery(document, document.authorities.map((authority) => discoveredRoom(authority)), capabilities(document)),
|
|
257
|
-
member: document.member,
|
|
258
|
-
};
|
|
259
|
-
},
|
|
260
285
|
async bootstrap(_authorization, request) {
|
|
261
286
|
const entry = authorityFor(request.locator);
|
|
262
287
|
if (entry === undefined)
|
|
263
288
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
},
|
|
268
|
-
async refresh(_authorization, request) {
|
|
269
|
-
const entry = authorityFor(request.locator);
|
|
270
|
-
if (entry === undefined)
|
|
271
|
-
return { kind: 'room-not-readable', locator: request.locator };
|
|
272
|
-
if (request.pageToken !== undefined)
|
|
273
|
-
return { kind: 'transport-uncertainty' };
|
|
274
|
-
const from = logPosition(request.fromRoomVersion);
|
|
275
|
-
if (from === null)
|
|
276
|
-
return { kind: 'beyond-horizon' };
|
|
277
|
-
const answered = await streamed(entry, request, from);
|
|
278
|
-
if (answered !== null)
|
|
279
|
-
return answered;
|
|
280
|
-
return enumerateTogether({ entry, from, fromRoomVersion: request.fromRoomVersion });
|
|
289
|
+
return request.pageToken === undefined
|
|
290
|
+
? listedRoom(entry)
|
|
291
|
+
: chunkPage(entry, request.pageToken, request.arriving);
|
|
281
292
|
},
|
|
282
293
|
async mutate(_authorization, request, keep) {
|
|
283
294
|
const entry = authorityFor(request.locator);
|
|
284
295
|
if (entry === undefined)
|
|
285
296
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
286
|
-
const
|
|
297
|
+
const batch = request.changeBatch;
|
|
298
|
+
const destination = batch.between?.destination.room;
|
|
299
|
+
const into = destination === undefined ? undefined : authorityFor(destination);
|
|
300
|
+
if (destination !== undefined && into === undefined) {
|
|
301
|
+
return { kind: 'room-not-readable', locator: destination };
|
|
302
|
+
}
|
|
303
|
+
const mapped = into === undefined
|
|
304
|
+
? houseChanges(batch, entry.handle)
|
|
305
|
+
: houseMove(batch, entry.handle, into.handle);
|
|
287
306
|
if (mapped.kind === 'unmapped')
|
|
288
307
|
return rejectedMapping(mapped);
|
|
289
|
-
const head = operationHead(
|
|
308
|
+
const head = operationHead(batch, entry.authority);
|
|
290
309
|
const delta = deltaBody(mapped.changes);
|
|
291
310
|
const bytes = deltaBytes(delta);
|
|
292
311
|
const handed = request.upload;
|
|
293
|
-
const
|
|
312
|
+
const answer = (upload) => submit(request, head, mapped.changes, delta, bytes, entry, upload, keep, into);
|
|
313
|
+
const outcome = await answer(handed);
|
|
294
314
|
if (handed === undefined || !lapsedGrant(outcome))
|
|
295
|
-
return
|
|
296
|
-
return
|
|
315
|
+
return outcome;
|
|
316
|
+
return answer(undefined);
|
|
297
317
|
},
|
|
298
318
|
async history(_authorization, request) {
|
|
299
319
|
const entry = authorityFor(request.locator);
|
|
300
320
|
if (entry === undefined)
|
|
301
321
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
302
|
-
const answer = await transport.door(
|
|
322
|
+
const answer = await transport.door(houseDoorRoute('files/revisions/list'), revisionBody({
|
|
303
323
|
path: request.path,
|
|
304
324
|
handle: entry.handle,
|
|
305
325
|
...(request.revision === undefined ? {} : { revision: request.revision }),
|
|
@@ -310,6 +330,47 @@ export function createAgentsHouseAdapter(options) {
|
|
|
310
330
|
...(request.revision === undefined ? {} : { revision: request.revision }),
|
|
311
331
|
});
|
|
312
332
|
},
|
|
333
|
+
async binary(_authorization, request) {
|
|
334
|
+
const ask = pathAddress(request);
|
|
335
|
+
if (ask === null)
|
|
336
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
337
|
+
return downloaded(ask, request.locator);
|
|
338
|
+
},
|
|
339
|
+
async link(_authorization, request) {
|
|
340
|
+
const ask = pathAddress(request);
|
|
341
|
+
if (ask === null)
|
|
342
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
343
|
+
return linked(await ask(), request.locator);
|
|
344
|
+
},
|
|
345
|
+
async attach(_authorization, request) {
|
|
346
|
+
const entry = authorityFor(request.locator);
|
|
347
|
+
if (entry === undefined)
|
|
348
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
349
|
+
const declared = await transport.door(houseDoorRoute('files/attach'), {
|
|
350
|
+
room_ref: entry.authority,
|
|
351
|
+
name: request.name,
|
|
352
|
+
bytes: request.byteLength,
|
|
353
|
+
sha256: request.sha256,
|
|
354
|
+
media_type: request.mediaType.length > 0 ? request.mediaType : OCTET_STREAM,
|
|
355
|
+
});
|
|
356
|
+
const refused = refusedAttach(declared, request.locator);
|
|
357
|
+
if (refused !== null)
|
|
358
|
+
return refused;
|
|
359
|
+
const upload = houseUpload(declared.body?.upload);
|
|
360
|
+
if (upload === null)
|
|
361
|
+
return UNCERTAIN_READ;
|
|
362
|
+
const finished = await finishedUpload(transport, upload, request.blob);
|
|
363
|
+
if (finished === null)
|
|
364
|
+
return UNCERTAIN_READ;
|
|
365
|
+
const unfinished = refusedAttach(finished, request.locator);
|
|
366
|
+
if (unfinished !== null)
|
|
367
|
+
return unfinished;
|
|
368
|
+
const { path, revision } = (finished.body ?? {});
|
|
369
|
+
const root = `/rooms/${entry.handle}/`;
|
|
370
|
+
return typeof path === 'string' && path.startsWith(root) && typeof revision === 'string'
|
|
371
|
+
? { kind: 'attached', path: path.slice(root.length), revision }
|
|
372
|
+
: UNCERTAIN_READ;
|
|
373
|
+
},
|
|
313
374
|
reached(locator, version, target) {
|
|
314
375
|
return reachedVersion(version, target, authorityFor(locator)?.logEpoch);
|
|
315
376
|
},
|
|
@@ -319,7 +380,13 @@ export function createAgentsHouseAdapter(options) {
|
|
|
319
380
|
async action(_authorization, request) {
|
|
320
381
|
return withAt(await houseAction(transport, request));
|
|
321
382
|
},
|
|
322
|
-
|
|
383
|
+
search(_authorization, request) {
|
|
384
|
+
return houseSearch(transport, [...tracked.values()], request);
|
|
385
|
+
},
|
|
386
|
+
roomStream: {
|
|
387
|
+
hold,
|
|
388
|
+
observe: notifications.observe,
|
|
389
|
+
},
|
|
323
390
|
conversations: notifications.conversations,
|
|
324
391
|
serviceMode: notifications.serviceMode,
|
|
325
392
|
};
|
|
@@ -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"}
|