@agentshouse/mdruntime-adapter 0.1.0-cfded86738bb2 → 0.1.0-cfe552b74bdf7

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 (63) hide show
  1. package/README.md +2 -2
  2. package/dist/actions.d.ts +3 -56
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +1 -287
  5. package/dist/adapter.d.ts.map +1 -1
  6. package/dist/adapter.js +158 -326
  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 +9 -3
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +8 -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 +11 -12
  29. package/dist/part.d.ts.map +1 -1
  30. package/dist/part.js +63 -55
  31. package/dist/read.d.ts +19 -57
  32. package/dist/read.d.ts.map +1 -1
  33. package/dist/read.js +84 -220
  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 +75 -157
  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 -36
  52. package/dist/transport.d.ts.map +1 -1
  53. package/dist/transport.js +55 -11
  54. package/dist/upload.d.ts.map +1 -1
  55. package/dist/upload.js +26 -15
  56. package/dist/write.d.ts +6 -1
  57. package/dist/write.d.ts.map +1 -1
  58. package/dist/write.js +17 -19
  59. package/package.json +8 -4
  60. package/AGENTS.md +0 -317
  61. package/dist/gather.d.ts +0 -4
  62. package/dist/gather.d.ts.map +0 -1
  63. package/dist/gather.js +0 -35
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, manifested, parseEnumeration, parseFileAddress, parseGrant, parseParted, partInventory, refreshFrom, viewOf, wholeView, } from './read.js';
7
- import { PART_ATTEMPTS, partArrival, partFrame, 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';
9
7
  import { finishedUpload, houseUpload } from './upload.js';
10
8
  import { houseAction } from './actions.js';
11
- import { classifyDoor, classifyRead, discoveryFailure, doorRefusal } from './refusal.js';
12
- import { houseNotifications } from './stream.js';
13
- 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';
14
13
  import { batchPaths, deltaBody, deltaBytes, deltaDigest, historyOutcome, houseChanges, houseMove, mutationOutcome, operationHead, rejectedMapping, revisionBody, uploadable, } from './write.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,160 +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, received, arriving) {
64
- if (received !== undefined) {
65
- const kept = new Uint8Array(received);
66
- const held = await housePart(continued.room, kept, listed, 'credential');
67
- if (held !== null)
68
- return 'kind' in held ? held : { scope: held, frame: kept };
69
- }
70
- for (let attempt = 0; attempt < PART_ATTEMPTS; attempt += 1) {
71
- const answered = await transport.door(DOOR_BOOTSTRAP, {
72
- prefixes: [authorityRoot(entry.handle)],
73
- part: listed.part,
74
- ...(continued.held === undefined ? {} : { held: [continued.held] }),
75
- }, partArrival(listed, arriving));
76
- const failure = classifyRead(answered.status, answered.body, entry.locator);
77
- if (failure !== null)
78
- return failure;
79
- const frame = partFrame(answered.body);
80
- if (frame === null)
81
- continue;
82
- const scope = await housePart(continued.room, frame, listed, 'credential');
83
- if (scope !== null)
84
- return 'kind' in scope ? scope : { scope, frame };
85
- }
86
- return unverifiedPart(entry.locator);
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
+ };
87
79
  }
88
- async function manifestPage(asked, continued) {
89
- const inventory = partInventory(continued.room);
90
- if (inventory.parts === 0) {
91
- const page = await partPage(asked, continued, undefined, undefined);
92
- return page.kind === 'bootstrap' ? { ...page, inventory } : page;
93
- }
94
- return manifested(continued.room, inventory, JSON.stringify(continued));
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
95
  }
