@agentshouse/mdruntime-adapter 0.1.0-ce1149641691d → 0.1.0-ce3ced044cab5

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 (61) hide show
  1. package/README.md +2 -2
  2. package/dist/actions.d.ts +6 -26
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +18 -150
  5. package/dist/adapter.d.ts.map +1 -1
  6. package/dist/adapter.js +167 -223
  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 +5 -10
  14. package/dist/discovery.d.ts.map +1 -1
  15. package/dist/discovery.js +18 -32
  16. package/dist/gather.d.ts +0 -1
  17. package/dist/gather.d.ts.map +1 -1
  18. package/dist/gather.js +1 -1
  19. package/dist/house-model.d.ts +2 -0
  20. package/dist/house-model.d.ts.map +1 -0
  21. package/dist/house-model.js +486 -0
  22. package/dist/index.d.ts +8 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +7 -1
  25. package/dist/model.d.ts +5 -1
  26. package/dist/model.d.ts.map +1 -1
  27. package/dist/model.js +11 -13
  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 +33 -17
  32. package/dist/read.d.ts.map +1 -1
  33. package/dist/read.js +187 -122
  34. package/dist/room-stream.d.ts +19 -0
  35. package/dist/room-stream.d.ts.map +1 -0
  36. package/dist/room-stream.js +57 -0
  37. package/dist/room-types.d.ts +7 -0
  38. package/dist/room-types.d.ts.map +1 -0
  39. package/dist/room-types.js +125 -0
  40. package/dist/site.d.ts.map +1 -1
  41. package/dist/site.js +43 -92
  42. package/dist/stream.d.ts +1 -0
  43. package/dist/stream.d.ts.map +1 -1
  44. package/dist/stream.js +17 -2
  45. package/dist/transport.d.ts +14 -8
  46. package/dist/transport.d.ts.map +1 -1
  47. package/dist/transport.js +2 -1
  48. package/dist/upload.d.ts +12 -0
  49. package/dist/upload.d.ts.map +1 -0
  50. package/dist/upload.js +63 -0
  51. package/dist/write.d.ts +4 -0
  52. package/dist/write.d.ts.map +1 -1
  53. package/dist/write.js +22 -18
  54. package/package.json +8 -4
  55. package/AGENTS.md +0 -304
  56. package/dist/handed.d.ts +0 -15
  57. package/dist/handed.d.ts.map +0 -1
  58. package/dist/handed.js +0 -45
  59. package/dist/referrer.d.ts +0 -7
  60. package/dist/referrer.d.ts.map +0 -1
  61. package/dist/referrer.js +0 -35
package/dist/adapter.js CHANGED
@@ -1,60 +1,49 @@
1
- import { sortedKeys, stepped } from '@agentshouse/mdruntime';
1
+ import { stepped } from '@agentshouse/mdruntime';
2
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';
3
+ import { streamedModels, viewModels } from './model.js';
4
+ import { gathered, selections } from './gather.js';
5
5
  import { createSiteAdapter } from './site.js';
6
- import { authorityRoot, bootstrapping, emptyScope, housePart, parseEnumeration, parseGrant, parseParted, refreshFrom, viewOf, wholeView, } from './read.js';
7
- import { PART_ATTEMPTS, unverifiedPart } from './part.js';
6
+ import { authorityRoot, bootstrapping, parseEnumeration, parseFileAddress, parseGrant, refreshFrom, viewOf, wholeView, } from './read.js';
7
+ import { roomStreams } from './room-stream.js';
8
8
  import { sha256Hex } from './digest.js';
9
- import { acceptedHanded, enumeratedHanded, heldHanded, scopeHanded, streamedHanded, } from './handed.js';
9
+ import { finishedUpload, houseUpload } from './upload.js';
10
10
  import { houseAction } from './actions.js';
11
11
  import { classifyDoor, classifyRead, discoveryFailure, doorRefusal } from './refusal.js';
