@agentshouse/mdruntime-adapter 0.1.0-cae3b43168023 → 0.1.0-cb0bbc4ccacd0

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 (70) hide show
  1. package/README.md +2 -2
  2. package/dist/actions.d.ts +4 -72
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +7 -322
  5. package/dist/adapter.d.ts.map +1 -1
  6. package/dist/adapter.js +151 -337
  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 +22 -14
  14. package/dist/discovery.d.ts.map +1 -1
  15. package/dist/discovery.js +75 -55
  16. package/dist/history.d.ts +12 -0
  17. package/dist/history.d.ts.map +1 -0
  18. package/dist/history.js +92 -0
  19. package/dist/house-model.d.ts +641 -0
  20. package/dist/house-model.d.ts.map +1 -0
  21. package/dist/house-model.js +361 -0
  22. package/dist/index.d.ts +11 -3
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +10 -2
  25. package/dist/model.d.ts +8 -3
  26. package/dist/model.d.ts.map +1 -1
  27. package/dist/model.js +37 -34
  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 +25 -56
  32. package/dist/read.d.ts.map +1 -1
  33. package/dist/read.js +136 -298
  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 +20 -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 +4 -3
  41. package/dist/room-types.d.ts.map +1 -1
  42. package/dist/room-types.js +67 -10
  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 +84 -178
  48. package/dist/space-schema.d.ts +7 -0
  49. package/dist/space-schema.d.ts.map +1 -0
  50. package/dist/space-schema.js +18 -0
  51. package/dist/stream.d.ts +14 -14
  52. package/dist/stream.d.ts.map +1 -1
  53. package/dist/stream.js +169 -424
  54. package/dist/transport.d.ts +52 -39
  55. package/dist/transport.d.ts.map +1 -1
  56. package/dist/transport.js +54 -11
  57. package/dist/upload.d.ts +12 -0
  58. package/dist/upload.d.ts.map +1 -0
  59. package/dist/upload.js +63 -0
  60. package/dist/write.d.ts +6 -1
  61. package/dist/write.d.ts.map +1 -1
  62. package/dist/write.js +20 -38
  63. package/package.json +8 -4
  64. package/AGENTS.md +0 -309
  65. package/dist/gather.d.ts +0 -4
  66. package/dist/gather.d.ts.map +0 -1
  67. package/dist/gather.js +0 -35
  68. package/dist/referrer.d.ts +0 -9
  69. package/dist/referrer.d.ts.map +0 -1
  70. package/dist/referrer.js +0 -41
package/dist/read.js CHANGED
@@ -1,6 +1,6 @@
1
- import { patching, ROW_WEIGHT, stepped, } from '@agentshouse/mdruntime';
2
- import { checkedPayload, gunzipped, parsePart } from './part.js';
3
- import { DECIMAL, readPosition, roomVersion } from './version.js';
1
+ import { paced, patching, ROW_WEIGHT, } from '@agentshouse/mdruntime';
2
+ import { gunzipped } from './part.js';
3
+ import { readPosition, roomVersion } from './version.js';
4
4
  const REVISION_FILE = /^fr_([0-9a-z]+)\.[0-9a-z]+\.[0-9a-z]$/u;