96
- async function partPage(asked, continued, received, arriving) {
97
- const { entry } = asked;
98
- const listed = continued.room.parts[continued.next];
99
- const sent = listed === undefined
100
- ? { scope: emptyScope(continued.room), frame: null }
101
- : await fetchedPart(entry, continued, listed, received, arriving);
102
- if ('kind' in sent)
103
- return sent;
104
- const scope = await reused(sent.scope, asked.held);
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);
105
101
  if (scope === null) {
106
- return asked.held === undefined
107
- ? UNCERTAIN_READ
108
- : bootstrapTogether({ entry, held: undefined });
102
+ unreused.add(entry.locator);
103
+ return UNCERTAIN_READ;
109
104
  }
110
- const next = continued.next + 1;
111
- const more = next < continued.room.parts.length;
112
- if (continued.next === 0 && !more)
113
- handed.set(entry.locator, roomVersion(scope));
114
- else
115
- handed.delete(entry.locator);
116
- notifications.reach(entry.authority, scope);
117
- const seen = [
118
- ...continued.seen,
119
- ...entry.schemas.filter((schema) => scope.files.some((file) => file.path === schema)),
120
- ];
121
- const models = await partModels(scope, entry, new Set(seen), !more);
122
105
  return {
123
106
  ...(await stepped(bootstrapping(scope))),
124
- ...(models === undefined ? {} : { models }),
125
- ...(more ? { pageToken: JSON.stringify({ ...continued, next, seen }) } : {}),
126
- ...(sent.frame === null ? {} : { received: sent.frame }),
107
+ ...(part.models === undefined ? {} : { models: part.models }),
108
+ ...(part.pageToken === undefined ? {} : { pageToken: part.pageToken }),
109
+ bytes: part.bytes,
127
110
  };
128
111
  }
129
- async function enumeratedPage(ask, page) {
130
- const answer = await transport.door(DOOR_ENUMERATE, {
131
- prefixes: [authorityRoot(ask.entry.handle)],
132
- positions: [
133
- {
134
- ...presented(ask.entry.authority, { position: page.after, logEpoch: ask.from.logEpoch }),
135
- page: { through: page.through, read: page.read },
136
- },
137
- ],
138
- });
139
- const failure = classifyRead(answer.status, answer.body, ask.entry.locator);
140
- if (failure !== null)
141
- return failure;
142
- const enumeration = parseEnumeration(answer.body, 'credential');
143
- 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)
144
132
  return UNCERTAIN_READ;
145
- return (viewOf(enumeration, ask.entry) ?? { kind: 'room-not-readable', locator: ask.entry.locator });
146
- }
147
- async function enumeratedRoom(enumeration, ask) {
148
- const first = viewOf(enumeration, ask.entry);
149
- if (first === undefined)
150
- return { kind: 'room-not-readable', locator: ask.entry.locator };
151
- const view = await wholeView(first, (page) => enumeratedPage(ask, page));
152
- if ('kind' in view)
153
- return view;
154
- notifications.reach(ask.entry.authority, view);
155
- const answer = await refreshFrom(view, ask.fromRoomVersion);
156
- if (answer.kind !== 'net-advancement')
157
- return answer;
158
- handed.set(ask.entry.locator, roomVersion(view));
159
- const models = await viewModels(view, ask.entry);
160
- return models === undefined ? answer : { ...answer, models };
133
+ return stepped(bootstrapping({ ...last, files, contents }));
161
134
  }
162
- async function streamed(entry, request, from) {
163
- if (handed.get(entry.locator) !== request.fromRoomVersion)
164
- return null;
165
- const asked = notifications.edited(entry, from);
166
- const kept = asked.length === 0 || heldRevisions === undefined
167
- ? new Map()
168
- : await heldRevisions(entry.locator, asked);
169
- const advanced = await stepped(notifications.advance(entry, from, (path, revision) => kept.get(path) === revision));
170
- if (advanced === null)
171
- return null;
172
- handed.set(entry.locator, advanced.page.roomVersion);
173
- const models = await streamedModels(advanced.schemas, entry, 'credential');
174
- 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);
175
148
  }