12
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';
13
+ import { DOOR_BATCH, DOOR_BATCH_UPLOAD, DOOR_BOOTSTRAP, DOOR_DISCOVER, DOOR_ENUMERATE, DOOR_FILES_ATTACH, DOOR_FILES_GET, DOOR_REVISIONS, } from './transport.js';
14
14
  import { batchPaths, deltaBody, deltaBytes, deltaDigest, historyOutcome, houseChanges, houseMove, mutationOutcome, operationHead, rejectedMapping, revisionBody, uploadable, } from './write.js';
15
- import { houseReferrer } from './referrer.js';
15
+ import { HOUSE_NAMEABLE_ROOM_TYPES, HOUSE_ROOM_TYPES } from './room-types.js';
16
16
  import { followsVersion, logPosition, presented, reachedVersion, roomVersion, } from './version.js';
17
17
  const UNCERTAIN = { kind: 'transport-uncertainty' };
18
18
  const UNCERTAIN_READ = { kind: 'transport-uncertainty' };
19
+ const OCTET_STREAM = 'application/octet-stream';
20
+ const EXPIRED_ADDRESS = 403;
19
21
  function lapsedGrant(outcome) {
20
22
  return outcome.kind === 'rejected' && outcome.code === 'upload_unavailable';
21
23
  }
