@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.
Files changed (67) hide show
  1. package/README.md +2 -2
  2. package/dist/actions.d.ts +3 -71
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +1 -317
  5. package/dist/adapter.d.ts.map +1 -1
  6. package/dist/adapter.js +171 -336
  7. package/dist/app-reference.d.ts +2 -0
  8. package/dist/app-reference.d.ts.map +1 -0
  9. package/dist/app-reference.js +2 -0
  10. package/dist/crockford.d.ts +4 -0
  11. package/dist/crockford.d.ts.map +1 -0
  12. package/dist/crockford.js +3 -0
  13. package/dist/discovery.d.ts +12 -12
  14. package/dist/discovery.d.ts.map +1 -1
  15. package/dist/discovery.js +44 -51
  16. package/dist/history.d.ts +12 -0
  17. package/dist/history.d.ts.map +1 -0
  18. package/dist/history.js +91 -0
  19. package/dist/house-model.d.ts +892 -0
  20. package/dist/house-model.d.ts.map +1 -0
  21. package/dist/house-model.js +482 -0
  22. package/dist/index.d.ts +10 -3
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +9 -2
  25. package/dist/model.d.ts +5 -2
  26. package/dist/model.d.ts.map +1 -1
  27. package/dist/model.js +10 -29
  28. package/dist/part.d.ts +12 -11
  29. package/dist/part.d.ts.map +1 -1
  30. package/dist/part.js +66 -56
  31. package/dist/read.d.ts +19 -56
  32. package/dist/read.d.ts.map +1 -1
  33. package/dist/read.js +138 -297
  34. package/dist/refusal.d.ts +0 -3
  35. package/dist/refusal.d.ts.map +1 -1
  36. package/dist/refusal.js +0 -5
  37. package/dist/room-stream.d.ts +19 -0
  38. package/dist/room-stream.d.ts.map +1 -0
  39. package/dist/room-stream.js +57 -0
  40. package/dist/room-types.d.ts +2 -1
  41. package/dist/room-types.d.ts.map +1 -1
  42. package/dist/room-types.js +62 -3
  43. package/dist/search.d.ts +5 -0
  44. package/dist/search.d.ts.map +1 -0
  45. package/dist/search.js +47 -0
  46. package/dist/site.d.ts.map +1 -1
  47. package/dist/site.js +79 -177
  48. package/dist/stream.d.ts +13 -14
  49. package/dist/stream.d.ts.map +1 -1
  50. package/dist/stream.js +168 -426
  51. package/dist/transport.d.ts +48 -38
  52. package/dist/transport.d.ts.map +1 -1
  53. package/dist/transport.js +55 -11
  54. package/dist/upload.d.ts +12 -0
  55. package/dist/upload.d.ts.map +1 -0
  56. package/dist/upload.js +63 -0
  57. package/dist/write.d.ts +6 -1
  58. package/dist/write.d.ts.map +1 -1
  59. package/dist/write.js +19 -32
  60. package/package.json +8 -4
  61. package/AGENTS.md +0 -309
  62. package/dist/gather.d.ts +0 -4
  63. package/dist/gather.d.ts.map +0 -1
  64. package/dist/gather.js +0 -35
  65. package/dist/referrer.d.ts +0 -9
  66. package/dist/referrer.d.ts.map +0 -1
  67. package/dist/referrer.js +0 -41
package/dist/adapter.js CHANGED
@@ -1,21 +1,21 @@
1
1
  import { stepped } from '@agentshouse/mdruntime';
2
- import { DISCOVER_PREFIXES, capabilities, discoveredRoom, mapDiscovery, parseDiscovery, trackedFrom, } from './discovery.js';
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, emptyScope, housePart, parseEnumeration, parseFileAddress, parseGrant, parseParted, refreshFrom, viewOf, wholeView, } from './read.js';
7
- import { PART_ATTEMPTS, unverifiedPart } from './part.js';
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 { classifyDoor, classifyRead, discoveryFailure, doorRefusal } from './refusal.js';
11
- import { houseNotifications } from './stream.js';
12
- import { DOOR_BATCH, DOOR_BATCH_UPLOAD, DOOR_BOOTSTRAP, DOOR_DISCOVER, DOOR_ENUMERATE, DOOR_FILES_GET, DOOR_REVISIONS, } from './transport.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
13
  import { batchPaths, deltaBody, deltaBytes, deltaDigest, historyOutcome, houseChanges, houseMove, mutationOutcome, operationHead, rejectedMapping, revisionBody, uploadable, } from './write.js';