176
149
  function held(rooms) {
177
- const kept = rooms.flatMap((room) => {
150
+ notifications.send(rooms.flatMap((room) => {
178
151
  const entry = tracked.get(room.locator);
179
152
  const at = logPosition(room.roomVersion);
180
- if (entry === undefined || at === null)
181
- return [];
182
- handed.set(room.locator, room.roomVersion);
183
- notifications.reach(entry.authority, at);
184
- return [presented(entry.authority, at)];
185
- });
186
- notifications.send(kept);
187
- }
188
- async function adoptedMove(entry, into, outcome) {
189
- if (outcome.kind === 'accepted' && outcome.destination !== undefined) {
190
- await adopted(into, { kind: 'accepted', ...outcome.destination });
191
- }
192
- return adopted(entry, outcome);
193
- }
194
- async function adopted(entry, outcome) {
195
- if (outcome.kind !== 'accepted')
196
- return outcome;
197
- const held = handed.get(entry.locator);
198
- if (held === undefined)
199
- return outcome;
200
- const follows = followsVersion(held, outcome.roomVersion);
201
- if (follows)
202
- handed.set(entry.locator, outcome.roomVersion);
203
- const at = logPosition(outcome.roomVersion);
204
- if (follows && at !== null)
205
- notifications.reach(entry.authority, at);
206
- return outcome;
153
+ return entry === undefined || at === null ? [] : [presented(entry.authority, at)];
154
+ }));
207
155
  }