5
5
  function fileOf(revision) {
6
6
  return REVISION_FILE.exec(revision)?.[1];
@@ -8,6 +8,7 @@ function fileOf(revision) {
8
8
  export function answering() {
9
9
  return {
10
10
  documents: new Map(),
11
+ facts: new Map(),
11
12
  revisions: new Map(),
12
13
  fileIds: new Map(),
13
14
  changes: new Map(),
@@ -25,6 +26,7 @@ export function revised(answer, path, revision) {
25
26
  }
26
27
  export function forgotten(answer, path) {
27
28
  answer.documents.delete(path);
29
+ answer.facts.delete(path);
28
30
  answer.revisions.delete(path);
29
31
  answer.fileIds.delete(path);
30
32
  answer.changes.delete(path);
@@ -53,6 +55,7 @@ export function* answered(answer) {
53
55
  const removals = yield* pathsOf(answer.removals);
54
56
  return {
55
57
  documents: yield* patching({}, answer.documents),
58
+ facts: yield* patching({}, answer.facts),
56
59
  revisions: yield* patching({}, answer.revisions),
57
60
  ...(answer.fileIds.size === 0 ? {} : { fileIds: yield* patching({}, answer.fileIds) }),
58
61
  changes: yield* patching({}, answer.changes),
@@ -98,10 +101,10 @@ export function parseFileAddress(body) {
98
101
  function changeAuthor(value) {
99
102
  if (typeof value !== 'object' || value === null)
100
103
  return null;
101
- const { user, site, inbox, name } = value;
104
+ const { user, site, inbox, app, name } = value;
102
105
  if (typeof name !== 'string')
103
106
  return null;
104
- const named = [user, site, inbox].filter((id) => id !== undefined);
107
+ const named = [user, site, inbox, app].filter((id) => id !== undefined);
105
108
  if (named.length !== 1)
106
109
  return null;
107
110
  if (typeof user === 'string')
@@ -110,6 +113,8 @@ function changeAuthor(value) {
110
113
  return { kind: 'site', id: site, name };
111
114
  if (typeof inbox === 'string')
112
115
  return { kind: 'inbox', id: inbox, name };
116
+ if (typeof app === 'string')
117
+ return { kind: 'app', id: app, name };
113
118
  return null;
114
119
  }
115
120
  export function headChange(held) {
@@ -126,19 +131,22 @@ function headed(head) {
126
131
  return head === undefined ? {} : { head };
127
132
  }
128
133
  export function binaryFileOf(held) {
129
- if (held.file === undefined)
134
+ if (held.media_type === undefined)
130
135
  return undefined;
131
- const { file, bytes, media_type: mediaType, sha256 } = held;
132
- if (typeof file !== 'string' ||
133
- typeof bytes !== 'number' ||
134
- typeof mediaType !== 'string' ||
135
- typeof sha256 !== 'string')
136
+ const { bytes, media_type: mediaType, sha256 } = held;
137
+ if (typeof bytes !== 'number' || typeof mediaType !== 'string' || typeof sha256 !== 'string')
136
138
  return null;
137
- return { fileRef: file, byteLength: bytes, mediaType, sha256 };
139
+ return { byteLength: bytes, mediaType, sha256 };
138
140
  }
139
141
  function binaried(binary) {
140
142
  return binary === undefined ? {} : { binary };
141
143
  }
144
+ export function carriedFacts(held) {
145
+ return held.facts === undefined ? {} : { facts: held.facts };
146
+ }
147
+ function carriedSpace(held) {
148
+ return typeof held.space === 'string' ? { space: held.space } : {};
149
+ }
142
150
  function parseFile(value, mode) {
143
151
  if (typeof value !== 'object' || value === null)
144
152
  return null;
@@ -158,6 +166,7 @@ function parseFile(value, mode) {
158
166
  version: file.sha256,
159
167
  ...headed(head),
160
168
  ...binaried(binary),
169
+ ...carriedFacts(file),
161
170
  };
162
171
  }
163
172
  if (typeof file.revision !== 'string')
@@ -169,15 +178,33 @@ function parseFile(value, mode) {
169
178
  ...(typeof file.sha256 === 'string' ? { sha256: file.sha256 } : {}),
170
179
  ...headed(head),
171
180
  ...binaried(binary),
181
+ ...carriedFacts(file),
182
+ ...carriedSpace(file),
172
183
  };
173
184
  }
174
- function parseRoomParts(value) {
185
+ function parseModels(value, mode) {
186
+ if (!Array.isArray(value))
187
+ return null;
188
+ const files = [];
189
+ const contents = [];
190
+ for (const entry of value) {
191
+ const file = parseFile(entry, mode);
192
+ const { content } = entry;
193
+ if (file === null || typeof content !== 'string')
194
+ return null;
195
+ files.push(file);
196
+ contents.push({ path: file.path, content });
197
+ }
198
+ return { files, contents };
199
+ }
200
+ function parseRoomHead(value, mode) {
175
201
  if (typeof value !== 'object' || value === null)
176
202
  return null;
177
203
  const held = value;
178
204
  if (typeof held.manifest !== 'object' || held.manifest === null)
179
205
  return null;
180
- if (!Array.isArray(held.parts))
206
+ const models = parseModels(held.models, mode);
207
+ if (models === null)
181
208
  return null;
182
209
  const manifest = held.manifest;
183
210
  if (manifest.scope !== 'room')
@@ -187,36 +214,36 @@ function parseRoomParts(value) {
187
214
  return null;
188
215
  if (typeof manifest.room_handle !== 'string' || manifest.room_handle.length === 0)
189
216
  return null;
190
- const parts = [];
191
- for (const entry of held.parts) {
192
- const part = parsePart(entry);
193
- if (part === null)
194
- return null;
195
- parts.push(part);
196
- }
197
- return { anchor: manifest.anchor, ...at, parts };
217
+ return { anchor: manifest.anchor, ...at, models };
198
218
  }
199
- export function parseParted(body) {
200
- if (typeof body !== 'object' || body === null)
201
- return null;
202
- if (!('scopes' in body) || !Array.isArray(body.scopes))
203
- return null;
204
- const rooms = [];
205
- for (const entry of body.scopes) {
206
- const room = parseRoomParts(entry);
207
- if (room === null)
208
- return null;
209
- rooms.push(room);
219
+ export async function roomHead(payload, mode) {
220
+ let text = '';
221
+ try {
222
+ for await (const chunk of gunzipped(payload))
223
+ text += chunk;
224
+ return text.endsWith('\n') && text.indexOf('\n') === text.length - 1
225
+ ? parseRoomHead(JSON.parse(text), mode)
226
+ : null;
210
227
  }
211
- if (!('next' in body) || body.next === undefined)
212
- return { rooms };
213
- const next = body.next;
214
- if (typeof next !== 'object' || next === null || typeof next.room !== 'string')
228
+ catch {
215
229
  return null;
216
- return { rooms, next: next.room };
230
+ }
231
+ }
232
+ export function manifested(room, pageToken, models) {
233
+ return {
234
+ kind: 'bootstrap',
235
+ roomVersion: roomVersion(room),
236
+ documents: {},
237
+ facts: {},
238
+ revisions: {},
239
+ changes: {},
240
+ binaryFiles: {},
241
+ pageToken,
242
+ ...(models === undefined ? {} : { models }),
243
+ };
217
244
  }
218
- export function parseSiteParted(body) {
219
- return parseRoomParts(body);
245
+ export function modelScope(room) {
246
+ return { ...emptyScope(room), files: room.models.files, contents: room.models.contents };
220
247
  }
221
248
  export function emptyScope(room) {
222
249
  return {
@@ -227,242 +254,75 @@ export function emptyScope(room) {
227
254
  contents: [],
228
255
  };
229
256
  }
230
- function* partLines(text, mode) {
231
- const files = [];
232
- const contents = [];
233
- const folders = [];
234
- let start = 0;
235
- while (start < text.length) {
236
- const end = text.indexOf('\n', start);
237
- if (end === -1)
238
- return null;
239
- let entry;
240
- try {
241
- entry = JSON.parse(text.slice(start, end));
242
- }
243
- catch {
244
- return null;
245
- }
246
- start = end + 1;
247
- if (folderLine(entry)) {
248
- folders.push(entry.folder);
249
- yield ROW_WEIGHT;
250
- continue;
251
- }
252
- const file = parseFile(entry, mode);
253
- if (file === null)
254
- return null;
255
- files.push(file);
256
- const { content } = entry;
257
- if (typeof content === 'string')
258
- contents.push({ path: file.path, content });
259
- else if (content !== undefined)
260
- return null;
261
- yield ROW_WEIGHT;
257
+ function partLine(line, mode, read) {
258
+ if (read.ended)
259
+ return false;
260
+ let entry;
261
+ try {
262
+ entry = JSON.parse(line);
262
263
  }
263
- return { files, contents, folders };
264
- }
265
- function folderLine(entry) {
266
- if (typeof entry !== 'object' || entry === null || !('folder' in entry))
264
+ catch {
267
265
  return false;
268
- return typeof entry.folder === 'string' && Object.keys(entry).length === 1;
269
- }
270
- export async function housePart(room, body, listed, mode) {
271
- const payload = await checkedPayload(body, listed);
272
- if (payload === null)
273
- return null;
274
- const text = await gunzipped(payload);
275
- const read = text === null ? null : await stepped(partLines(text, mode));
276
- return read === null ? { kind: 'transport-uncertainty' } : { ...emptyScope(room), ...read };
277
- }
278
- function folderChange(value) {
279
- if (typeof value !== 'object' || value === null)
280
- return null;
281
- const { path, folder, removed, ...rest } = value;
282
- return typeof path === 'string' &&
283
- folder === true &&
284
- (removed === undefined || removed === true) &&
285
- Object.keys(rest).length === 0
286
- ? { path, removed: removed === true }
287
- : null;
288
- }
289
- function parseChange(value, mode) {
290
- if (typeof value !== 'object' || value === null)
291
- return null;
292
- const held = value;
293
- if (typeof held.path !== 'string')
294
- return null;
295
- if (held.removed === true)
296
- return { path: held.path, removed: true };
297
- const head = headChange(held);
298
- const binary = binaryFileOf(held);
299
- if (head === null || binary === null)
300
- return null;
301
- if (binary !== undefined) {
302
- if (mode === 'credential' && typeof held.revision !== 'string')
303
- return null;
304
- const revision = typeof held.revision === 'string' ? held.revision : binary.sha256;
305
- return { path: held.path, binary, revision, version: revision, ...headed(head) };
306
266
  }
307
- if (mode === 'site') {
308
- if (typeof held.content !== 'string' || typeof held.sha256 !== 'string')
309
- return null;
310
- return {
311
- path: held.path,
312
- content: held.content,
313
- revision: undefined,
314
- version: held.sha256,
315
- ...headed(head),
316
- };
267
+ if (endLine(entry)) {
268
+ read.ended = true;
269
+ return true;
317
270
  }
318
- if (typeof held.content === 'string' && typeof held.revision === 'string') {
319
- return {
320
- path: held.path,
321
- content: held.content,
322
- revision: held.revision,
323
- version: held.revision,
324
- ...headed(head),
325
- };
271
+ if (folderLine(entry)) {
272
+ read.folders.push(entry.folder);
273
+ return true;
326
274
  }
327
- return null;
328
- }
329
- export function parseEnumeration(body, mode) {
330
- if (typeof body !== 'object' || body === null)
331
- return null;
332
- if (!('authorities' in body) || !Array.isArray(body.authorities))
333
- return null;
334
- const authorities = [];
335
- for (const entry of body.authorities) {
336
- if (typeof entry !== 'object' || entry === null)
337
- return null;
338
- const held = entry;
339
- const at = readPosition(held);
340
- if (typeof held.authority !== 'string' || at === null)
341
- return null;
342
- if (!Array.isArray(held.changes))
343
- return null;
344
- const changes = [];
345
- const folders = [];
346
- for (const change of held.changes) {
347
- const folder = folderChange(change);
348
- if (folder !== null) {
349
- folders.push(folder);
350
- continue;
351
- }
352
- const mapped = parseChange(change, mode);
353
- if (mapped === null)
275
+ const file = parseFile(entry, mode);
276
+ if (file === null)
277
+ return false;
278
+ read.files.push(file);
279
+ const { content } = entry;
280
+ if (typeof content === 'string')
281
+ read.contents.push({ path: file.path, content });
282
+ else if (content !== undefined)
283
+ return false;
284
+ return true;
285
+ }
286
+ async function partRead(chunks, mode) {
287
+ const read = { files: [], contents: [], folders: [], ended: false };
288
+ const pace = paced();
289
+ const unfinished = [];
290
+ for (let chunk = await chunks.read(); chunk.done !== true; chunk = await chunks.read()) {
291
+ const text = chunk.value;
292
+ let start = 0;
293
+ for (let end = text.indexOf('\n'); end !== -1; end = text.indexOf('\n', start)) {
294
+ const piece = text.slice(start, end);
295
+ const line = unfinished.length === 0 ? piece : unfinished.splice(0).join('') + piece;
296
+ if (!partLine(line, mode, read)) {
297
+ await chunks.cancel();
354
298
  return null;
355
- changes.push(mapped);
299
+ }
300
+ start = end + 1;
301
+ const due = pace(line.length + ROW_WEIGHT);
302
+ if (due instanceof Promise)
303
+ await due;
356
304
  }
357
- const next = held.next === undefined ? undefined : readPage(held.next);
358
- if (next === null)
359
- return null;
360
- authorities.push({
361
- authority: held.authority,
362
- ...at,
363
- changes,
364
- ...(folders.length === 0 ? {} : { folders }),
365
- ...(next === undefined ? {} : { next }),
366
- });
305
+ if (start < text.length)
306
+ unfinished.push(text.slice(start));
367
307
  }
368
- return { authorities };
308
+ return unfinished.length === 0 ? read : null;
369
309
  }
370
- function readPage(held) {
371
- if (typeof held !== 'object' || held === null)
372
- return null;
373
- const { after, through, read } = held;
374
- if (typeof after !== 'string' || !DECIMAL.test(after))
375
- return null;
376
- if (typeof through !== 'string' || !DECIMAL.test(through))
377
- return null;
378
- if (typeof read !== 'number' || !Number.isSafeInteger(read) || read < 0)
379
- return null;
380
- return { after, through, read };
381
- }
382
- function advances(asked, next) {
383
- const moved = BigInt(next.through) - BigInt(asked.through);
384
- return moved > 0n || (moved === 0n && next.after === asked.after && next.read > asked.read);
385
- }
386
- export async function wholeView(first, more) {
387
- const changes = new Map(first.changes.map((change) => [change.path, change]));
388
- const folders = new Map((first.folders ?? []).map((folder) => [folder.path, folder]));
389
- let view = first;
390
- while (view.next !== undefined) {
391
- const asked = view.next;
392
- const page = await more(asked);
393
- if ('kind' in page)
394
- return page;
395
- if (page.position !== asked.through ||
396
- page.logEpoch !== first.logEpoch ||
397
- (page.next !== undefined && !advances(asked, page.next))) {
398
- return { kind: 'transport-uncertainty' };
399
- }
400
- for (const change of page.changes) {
401
- changes.delete(change.path);
402
- changes.set(change.path, change);
403
- }
404
- for (const folder of page.folders ?? []) {
405
- folders.delete(folder.path);
406
- folders.set(folder.path, folder);
407
- }
408
- view = page;
409
- }
410
- return {
411
- authority: first.authority,
412
- position: view.position,
413
- logEpoch: first.logEpoch,
414
- changes: [...changes.values()],
415
- ...(folders.size === 0 ? {} : { folders: [...folders.values()] }),
416
- };
310
+ function endLine(entry) {
311
+ if (typeof entry !== 'object' || entry === null || !('end' in entry))
312
+ return false;
313
+ return entry.end === true && Object.keys(entry).length === 1;
417
314
  }
418
- export function* advancedScope(scope, view) {
419
- const files = new Map();
420
- for (const file of scope.files) {
421
- files.set(file.path, file);
422
- yield ROW_WEIGHT;
423
- }
424
- const contents = new Map();
425
- for (const entry of scope.contents) {
426
- contents.set(entry.path, entry.content);
427
- yield ROW_WEIGHT;
428
- }
429
- for (const change of view.changes) {
430
- files.delete(change.path);
431
- contents.delete(change.path);
432
- yield ROW_WEIGHT;
433
- if ('removed' in change)
434
- continue;
435
- files.set(change.path, {
436
- path: change.path,
437
- revision: change.revision,
438
- version: change.version,
439
- ...headed(change.head),
440
- ...('binary' in change ? { binary: change.binary } : {}),
441
- });
442
- if ('content' in change)
443
- contents.set(change.path, change.content);
444
- }
445
- const kept = [];
446
- for (const [path, content] of contents) {
447
- kept.push({ path, content });
448
- yield ROW_WEIGHT;
449
- }
450
- const folders = new Set(scope.folders);
451
- for (const folder of view.folders ?? []) {
452
- if (folder.removed)
453
- folders.delete(folder.path);
454
- else
455
- folders.add(folder.path);
456
- yield ROW_WEIGHT;
457
- }
458
- return {
459
- ...scope,
460
- position: view.position,
461
- logEpoch: view.logEpoch,
462
- files: [...files.values()],
463
- contents: kept,
464
- ...(folders.size === 0 ? {} : { folders: [...folders] }),
465
- };
315
+ function folderLine(entry) {
316
+ if (typeof entry !== 'object' || entry === null || !('folder' in entry))
317
+ return false;
318
+ return typeof entry.folder === 'string' && Object.keys(entry).length === 1;
319
+ }
320
+ export async function housePart(room, payload, mode) {
321
+ const read = await partRead(gunzipped(payload).getReader(), mode).catch(() => null);
322
+ if (read === null)
323
+ return { kind: 'transport-uncertainty' };
324
+ const { ended, ...scope } = read;
325
+ return { scope: { ...emptyScope(room), ...scope }, ended };
466
326
  }
467
327
  export function* bootstrapping(scope) {
468
328
  const contents = new Map();
@@ -473,6 +333,8 @@ export function* bootstrapping(scope) {
473
333
  const answer = answering();
474
334
  for (const file of scope.files) {
475
335
  yield ROW_WEIGHT;
336
+ if (file.space !== undefined)
337
+ continue;
476
338
  if (file.head !== undefined)
477
339
  answer.changes.set(file.path, file.head);
478
340
  const content = contents.get(file.path);
@@ -480,6 +342,8 @@ export function* bootstrapping(scope) {
480
342
  answer.binaryFiles.set(file.path, file.binary);
481
343
  else if (content !== undefined)
482
344
  answer.documents.set(file.path, content);
345
+ if (file.binary === undefined && file.facts !== undefined)
346
+ answer.facts.set(file.path, file.facts);
483
347
  if (file.revision !== undefined)
484
348
  revised(answer, file.path, file.revision);
485
349
  }
@@ -495,36 +359,10 @@ export function schemaOf(scope, schema) {
495
359
  const content = scope.contents.find((entry) => entry.path === schema);
496
360
  return content === undefined
497
361
  ? null
498
- : { schema: content.content, version: file.version, revision: file.revision ?? null };
499
- }
500
- export function viewOf(enumeration, tracked) {
501
- return enumeration.authorities.find((entry) => entry.authority === tracked.authority);
502
- }
503
- function* refreshing(view, fromRoomVersion) {
504
- if (roomVersion(view) === fromRoomVersion)
505
- return { kind: 'still-current' };
506
- const answer = answering();
507
- for (const change of view.changes) {
508
- yield ROW_WEIGHT;
509
- if ('removed' in change) {
510
- answer.removals.add(change.path);
511
- continue;
512
- }
513
- if ('content' in change)
514
- answer.documents.set(change.path, change.content);
515
- else
516
- answer.binaryFiles.set(change.path, change.binary);
517
- if (change.head !== undefined)
518
- answer.changes.set(change.path, change.head);
519
- if (change.revision !== undefined)
520
- revised(answer, change.path, change.revision);
521
- }
522
- for (const folder of view.folders ?? []) {
523
- yield ROW_WEIGHT;
524
- folded(answer, folder.path, folder.removed);
525
- }
526
- return { kind: 'net-advancement', roomVersion: roomVersion(view), ...(yield* answered(answer)) };
527
- }
528
- export async function refreshFrom(view, fromRoomVersion) {
529
- return stepped(refreshing(view, fromRoomVersion));
362
+ : {
363
+ schema: content.content,
364
+ version: file.version,
365
+ revision: file.revision ?? null,
366
+ ...(file.space === undefined ? {} : { space: file.space }),
367
+ };
530
368
  }
package/dist/refusal.d.ts CHANGED
@@ -2,8 +2,5 @@ import type { AdapterFailure, DiscoverResult, ProviderRefusal, ScopedRefusal } f
2
2
  export declare function doorRefusal(body: unknown): ProviderRefusal | null;
3
3
  export declare function scopedRefusal(locator: string, scope: ScopedRefusal['scope'], refusal: ProviderRefusal): ScopedRefusal;
4
4
  export declare function classifyDoor(status: number, body: unknown, locator: string): AdapterFailure | null;
5
- export declare function classifyRead(status: number, body: unknown, locator: string): AdapterFailure | {
6
- kind: 'beyond-horizon';
7
- } | null;
8
5
  export declare function discoveryFailure(status: number, body: unknown): DiscoverResult | null;
9
6
  //# sourceMappingURL=refusal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"refusal.d.ts","sourceRoot":"","sources":["../src/refusal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,eAAe,EACf,aAAa,EACd,MAAM,wBAAwB,CAAC;AAEhC,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAOjE;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAC7B,OAAO,EAAE,eAAe,GACvB,aAAa,CAEf;AAqBD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,MAAM,GACd,cAAc,GAAG,IAAI,CAMvB;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,MAAM,GACd,cAAc,GAAG;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAAG,IAAI,CAGpD;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAQrF"}
1
+ {"version":3,"file":"refusal.d.ts","sourceRoot":"","sources":["../src/refusal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,eAAe,EACf,aAAa,EACd,MAAM,wBAAwB,CAAC;AAEhC,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAOjE;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAC7B,OAAO,EAAE,eAAe,GACvB,aAAa,CAEf;AAqBD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,MAAM,GACd,cAAc,GAAG,IAAI,CAMvB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAQrF"}
package/dist/refusal.js CHANGED
@@ -39,11 +39,6 @@ export function classifyDoor(status, body, locator) {
39
39
  return scopedRefusal(locator, failure.scope, failure.refusal);
40
40
  return failure;
41
41
  }
42
- export function classifyRead(status, body, locator) {
43
- if (doorRefusal(body)?.code === 'expired')
44
- return { kind: 'beyond-horizon' };
45
- return classifyDoor(status, body, locator);
46
- }
47
42
  export function discoveryFailure(status, body) {
48
43
  const failure = doorFailure(status, body);
49
44
  if (failure === null)
@@ -0,0 +1,20 @@
1
+ import type { BootstrapResult, RoomModels } from '@agentshouse/mdruntime';
2
+ import type { TrackedAuthority } from './discovery.js';
3
+ import { type HouseScope } from './read.js';
4
+ import type { SpaceSchemas } from './space-schema.js';
5
+ import type { HouseMode } from './transport.js';
6
+ export type StreamedPart = {
7
+ readonly scope: HouseScope;
8
+ readonly first: boolean;
9
+ readonly ended: boolean;
10
+ readonly models: RoomModels | undefined;
11
+ readonly pageToken: string | undefined;
12
+ readonly bytes: number;
13
+ };
14
+ export declare function roomStreams(mode: HouseMode, spaces: SpaceSchemas): {
15
+ head: (entry: TrackedAuthority, room: ReadableStream<Uint8Array>, arriving: ((bytes: number) => void) | undefined, signal: AbortSignal | undefined) => Promise<BootstrapResult>;
16
+ part: (entry: TrackedAuthority, token: string) => Promise<StreamedPart | Exclude<BootstrapResult, {
17
+ kind: 'bootstrap';
18
+ }>>;
19
+ };
20
+ //# sourceMappingURL=room-stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-stream.d.ts","sourceRoot":"","sources":["../src/room-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGvD,OAAO,EAAuD,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AACjG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAYhD,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY;kBAKtD,gBAAgB,QACjB,cAAc,CAAC,UAAU,CAAC,YACtB,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,UACvC,WAAW,GAAG,SAAS,KAC9B,OAAO,CAAC,eAAe,CAAC;kBAelB,gBAAgB,SAChB,MAAM,KACZ,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,eAAe,EAAE;QAAE,IAAI,EAAE,WAAW,CAAA;KAAE,CAAC,CAAC;EAkC3E"}
@@ -0,0 +1,57 @@
1
+ import { manifestedModels, partModels } from './model.js';
2
+ import { roomFrames } from './part.js';
3
+ import { housePart, manifested, roomHead } from './read.js';
4
+ const UNCERTAIN = { kind: 'transport-uncertainty' };
5
+ export function roomStreams(mode, spaces) {
6
+ const open = new Map();
7
+ let opened = 0;
8
+ async function head(entry, room, arriving, signal) {
9
+ const frames = roomFrames(room, arriving, signal);
10
+ const first = await frames();
11
+ if (first.kind !== 'frame')
12
+ return UNCERTAIN;
13
+ const held = await roomHead(first.payload, mode);
14
+ if (held === null || held.anchor !== entry.authority)
15
+ return UNCERTAIN;
16
+ const { models, seen } = await manifestedModels(held, entry, spaces);
17
+ opened += 1;
18
+ const id = String(opened);
19
+ open.set(id, { entry, head: held, frames, next: 1, seen });
20
+ signal?.addEventListener('abort', () => open.delete(id), { once: true });
21
+ return { ...manifested(held, `${id}:1`, models), bytes: first.bytes };
22
+ }
23
+ async function part(entry, token) {
24
+ const [id = '', at = ''] = token.split(':');
25
+ const room = open.get(id);
26
+ if (room === undefined || room.entry.locator !== entry.locator || String(room.next) !== at)
27
+ return UNCERTAIN;
28
+ const frame = await room.frames();
29
+ if (frame.kind !== 'frame') {
30
+ open.delete(id);
31
+ return UNCERTAIN;
32
+ }
33
+ const read = await housePart(room.head, frame.payload, mode);
34
+ if ('kind' in read) {
35
+ open.delete(id);
36
+ return read;
37
+ }
38
+ const { scope, ended } = read;
39
+ const first = room.next === 1;
40
+ room.next += 1;
41
+ room.seen = [
42
+ ...room.seen,
43
+ ...(scope.files.some((file) => file.path === entry.schema) ? [entry.schema] : []),
44
+ ];
45
+ if (ended)
46
+ open.delete(id);
47
+ return {
48
+ scope,
49
+ first,
50
+ ended,
51
+ models: await partModels(scope, entry, new Set(room.seen), ended),
52
+ pageToken: ended ? undefined : `${id}:${room.next}`,
53
+ bytes: frame.bytes,
54
+ };
55
+ }
56
+ return { head, part };
57
+ }