14
- import { houseReferrer, houseReferrerScope } from './referrer.js';
15
- import { HOUSE_ROOM_TYPES } from './room-types.js';
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 handed = new Map();
56
- let heldRevisions;
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
- async function fetchedPart(entry, continued, listed) {
64
- for (let attempt = 0; attempt < PART_ATTEMPTS; attempt += 1) {
65
- const answered = await transport.door(DOOR_BOOTSTRAP, {
66
- prefixes: [authorityRoot(entry.handle)],
67
- part: listed.part,
68
- ...(continued.held === undefined ? {} : { held: [continued.held] }),
69
- });
70
- const failure = classifyRead(answered.status, answered.body, entry.locator);
71
- if (failure !== null)
72
- return failure;
73
- const scope = await housePart(continued.room, answered.body, listed, 'credential');
74
- if (scope !== null)
75
- return scope;
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
- async function partPage(asked, continued) {
80
- const { entry } = asked;
81
- const listed = continued.room.parts[continued.next];
82
- const sent = listed === undefined
83
- ? emptyScope(continued.room)
84
- : await fetchedPart(entry, continued, listed);
85
- if ('kind' in sent)
86
- return sent;
87
- const scope = await reused(sent, asked.held);
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
- return asked.held === undefined
90
- ? UNCERTAIN_READ
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
- ...(more ? { pageToken: JSON.stringify({ ...continued, next, seen }) } : {}),
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 enumeratedPage(ask, page) {
112
- const answer = await transport.door(DOOR_ENUMERATE, {
113
- prefixes: [authorityRoot(ask.entry.handle)],
114
- positions: [
115
- {
116
- ...presented(ask.entry.authority, { position: page.after, logEpoch: ask.from.logEpoch }),
117
- page: { through: page.through, read: page.read },
118
- },
119
- ],
120
- });
121
- const failure = classifyRead(answer.status, answer.body, ask.entry.locator);
122
- if (failure !== null)
123
- return failure;
124
- const enumeration = parseEnumeration(answer.body, 'credential');
125
- if (enumeration === null)
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 (viewOf(enumeration, ask.entry) ?? { kind: 'room-not-readable', locator: ask.entry.locator });
133
+ return stepped(bootstrapping({ ...last, files, contents }));
128
134
  }
129
- async function enumeratedRoom(enumeration, ask) {
130
- const first = viewOf(enumeration, ask.entry);
131
- if (first === undefined)
132
- return { kind: 'room-not-readable', locator: ask.entry.locator };
133
- const view = await wholeView(first, (page) => enumeratedPage(ask, page));
134
- if ('kind' in view)
135
- return view;
136
- notifications.reach(ask.entry.authority, view);
137
- const answer = await refreshFrom(view, ask.fromRoomVersion);
138
- if (answer.kind !== 'net-advancement')
139
- return answer;
140
- handed.set(ask.entry.locator, roomVersion(view));
141
- const models = await viewModels(view, ask.entry);
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
- const kept = rooms.flatMap((room) => {
150
+ notifications.send(rooms.flatMap((room) => {
160
151
  const entry = tracked.get(room.locator);
161
152
  const at = logPosition(room.roomVersion);
162
- if (entry === undefined || at === null)
163
- return [];
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(DOOR_BATCH_UPLOAD, { ...head, paths, bytes, sha256 });
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 grants = refusal.fields.upload;
344
- if (!Array.isArray(grants))
211
+ const uploads = refusal.fields.upload;
212
+ if (!Array.isArray(uploads))
345
213
  return false;
346
- for (const grant of grants) {
347
- const { url, operation, sha256 } = grant;
348
- const change = batch.changes.find((held) => held.kind === 'binary' && held.sha256 === sha256);
349
- if (typeof url !== 'string' || typeof operation !== 'string' || change === undefined)
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 delivered = await transport.transfer({
352
- act: 'binary_stage',
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(DOOR_BATCH, prepared.body);
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(DOOR_BATCH, prepared.body);
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(DOOR_FILES_GET, {
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
- const asked = { entry, held: request.held };
484
- if (request.pageToken !== undefined) {
485
- return partPage(asked, JSON.parse(request.pageToken));
486
- }
487
- return bootstrapTogether(asked);
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 settle(outcome);
527
- return settle(await answer(undefined));
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(DOOR_REVISIONS, revisionBody({
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
- if (request.kind === 'path') {
546
- const ask = pathAddress(request);
547
- if (ask === null)
548
- return { kind: 'room-not-readable', locator: request.locator };
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
- referrerScope(referrer) {
564
- return houseReferrerScope(referrer, tracked);
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
- reopen: notifications.reopen,
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,2 @@
1
+ export declare const APP_REFERENCE_PATTERN: RegExp;
2
+ //# sourceMappingURL=app-reference.d.ts.map
@@ -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"}