208
156
  function authorityFor(locator) {
209
157
  return tracked.get(locator);
@@ -222,116 +170,18 @@ export function createAgentsHouseAdapter(options) {
222
170
  return result;
223
171
  return { ...result, at: { locator, roomVersion: roomVersion({ position, logEpoch }) } };
224
172
  }
225
- async function holding(asks) {
226
- const bound = Math.floor(declared().max_held_files / Math.max(1, asks.filter((ask) => ask.held !== undefined).length));
227
- const held = [];
228
- for (const ask of asks) {
229
- if (ask.held === undefined || bound === 0)
230
- continue;
231
- const files = await heldFiles(ask.entry.authority, ask.held, bound);
232
- if (files !== null)
233
- held.push(files);
234
- }
235
- return held;
236
- }
237
- async function bootstrapped(asks, answer) {
238
- let open = asks.map((asked, ask) => ({ entry: asked.entry, asked, ask }));
239
- while (open.length > 0) {
240
- const unreached = [];
241
- for (const part of selections(open, declared().max_prefixes)) {
242
- const held = await holding(part.map(({ asked }) => asked));
243
- const answered = await transport.door(DOOR_BOOTSTRAP, {
244
- prefixes: part.map(({ entry }) => authorityRoot(entry.handle)),
245
- ...(held.length === 0 ? {} : { held }),
246
- });
247
- const classified = part.map(({ entry }) => classifyDoor(answered.status, answered.body, entry.locator));
248
- const parted = classified[0] === null ? parseParted(answered.body) : null;
249
- for (const [index, asked] of part.entries()) {
250
- const failure = classified[index];
251
- if (failure !== null && failure !== undefined) {
252
- answer(asked.ask, failure);
253
- continue;
254
- }
255
- if (parted === null) {
256
- answer(asked.ask, UNCERTAIN_READ);
257
- continue;
258
- }
259
- const room = parted.rooms.find((candidate) => candidate.anchor === asked.entry.authority);
260
- if (room === undefined && parted.next !== undefined) {
261
- unreached.push(asked);
262
- continue;
263
- }
264
- if (room === undefined) {
265
- answer(asked.ask, { kind: 'room-not-readable', locator: asked.entry.locator });
266
- continue;
267
- }
268
- const kept = held.find((files) => files.room === asked.entry.authority);
269
- answer(asked.ask, await manifestPage(asked.asked, {
270
- room,
271
- next: 0,
272
- seen: [],
273
- ...(kept === undefined ? {} : { held: kept }),
274
- }));
275
- }
276
- }
277
- open = unreached;
278
- }
279
- }
280
- function layered(asks) {
281
- const depths = new Map();
282
- const layers = [];
283
- for (const ask of asks) {
284
- const depth = depths.get(ask.ask.entry.authority) ?? 0;
285
- depths.set(ask.ask.entry.authority, depth + 1);
286
- (layers[depth] ??= []).push(ask);
287
- }
288
- return layers;
289
- }
290
- async function enumerated(asks) {
291
- const answers = [];
292
- const parts = layered(asks.map((ask, index) => ({ ask, index }))).flatMap((layer) => selections(layer, declared().max_prefixes));
293
- for (const part of parts) {
294
- let open = [...part];
295
- while (open.length > 0) {
296
- const answer = await transport.door(DOOR_ENUMERATE, {
297
- prefixes: open.map(({ ask }) => authorityRoot(ask.entry.handle)),
298
- positions: open.map(({ ask }) => presented(ask.entry.authority, ask.from)),
299
- });
300
- const classified = open.map(({ ask }) => classifyRead(answer.status, answer.body, ask.entry.locator));
301
- if (classified[0]?.kind === 'beyond-horizon') {
302
- const named = doorRefusal(answer.body)?.fields.authority;
303
- const expired = open.filter(({ ask }) => ask.entry.authority === named);
304
- const answered = expired.length === 0 ? UNCERTAIN_READ : { kind: 'beyond-horizon' };
305
- const gone = expired.length === 0 ? open : expired;
306
- for (const ask of gone)
307
- answers[ask.index] = answered;
308
- open = open.filter((ask) => !gone.includes(ask));
309
- continue;
310
- }
311
- const enumeration = classified[0] === null ? parseEnumeration(answer.body, 'credential') : null;
312
- for (const [answerIndex, { ask, index }] of open.entries()) {
313
- const failure = classified[answerIndex];
314
- if (failure !== null && failure !== undefined) {
315
- answers[index] = failure;
316
- continue;
317
- }
318
- answers[index] =
319
- enumeration === null ? UNCERTAIN_READ : await enumeratedRoom(enumeration, ask);
320
- }
321
- open = [];
322
- }
323
- }
324
- return answers;
325
- }
326
- const bootstrapTogether = gatheredEach(bootstrapped);
327
- const enumerateTogether = gathered(enumerated);
328
173
  async function uploaded(head, changes, delta, bytes, entry, handed, keep) {
329
174
  const paths = batchPaths(changes);
330
175
  const sha256 = await deltaDigest(delta);
331
176
  if (handed !== undefined && handed.sha256 === sha256) {
332
177
  return { body: { ...head, paths, upload: handed, runtime: notifications.runtime } };
333
178
  }
334
- 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
+ });
335
185
  if (minted.status !== 200) {
336
186
  return {
337
187
  outcome: await stepped(mutationOutcome(minted.status, minted.body, entry.locator, entry.handle)),
@@ -379,11 +229,11 @@ export function createAgentsHouseAdapter(options) {
379
229
  : { body: inline };
380
230
  if ('outcome' in prepared)
381
231
  return prepared.outcome;
382
- const answer = await transport.door(DOOR_BATCH, prepared.body);
232
+ const answer = await transport.door(houseDoorRoute('batch'), prepared.body);
383
233
  const stagedFiles = await staged(answer, request);
384
234
  if (stagedFiles === false)
385
235
  return UNCERTAIN;
386
- 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);
387
237
  if (stagedFiles === true && (await staged(settled, request)) !== null)
388
238
  return UNCERTAIN;
389
239
  return stepped(mutationOutcome(settled.status, settled.body, entry.locator, entry.handle, into === undefined
@@ -411,9 +261,22 @@ export function createAgentsHouseAdapter(options) {
411
261
  function linked(answer, locator) {
412
262
  const address = addressed(answer, locator);
413
263
  return address.kind === 'address'
414
- ? { kind: 'link', url: address.url, name: address.name }
264
+ ? { kind: 'link', url: address.url, name: address.name, mediaType: address.mediaType }
415
265
  : address;
416
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
+ }
417
280
  async function downloaded(ask, locator) {
418
281
  let address = addressed(await ask(), locator);
419
282
  if (address.kind !== 'address')
@@ -438,7 +301,7 @@ export function createAgentsHouseAdapter(options) {
438
301
  const entry = authorityFor(request.locator);
439
302
  if (entry === undefined)
440
303
  return null;
441
- return () => transport.door(DOOR_FILES_GET, {
304
+ return () => transport.door(houseDoorRoute('files/get'), {
442
305
  room_ref: entry.authority,
443
306
  path: request.path,
444
307
  revision: request.revision,
@@ -446,72 +309,19 @@ export function createAgentsHouseAdapter(options) {
446
309
  }
447
310
  return {
448
311
  roomTypes: HOUSE_ROOM_TYPES,
312
+ nameableRoomTypes: HOUSE_NAMEABLE_ROOM_TYPES,
449
313
  async authorize() {
450
314
  return options.authorize();
451
315
  },
452
- async discover(_authorization, scope) {
453
- const answer = await transport.door(DOOR_DISCOVER, {
454
- prefixes: [...DISCOVER_PREFIXES],
455
- ...(scope === undefined ? {} : { rooms: scope.authorities }),
456
- });
457
- const failed = discoveryFailure(answer.status, answer.body);
458
- if (failed !== null)
459
- return failed;
460
- const document = parseDiscovery(answer.body);
461
- if (document === null)
462
- return { kind: 'transport-uncertainty' };
463
- bounds = document.bounds;
464
- const entries = trackedFrom(document);
465
- const covered = scope === undefined
466
- ? null
467
- : [
468
- ...new Set([
469
- ...[...tracked.values()]
470
- .filter((entry) => scope.authorities.includes(entry.authority))
471
- .map((entry) => entry.locator),
472
- ...entries.map((entry) => entry.locator),
473
- ]),
474
- ];
475
- if (covered === null)
476
- tracked.clear();
477
- else
478
- for (const locator of covered)
479
- tracked.delete(locator);
480
- for (const entry of entries)
481
- tracked.set(entry.locator, entry);
482
- for (const locator of handed.keys())
483
- if (!tracked.has(locator))
484
- handed.delete(locator);
485
- notifications.track([...tracked.values()]);
486
- return {
487
- ...mapDiscovery(document, document.authorities.map((authority) => discoveredRoom(authority)), capabilities(document.actions, [...tracked.values()])),
488
- member: document.member,
489
- ...(covered === null ? {} : { covered }),
490
- };
491
- },
492
316
  async bootstrap(_authorization, request) {
493
317
  const entry = authorityFor(request.locator);
494
318
  if (entry === undefined)
495
319
  return { kind: 'room-not-readable', locator: request.locator };
496
- const asked = { entry, held: request.held };
497
- if (request.pageToken !== undefined) {
498
- return partPage(asked, JSON.parse(request.pageToken), request.received, request.arriving);
499
- }
500
- return bootstrapTogether(asked);
501
- },
502
- async refresh(_authorization, request) {
503
- const entry = authorityFor(request.locator);
504
- if (entry === undefined)
505
- return { kind: 'room-not-readable', locator: request.locator };
506
- if (request.pageToken !== undefined)
507
- return { kind: 'transport-uncertainty' };
508
- const from = logPosition(request.fromRoomVersion);
509
- if (from === null)
510
- return { kind: 'beyond-horizon' };
511
- const answered = await streamed(entry, request, from);
512
- if (answered !== null)
513
- return answered;
514
- 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);
515
325
  },
516
326
  async mutate(_authorization, request, keep) {
517
327
  const entry = authorityFor(request.locator);
@@ -528,22 +338,21 @@ export function createAgentsHouseAdapter(options) {
528
338
  : houseMove(batch, entry.handle, into.handle);
529
339
  if (mapped.kind === 'unmapped')
530
340
  return rejectedMapping(mapped);
531
- const head = operationHead(batch);
341
+ const head = operationHead(batch, entry.authority);
532
342
  const delta = deltaBody(mapped.changes);
533
343
  const bytes = deltaBytes(delta);
534
344
  const handed = request.upload;
535
345
  const answer = (upload) => submit(request, head, mapped.changes, delta, bytes, entry, upload, keep, into);
536
- const settle = (outcome) => into === undefined ? adopted(entry, outcome) : adoptedMove(entry, into, outcome);
537
346
  const outcome = await answer(handed);
538
347
  if (handed === undefined || !lapsedGrant(outcome))
539
- return settle(outcome);
540
- return settle(await answer(undefined));
348
+ return outcome;
349
+ return answer(undefined);
541
350
  },
542
351
  async history(_authorization, request) {
543
352
  const entry = authorityFor(request.locator);
544
353
  if (entry === undefined)
545
354
  return { kind: 'room-not-readable', locator: request.locator };
546
- const answer = await transport.door(DOOR_REVISIONS, revisionBody({
355
+ const answer = await transport.door(houseDoorRoute('revisions'), revisionBody({
547
356
  path: request.path,
548
357
  handle: entry.handle,
549
358
  ...(request.revision === undefined ? {} : { revision: request.revision }),
@@ -566,6 +375,35 @@ export function createAgentsHouseAdapter(options) {
566
375
  return { kind: 'room-not-readable', locator: request.locator };
567
376
  return linked(await ask(), request.locator);
568
377
  },
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;
406
+ },
569
407
  reached(locator, version, target) {
570
408
  return reachedVersion(version, target, authorityFor(locator)?.logEpoch);
571
409
  },
@@ -575,18 +413,12 @@ export function createAgentsHouseAdapter(options) {
575
413
  async action(_authorization, request) {
576
414
  return withAt(await houseAction(transport, request));
577
415
  },
416
+ search(_authorization, request) {
417
+ return houseSearch(transport, [...tracked.values()], request);
418
+ },
578
419
  roomStream: {
579
420
  hold: held,
580
- reopen: notifications.reopen,
581
- observe(notify, receipts, revisions) {
582
- heldRevisions = revisions;
583
- return notifications.observe(notify, receipts);
584
- },
585
- published(locator, roomVersion) {
586
- const at = logPosition(roomVersion);
587
- if (at !== null)
588
- notifications.published(locator, at);
589
- },
421
+ observe: notifications.observe,
590
422
  },
591
423
  conversations: notifications.conversations,
592
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"}
@@ -0,0 +1,2 @@
1
+ import { CROCKFORD_CHARACTER } from './crockford.js';
2
+ export const APP_REFERENCE_PATTERN = new RegExp(`^a_(${CROCKFORD_CHARACTER}+)\\.(${CROCKFORD_CHARACTER})$`);
@@ -0,0 +1,4 @@
1
+ export declare const CROCKFORD_ALPHABET = "0123456789abcdefghjkmnpqrstvwxyz";
2
+ export declare const CROCKFORD_CHARACTER = "[0123456789abcdefghjkmnpqrstvwxyz]";
3
+ export declare const CROCKFORD_LEADING_CHARACTER: string;
4
+ //# sourceMappingURL=crockford.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crockford.d.ts","sourceRoot":"","sources":["../src/crockford.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,qCAAqC,CAAC;AAErE,eAAO,MAAM,mBAAmB,uCAA4B,CAAC;AAE7D,eAAO,MAAM,2BAA2B,QAAqC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export const CROCKFORD_ALPHABET = '0123456789abcdefghjkmnpqrstvwxyz';
2
+ export const CROCKFORD_CHARACTER = `[${CROCKFORD_ALPHABET}]`;
3
+ export const CROCKFORD_LEADING_CHARACTER = `[${CROCKFORD_ALPHABET.slice(1)}]`;