22
- const heldPaths = new WeakMap();
23
- async function sortedHeld(held) {
24
- const known = heldPaths.get(held.documents);
25
- if (known !== undefined)
26
- return known;
27
- const sorted = await stepped(sortedKeys(held.documents));
28
- heldPaths.set(held.documents, sorted);
29
- return sorted;
30
- }
31
- function heldFiles(authority, held, paths, bound) {
32
- const files = [];
33
- let through = null;
34
- for (let at = 0; at < paths.length && through === null; at += 1) {
35
- const revision = held.revisions[paths[at]];
36
- if (revision === undefined)
37
- continue;
38
- if (files.length === bound)
39
- through = files.at(-1).path;
40
- else
41
- files.push({ path: paths[at], revision });
42
- }
24
+ async function heldFiles(authority, held, bound) {
25
+ const listed = await held.files(null, bound + 1);
26
+ const files = listed.slice(0, bound);
27
+ const through = listed.length > bound ? (files.at(-1)?.path ?? null) : null;
43
28
  return files.length === 0 ? null : { room: authority, through, files };
44
29
  }
45
30
  async function reused(scope, held) {
46
31
  const sent = new Set(scope.contents.map((entry) => entry.path));
47
32
  const contents = [...scope.contents];
48
- for (const file of scope.files) {
49
- if (file.binary !== undefined || sent.has(file.path))
50
- continue;
51
- const content = held?.documents[file.path];
52
- if (content === undefined ||
53
- held?.revisions[file.path] !== file.revision ||
54
- (await sha256Hex(content)) !== file.sha256) {
33
+ const asked = scope.files.filter((file) => file.binary === undefined && !sent.has(file.path));
34
+ if (asked.length === 0)
35
+ return scope;
36
+ if (held === undefined)
37
+ return null;
38
+ const kept = await held.contents(asked.map(({ path }) => path));
39
+ for (const file of asked) {
40
+ const found = kept.get(file.path);
41
+ if (found === undefined ||
42
+ found.revision !== file.revision ||
43
+ (await sha256Hex(found.content)) !== file.sha256) {
55
44
  return null;
56
45
  }
57
- contents.push({ path: file.path, content });
46
+ contents.push({ path: file.path, content: found.content });
58
47
  }
59
48
  return { ...scope, contents };
60
49
  }
@@ -65,74 +54,49 @@ export function createAgentsHouseAdapter(options) {
65
54
  const notifications = houseNotifications(transport, 'credential');
66
55
  const tracked = new Map();
67
56
  const handed = new Map();
57
+ const rooms = roomStreams('credential');
58
+ const unreused = new Set();
59
+ let heldRevisions;
68
60
  let bounds;
69
61
  function declared() {
70
62
  if (bounds === undefined)
71
63
  throw new Error('no Discovery declared the bounds');
72
64
  return bounds;
73
65
  }
74
- function hand(locator, steps) {
75
- const held = handed.get(locator);
76
- const next = stepped(steps);
77
- if (!(next instanceof Promise)) {
78
- handed.set(locator, next);
79
- return;
80
- }
81
- return next.then((room) => {
82
- if (handed.get(locator) === held)
83
- handed.set(locator, room);
84
- else
85
- handed.delete(locator);
86
- });
87
- }
88
- async function fetchedPart(entry, continued, listed) {
89
- for (let attempt = 0; attempt < PART_ATTEMPTS; attempt += 1) {
90
- const answered = await transport.door(DOOR_BOOTSTRAP, {
91
- prefixes: [authorityRoot(entry.handle)],
92
- part: listed.part,
93
- ...(continued.held === undefined ? {} : { held: [continued.held] }),
94
- });
95
- const failure = classifyRead(answered.status, answered.body, entry.locator);
96
- if (failure !== null)
97
- return failure;
98
- const scope = await housePart(continued.room, answered.body, listed, 'credential');
99
- if (scope !== null)
100
- return scope;
101
- }
102
- return unverifiedPart(entry.locator);
103
- }
104
- async function partPage(asked, continued) {
105
- const { entry } = asked;
106
- const listed = continued.room.parts[continued.next];
107
- const sent = listed === undefined
108
- ? emptyScope(continued.room)
109
- : await fetchedPart(entry, continued, listed);
110
- if ('kind' in sent)
111
- return sent;
112
- const scope = await reused(sent, asked.held);
66
+ async function streamedPage(entry, token, held) {
67
+ const part = await rooms.part(entry, token);
68
+ if ('kind' in part)
69
+ return part;
70
+ const scope = await reused(part.scope, held);
113
71
  if (scope === null) {
114
- return asked.held === undefined
115
- ? UNCERTAIN_READ
116
- : bootstrapTogether({ entry, held: undefined });
72
+ unreused.add(entry.locator);
73
+ return UNCERTAIN_READ;
117
74
  }
118
- const next = continued.next + 1;
119
- const more = next < continued.room.parts.length;
120
- if (continued.next === 0 && !more)
121
- await hand(entry.locator, scopeHanded(scope));
75
+ if (part.first && part.ended)
76
+ handed.set(entry.locator, roomVersion(scope));
122
77
  else
123
78
  handed.delete(entry.locator);
124
79
  notifications.reach(entry.authority, scope);
125
- const seen = [
126
- ...continued.seen,
127
- ...entry.schemas.filter((schema) => scope.files.some((file) => file.path === schema)),
128
- ];
129
- const models = await partModels(scope, entry, new Set(seen), !more);
130
80
  return {
131
81
  ...(await stepped(bootstrapping(scope))),
132
- ...(models === undefined ? {} : { models }),
133
- ...(more ? { pageToken: JSON.stringify({ ...continued, next, seen }) } : {}),
82
+ ...(part.models === undefined ? {} : { models: part.models }),
83
+ ...(part.pageToken === undefined ? {} : { pageToken: part.pageToken }),
84
+ bytes: part.bytes,
134
85
  };
135
86
  }
87
+ async function openedRoom(entry, request) {
88
+ const reusing = unreused.delete(entry.locator) ? undefined : request.held;
89
+ const files = reusing === undefined
90
+ ? null
91
+ : await heldFiles(entry.authority, reusing, declared().max_held_files);
92
+ const answered = await transport.streamed(DOOR_BOOTSTRAP, {
93
+ prefixes: [authorityRoot(entry.handle)],
94
+ ...(files === null ? {} : { held: [files] }),
95
+ }, request.signal ?? new AbortController().signal);
96
+ if (answered.room === null)
97
+ return classifyDoor(answered.status, answered.body, entry.locator) ?? UNCERTAIN_READ;
98
+ return rooms.head(entry, answered.room, request.arriving, request.signal);
99
+ }
136
100
  async function enumeratedPage(ask, page) {
137
101
  const answer = await transport.door(DOOR_ENUMERATE, {
138
102
  prefixes: [authorityRoot(ask.entry.handle)],
@@ -162,18 +126,21 @@ export function createAgentsHouseAdapter(options) {
162
126
  const answer = await refreshFrom(view, ask.fromRoomVersion);
163
127
  if (answer.kind !== 'net-advancement')
164
128
  return answer;
165
- await hand(ask.entry.locator, enumeratedHanded(view, handed.get(ask.entry.locator)));
129
+ handed.set(ask.entry.locator, roomVersion(view));
166
130
  const models = await viewModels(view, ask.entry);
167
131
  return models === undefined ? answer : { ...answer, models };
168
132
  }
169
133
  async function streamed(entry, request, from) {
170
- const held = handed.get(entry.locator);
171
- if (held?.roomVersion !== request.fromRoomVersion)
134
+ if (handed.get(entry.locator) !== request.fromRoomVersion)
172
135
  return null;
173
- const advanced = await stepped(notifications.advance(entry, from, (path, revision) => held.revisions[path] === revision));
136
+ const asked = notifications.edited(entry, from);
137
+ const kept = asked.length === 0 || heldRevisions === undefined
138
+ ? new Map()
139
+ : await heldRevisions(entry.locator, asked);
140
+ const advanced = await stepped(notifications.advance(entry, from, (path, revision) => kept.get(path) === revision));
174
141
  if (advanced === null)
175
142
  return null;
176
- await hand(entry.locator, streamedHanded(held, advanced));
143
+ handed.set(entry.locator, advanced.page.roomVersion);
177
144
  const models = await streamedModels(advanced.schemas, entry, 'credential');
178
145
  return models === undefined ? advanced.page : { ...advanced.page, models };
179
146
  }
@@ -183,7 +150,7 @@ export function createAgentsHouseAdapter(options) {
183
150
  const at = logPosition(room.roomVersion);
184
151
  if (entry === undefined || at === null)
185
152
  return [];
186
- handed.set(room.locator, heldHanded(room));
153
+ handed.set(room.locator, room.roomVersion);
187
154
  notifications.reach(entry.authority, at);
188
155
  return [presented(entry.authority, at)];
189
156
  });
@@ -201,8 +168,9 @@ export function createAgentsHouseAdapter(options) {
201
168
  const held = handed.get(entry.locator);
202
169
  if (held === undefined)
203
170
  return outcome;
204
- const follows = followsVersion(held.roomVersion, outcome.roomVersion);
205
- await hand(entry.locator, acceptedHanded(held, outcome, follows ? outcome.roomVersion : held.roomVersion));
171
+ const follows = followsVersion(held, outcome.roomVersion);
172
+ if (follows)
173
+ handed.set(entry.locator, outcome.roomVersion);
206
174
  const at = logPosition(outcome.roomVersion);
207
175
  if (follows && at !== null)
208
176
  notifications.reach(entry.authority, at);
@@ -225,62 +193,6 @@ export function createAgentsHouseAdapter(options) {
225
193
  return result;
226
194
  return { ...result, at: { locator, roomVersion: roomVersion({ position, logEpoch }) } };
227
195
  }
228
- async function holding(asks) {
229
- const bound = Math.floor(declared().max_held_files / Math.max(1, asks.filter((ask) => ask.held !== undefined).length));
230
- const held = [];
231
- for (const ask of asks) {
232
- if (ask.held === undefined || bound === 0)
233
- continue;
234
- const paths = await sortedHeld(ask.held);
235
- const files = heldFiles(ask.entry.authority, ask.held, paths, bound);
236
- if (files !== null)
237
- held.push(files);
238
- }
239
- return held;
240
- }
241
- async function bootstrapped(asks, answer) {
242
- let open = asks.map((asked, ask) => ({ entry: asked.entry, asked, ask }));
243
- while (open.length > 0) {
244
- const unreached = [];
245
- for (const part of selections(open, declared().max_prefixes)) {
246
- const held = await holding(part.map(({ asked }) => asked));
247
- const answered = await transport.door(DOOR_BOOTSTRAP, {
248
- prefixes: part.map(({ entry }) => authorityRoot(entry.handle)),
249
- ...(held.length === 0 ? {} : { held }),
250
- });
251
- const classified = part.map(({ entry }) => classifyDoor(answered.status, answered.body, entry.locator));
252
- const parted = classified[0] === null ? parseParted(answered.body) : null;
253
- for (const [index, asked] of part.entries()) {
254
- const failure = classified[index];
255
- if (failure !== null && failure !== undefined) {
256
- answer(asked.ask, failure);
257
- continue;
258
- }
259
- if (parted === null) {
260
- answer(asked.ask, UNCERTAIN_READ);
261
- continue;
262
- }
263
- const room = parted.rooms.find((candidate) => candidate.anchor === asked.entry.authority);
264
- if (room === undefined && parted.next !== undefined) {
265
- unreached.push(asked);
266
- continue;
267
- }
268
- if (room === undefined) {
269
- answer(asked.ask, { kind: 'room-not-readable', locator: asked.entry.locator });
270
- continue;
271
- }
272
- const kept = held.find((files) => files.room === asked.entry.authority);
273
- answer(asked.ask, await partPage(asked.asked, {
274
- room,
275
- next: 0,
276
- seen: [],
277
- ...(kept === undefined ? {} : { held: kept }),
278
- }));
279
- }
280
- }
281
- open = unreached;
282
- }
283
- }
284
196
  function layered(asks) {
285
197
  const depths = new Map();
286
198
  const layers = [];
@@ -327,7 +239,6 @@ export function createAgentsHouseAdapter(options) {
327
239
  }
328
240
  return answers;
329
241
  }
330
- const bootstrapTogether = gatheredEach(bootstrapped);
331
242
  const enumerateTogether = gathered(enumerated);
332
243
  async function uploaded(head, changes, delta, bytes, entry, handed, keep) {
333
244
  const paths = batchPaths(changes);
@@ -342,7 +253,7 @@ export function createAgentsHouseAdapter(options) {
342
253
  };
343
254
  }
344
255
  const grant = parseGrant(minted.body);
345
- if (grant === null || grant.method !== 'POST')
256
+ if (grant === null)
346
257
  return { outcome: UNCERTAIN };
347
258
  const delivered = await transport.transfer({
348
259
  act: 'authored_batch_upload',
@@ -352,36 +263,31 @@ export function createAgentsHouseAdapter(options) {
352
263
  if (delivered.status !== 200)
353
264
  return { outcome: UNCERTAIN };
354
265
  const holding = parseGrant(delivered.body);
355
- if (holding === null || holding.method !== 'POST')
266
+ if (holding === null)
356
267
  return { outcome: UNCERTAIN };
357
268
  const upload = { url: holding.url, operation: holding.operation, bytes, sha256 };
358
269
  await keep(upload);
359
270
  return { body: { ...head, paths, upload, runtime: notifications.runtime } };
360
271
  }
361
- async function staged(answer, batch) {
272
+ async function staged(answer, { changeBatch: batch, file }) {
362
273
  const refusal = doorRefusal(answer.body);
363
274
  if (refusal?.code !== 'files_unstaged')
364
275
  return null;
365
- const grants = refusal.fields.upload;
366
- if (!Array.isArray(grants))
276
+ const uploads = refusal.fields.upload;
277
+ if (!Array.isArray(uploads))
367
278
  return false;
368
- for (const grant of grants) {
369
- const { url, operation, sha256 } = grant;
370
- const change = batch.changes.find((held) => held.kind === 'binary' && held.sha256 === sha256);
371
- if (typeof url !== 'string' || typeof operation !== 'string' || change === undefined)
279
+ for (const named of uploads) {
280
+ const upload = houseUpload(named);
281
+ const change = batch.changes.find((held) => held.kind === 'binary' && held.sha256 === named.sha256);
282
+ if (upload === null || change === undefined)
372
283
  return false;
373
- const delivered = await transport.transfer({
374
- act: 'binary_stage',
375
- url,
376
- body: change.blob,
377
- operation,
378
- });
379
- if (delivered.status !== 200)
284
+ const finished = await finishedUpload(transport, upload, await file(change.localId));
285
+ if (finished?.body?.staged !== true)
380
286
  return false;
381
287
  }
382
288
  return true;
383
289
  }
384
- async function submit(batch, head, changes, delta, bytes, entry, handed, keep, into) {
290
+ async function submit(request, head, changes, delta, bytes, entry, handed, keep, into) {
385
291
  const inline = { ...head, changes, runtime: notifications.runtime };
386
292
  const prepared = uploadable(inline, bytes, declared())
387
293
  ? await uploaded(head, changes, delta, bytes, entry, handed, keep)
@@ -389,11 +295,11 @@ export function createAgentsHouseAdapter(options) {
389
295
  if ('outcome' in prepared)
390
296
  return prepared.outcome;
391
297
  const answer = await transport.door(DOOR_BATCH, prepared.body);
392
- const stagedFiles = await staged(answer, batch);
298
+ const stagedFiles = await staged(answer, request);
393
299
  if (stagedFiles === false)
394
300
  return UNCERTAIN;
395
301
  const settled = stagedFiles === null ? answer : await transport.door(DOOR_BATCH, prepared.body);
396
- if (stagedFiles === true && (await staged(settled, batch)) !== null)
302
+ if (stagedFiles === true && (await staged(settled, request)) !== null)
397
303
  return UNCERTAIN;
398
304
  return stepped(mutationOutcome(settled.status, settled.body, entry.locator, entry.handle, into === undefined
399
305
  ? undefined
@@ -402,7 +308,7 @@ export function createAgentsHouseAdapter(options) {
402
308
  destination: { authority: into.authority, handle: into.handle },
403
309
  }));
404
310
  }
405
- function granted(answer, locator) {
311
+ function addressed(answer, locator) {
406
312
  const failure = classifyDoor(answer.status, answer.body, locator);
407
313
  if (failure !== null) {
408
314
  return failure.kind === 'scoped-refusal'
@@ -414,33 +320,61 @@ export function createAgentsHouseAdapter(options) {
414
320
  }
415
321
  : failure;
416
322
  }
417
- const grant = parseGrant(answer.body);
418
- const name = answer.body.name;
419
- if (grant === null || grant.method !== 'GET' || typeof name !== 'string') {
420
- return UNCERTAIN_READ;
421
- }
422
- return { kind: 'link', url: grant.url, name };
323
+ const address = parseFileAddress(answer.body);
324
+ return address === null ? UNCERTAIN_READ : { kind: 'address', ...address };
423
325
  }
424
- async function downloaded(answer, locator) {
425
- const link = granted(answer, locator);
426
- if (link.kind !== 'link')
427
- return link;
428
- const read = await transport.download(link.url);
429
- if (read.status !== 200 || read.blob === null)
326
+ function linked(answer, locator) {
327
+ const address = addressed(answer, locator);
328
+ return address.kind === 'address'
329
+ ? { kind: 'link', url: address.url, name: address.name, mediaType: address.mediaType }
330
+ : address;
331
+ }
332
+ function refusedAttach(answer, locator) {
333
+ const failure = classifyDoor(answer.status, answer.body, locator);
334
+ if (failure === null)
335
+ return null;
336
+ return failure.kind === 'scoped-refusal'
337
+ ? {
338
+ kind: 'rejected',
339
+ code: failure.code,
340
+ fields: failure.fields,
341
+ retryable: failure.retryable,
342
+ }
343
+ : failure;
344
+ }
345
+ async function downloaded(ask, locator) {
346
+ let address = addressed(await ask(), locator);
347
+ if (address.kind !== 'address')
348
+ return address;
349
+ let read = await transport.download(address.url);
350
+ if (read.status === EXPIRED_ADDRESS) {
351
+ address = addressed(await ask(), locator);
352
+ if (address.kind !== 'address')
353
+ return address;
354
+ read = await transport.download(address.url);
355
+ }
356
+ if (read.status !== 200 || read.body === null)
430
357
  return UNCERTAIN_READ;
431
- return { kind: 'binary', blob: read.blob };
358
+ return {
359
+ kind: 'binary',
360
+ body: read.body,
361
+ mediaType: address.mediaType,
362
+ sha256: address.sha256,
363
+ };
432
364
  }
433
- function pathGrant(request) {
365
+ function pathAddress(request) {
434
366
  const entry = authorityFor(request.locator);
435
367
  if (entry === undefined)
436
368
  return null;
437
- return transport.door(DOOR_FILES_GET, {
369
+ return () => transport.door(DOOR_FILES_GET, {
438
370
  room_ref: entry.authority,
439
371
  path: request.path,
440
372
  revision: request.revision,
441
373
  });
442
374
  }
443
375
  return {
376
+ roomTypes: HOUSE_ROOM_TYPES,
377
+ nameableRoomTypes: HOUSE_NAMEABLE_ROOM_TYPES,
444
378
  async authorize() {
445
379
  return options.authorize();
446
380
  },
@@ -488,11 +422,9 @@ export function createAgentsHouseAdapter(options) {
488
422
  const entry = authorityFor(request.locator);
489
423
  if (entry === undefined)
490
424
  return { kind: 'room-not-readable', locator: request.locator };
491
- const asked = { entry, held: request.held };
492
- if (request.pageToken !== undefined) {
493
- return partPage(asked, JSON.parse(request.pageToken));
494
- }
495
- return bootstrapTogether(asked);
425
+ return request.pageToken === undefined
426
+ ? openedRoom(entry, request)
427
+ : streamedPage(entry, request.pageToken, request.held);
496
428
  },
497
429
  async refresh(_authorization, request) {
498
430
  const entry = authorityFor(request.locator);
@@ -527,7 +459,7 @@ export function createAgentsHouseAdapter(options) {
527
459
  const delta = deltaBody(mapped.changes);
528
460
  const bytes = deltaBytes(delta);
529
461
  const handed = request.upload;
530
- const answer = (upload) => submit(batch, head, mapped.changes, delta, bytes, entry, upload, keep, into);
462
+ const answer = (upload) => submit(request, head, mapped.changes, delta, bytes, entry, upload, keep, into);
531
463
  const settle = (outcome) => into === undefined ? adopted(entry, outcome) : adoptedMove(entry, into, outcome);
532
464
  const outcome = await answer(handed);
533
465
  if (handed === undefined || !lapsedGrant(outcome))
@@ -550,36 +482,45 @@ export function createAgentsHouseAdapter(options) {
550
482
  });
551
483
  },
552
484
  async binary(_authorization, request) {
553
- if (request.kind === 'path') {
554
- const asked = pathGrant(request);
555
- if (asked === null)
556
- return { kind: 'room-not-readable', locator: request.locator };
557
- return downloaded(await asked, request.locator);
558
- }
559
- const referrer = houseReferrer(request.referrer, tracked);
560
- if (referrer === null) {
561
- return { kind: 'rejected', code: 'referrer_unknown', fields: {}, retryable: false };
562
- }
563
- const answer = await transport.door(DOOR_FILES_GET, {
564
- file: request.fileRef,
565
- referrer: referrer.referrer,
566
- });
567
- return downloaded(answer, referrer.locator);
485
+ const ask = pathAddress(request);
486
+ if (ask === null)
487
+ return { kind: 'room-not-readable', locator: request.locator };
488
+ return downloaded(ask, request.locator);
568
489
  },
569
490
  async link(_authorization, request) {
570
- const asked = pathGrant(request);
571
- if (asked === null)
491
+ const ask = pathAddress(request);
492
+ if (ask === null)
572
493
  return { kind: 'room-not-readable', locator: request.locator };
573
- return granted(await asked, request.locator);
494
+ return linked(await ask(), request.locator);
574
495
  },
575
- referrerScope(referrer) {
576
- const held = houseReferrer(referrer, tracked);
577
- if (held === null)
578
- return null;
579
- if (held.locator === '')
580
- return { kind: 'conversations' };
581
- const { path } = held.referrer;
582
- return { kind: 'room', locator: held.locator, ...(path === undefined ? {} : { path }) };
496
+ async attach(_authorization, request) {
497
+ const entry = authorityFor(request.locator);
498
+ if (entry === undefined)
499
+ return { kind: 'room-not-readable', locator: request.locator };
500
+ const declared = await transport.door(DOOR_FILES_ATTACH, {
501
+ room_ref: entry.authority,
502
+ name: request.name,
503
+ bytes: request.byteLength,
504
+ sha256: request.sha256,
505
+ media_type: request.mediaType.length > 0 ? request.mediaType : OCTET_STREAM,
506
+ });
507
+ const refused = refusedAttach(declared, request.locator);
508
+ if (refused !== null)
509
+ return refused;
510
+ const upload = houseUpload(declared.body?.upload);
511
+ if (upload === null)
512
+ return UNCERTAIN_READ;
513
+ const finished = await finishedUpload(transport, upload, request.blob);
514
+ if (finished === null)
515
+ return UNCERTAIN_READ;
516
+ const unfinished = refusedAttach(finished, request.locator);
517
+ if (unfinished !== null)
518
+ return unfinished;
519
+ const { path, revision } = (finished.body ?? {});
520
+ const root = `/rooms/${entry.handle}/`;
521
+ return typeof path === 'string' && path.startsWith(root) && typeof revision === 'string'
522
+ ? { kind: 'attached', path: path.slice(root.length), revision }
523
+ : UNCERTAIN_READ;
583
524
  },
584
525
  reached(locator, version, target) {
585
526
  return reachedVersion(version, target, authorityFor(locator)?.logEpoch);
@@ -593,7 +534,10 @@ export function createAgentsHouseAdapter(options) {
593
534
  roomStream: {
594
535
  hold: held,
595
536
  reopen: notifications.reopen,
596
- observe: notifications.observe,
537
+ observe(notify, receipts, revisions) {
538
+ heldRevisions = revisions;
539
+ return notifications.observe(notify, receipts);
540
+ },
597
541
  published(locator, roomVersion) {
598
542
  const at = logPosition(roomVersion);
599
543
  if (at !== null)
@@ -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)}]`;
@@ -22,20 +22,16 @@ export type HouseOperations = {
22
22
  write: readonly string[];
23
23
  delete: readonly string[];
24
24
  };
25
- export type HouseReadLevel = 'mcp' | 'online' | 'local';
26
- export type HouseModel = {
27
- root: string;
28
- paths: readonly string[];
29
- };
25
+ export type HouseAccessLevel = 'search' | 'open' | 'keep';
30
26
  export type HouseAuthority = LogPosition & {
31
27
  roomRef: string;
32
28
  roomHandle: string;
33
29
  name: string;
34
30
  schema: string;
35
- houseModel: HouseModel | null;
31
+ typedSelection: readonly string[] | null;
36
32
  managedReplication: 'admitted' | 'unavailable';
37
33
  protectedPaths: readonly string[];
38
- read: HouseReadLevel;
34
+ level: HouseAccessLevel;
39
35
  operations: HouseOperations;
40
36
  };
41
37
  export type HouseDiscoveryDocument = {
@@ -49,8 +45,7 @@ export type TrackedAuthority = LogPosition & {
49
45
  authority: string;
50
46
  handle: string;
51
47
  schema: string;
52
- houseModel: HouseModel | null;
53
- schemas: readonly string[];
48
+ typedSelection: readonly string[] | null;
54
49
  };
55
50
  export type HouseSiteAuthority = LogPosition & {
56
51
  roomRef: string;
@@ -67,7 +62,7 @@ export declare function siteTracked(document: HouseSiteDiscovery): TrackedAuthor
67
62
  export declare function trackedFrom(document: HouseDiscoveryDocument): TrackedAuthority[];
68
63
  export declare function providerLimits(bounds: HouseBounds): readonly ProviderLimit[];
69
64
  export declare function declaredRetention(bounds: HouseBounds): Retention;
70
- export declare function capabilities(actions: HouseDiscoveryDocument['actions'], rooms: readonly Pick<TrackedAuthority, 'authority' | 'houseModel'>[]): readonly Capability[];
65
+ export declare function capabilities(actions: HouseDiscoveryDocument['actions'], rooms: readonly Pick<TrackedAuthority, 'authority' | 'handle'>[]): readonly Capability[];
71
66
  export declare function siteCapabilities(): readonly Capability[];
72
67
  export declare function discoveredRoom(authority: HouseAuthority): DiscoveredRoom;
73
68
  export declare function mapDiscovery(document: Pick<HouseDiscoveryDocument, 'bounds'>, rooms: readonly DiscoveredRoom[], declared: readonly Capability[]): Discovery;
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}