@agentshouse/mdruntime-adapter 0.1.0-cd028205a5103 → 0.1.0-cd23c45caa798

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 (53) hide show
  1. package/AGENTS.md +285 -225
  2. package/dist/actions.d.ts +68 -1
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +196 -193
  5. package/dist/adapter.d.ts +1 -0
  6. package/dist/adapter.d.ts.map +1 -1
  7. package/dist/adapter.js +384 -103
  8. package/dist/discovery.d.ts +7 -4
  9. package/dist/discovery.d.ts.map +1 -1
  10. package/dist/discovery.js +46 -13
  11. package/dist/gather.d.ts +2 -1
  12. package/dist/gather.d.ts.map +1 -1
  13. package/dist/gather.js +15 -20
  14. package/dist/handed.d.ts +15 -0
  15. package/dist/handed.d.ts.map +1 -0
  16. package/dist/handed.js +45 -0
  17. package/dist/index.d.ts +2 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -0
  20. package/dist/model.d.ts +1 -1
  21. package/dist/model.d.ts.map +1 -1
  22. package/dist/model.js +6 -2
  23. package/dist/part.d.ts +13 -0
  24. package/dist/part.d.ts.map +1 -0
  25. package/dist/part.js +80 -0
  26. package/dist/read.d.ts +53 -16
  27. package/dist/read.d.ts.map +1 -1
  28. package/dist/read.js +265 -147
  29. package/dist/referrer.d.ts +7 -0
  30. package/dist/referrer.d.ts.map +1 -0
  31. package/dist/referrer.js +33 -0
  32. package/dist/refusal.d.ts +2 -5
  33. package/dist/refusal.d.ts.map +1 -1
  34. package/dist/refusal.js +6 -9
  35. package/dist/site.d.ts +1 -1
  36. package/dist/site.d.ts.map +1 -1
  37. package/dist/site.js +175 -58
  38. package/dist/stream.d.ts +4 -4
  39. package/dist/stream.d.ts.map +1 -1
  40. package/dist/stream.js +340 -42
  41. package/dist/transport.d.ts +64 -10
  42. package/dist/transport.d.ts.map +1 -1
  43. package/dist/transport.js +3 -0
  44. package/dist/version.d.ts +1 -0
  45. package/dist/version.d.ts.map +1 -1
  46. package/dist/version.js +1 -1
  47. package/dist/write.d.ts +14 -9
  48. package/dist/write.d.ts.map +1 -1
  49. package/dist/write.js +156 -37
  50. package/package.json +3 -4
  51. package/dist/links.d.ts +0 -20
  52. package/dist/links.d.ts.map +0 -1
  53. package/dist/links.js +0 -104
package/dist/read.js CHANGED
@@ -1,13 +1,52 @@
1
- import { readPosition, roomVersion } from './version.js';
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';
4
+ const REVISION_FILE = /^fr_([0-9a-z]+)\.[0-9a-z]+\.[0-9a-z]$/u;
5
+ function fileOf(revision) {
6
+ return REVISION_FILE.exec(revision)?.[1];
7
+ }
8
+ export function answering() {
9
+ return {
10
+ documents: new Map(),
11
+ revisions: new Map(),
12
+ fileIds: new Map(),
13
+ changes: new Map(),
14
+ binaryFiles: new Map(),
15
+ removals: new Set(),
16
+ };
17
+ }
18
+ export function revised(answer, path, revision) {
19
+ answer.revisions.set(path, revision);
20
+ const file = fileOf(revision);
21
+ if (file !== undefined)
22
+ answer.fileIds.set(path, file);
23
+ }
24
+ export function forgotten(answer, path) {
25
+ answer.documents.delete(path);
26
+ answer.revisions.delete(path);
27
+ answer.fileIds.delete(path);
28
+ answer.changes.delete(path);
29
+ answer.binaryFiles.delete(path);
30
+ answer.removals.delete(path);
31
+ }
32
+ export function* answered(answer) {
33
+ const removals = [];
34
+ for (const path of answer.removals) {
35
+ removals.push(path);
36
+ yield ROW_WEIGHT;
37
+ }
38
+ return {
39
+ documents: yield* patching({}, answer.documents),
40
+ revisions: yield* patching({}, answer.revisions),
41
+ ...(answer.fileIds.size === 0 ? {} : { fileIds: yield* patching({}, answer.fileIds) }),
42
+ changes: yield* patching({}, answer.changes),
43
+ binaryFiles: yield* patching({}, answer.binaryFiles),
44
+ removals,
45
+ };
46
+ }
2
47
  export function authorityRoot(handle) {
3
48
  return `/rooms/${handle}`;
4
49
  }
5
- export function contentPrefixes(tracked) {
6
- return [
7
- authorityRoot(tracked.handle),
8
- ...tracked.schemas.map((schema) => schemaPath(tracked.handle, schema)),
9
- ];
10
- }
11
50
  export function schemaPath(handle, schema) {
12
51
  return `${authorityRoot(handle)}/${schema}`;
13
52
  }
@@ -51,32 +90,19 @@ export function headChange(held) {
51
90
  function headed(head) {
52
91
  return head === undefined ? {} : { head };
53
92
  }
54
- function parseOriginal(value) {
55
- if (typeof value !== 'object' || value === null)
56
- return null;
57
- const { attachment, name, bytes, media_type: mediaType } = value;
58
- if (typeof attachment !== 'string' || typeof name !== 'string')
59
- return null;
60
- if (typeof bytes !== 'number' || !Number.isSafeInteger(bytes) || bytes < 0)
61
- return null;
62
- if (mediaType !== null && typeof mediaType !== 'string')
63
- return null;
64
- return { reference: attachment, name, byteLength: bytes, mediaType, entry: value };
65
- }
66
- export function parseOriginals(value) {
67
- if (!Array.isArray(value))
93
+ export function binaryFileOf(held) {
94
+ if (held.file === undefined)
95
+ return undefined;
96
+ const { file, bytes, media_type: mediaType, sha256 } = held;
97
+ if (typeof file !== 'string' ||
98
+ typeof bytes !== 'number' ||
99
+ typeof mediaType !== 'string' ||
100
+ typeof sha256 !== 'string')
68
101
  return null;
69
- const attachments = [];
70
- for (const entry of value) {
71
- const attachment = parseOriginal(entry);
72
- if (attachment === null)
73
- return null;
74
- attachments.push(attachment);
75
- }
76
- return attachments;
102
+ return { fileRef: file, byteLength: bytes, mediaType, sha256 };
77
103
  }
78
- function declared(attachments) {
79
- return attachments === undefined ? {} : { attachments };
104
+ function binaried(binary) {
105
+ return binary === undefined ? {} : { binary };
80
106
  }
81
107
  function parseFile(value, mode) {
82
108
  if (typeof value !== 'object' || value === null)
@@ -85,24 +111,38 @@ function parseFile(value, mode) {
85
111
  if (typeof file.path !== 'string')
86
112
  return null;
87
113
  const head = headChange(file);
88
- if (head === null)
114
+ const binary = binaryFileOf(file);
115
+ if (head === null || binary === null)
89
116
  return null;
90
117
  if (mode === 'site') {
91
118
  if (typeof file.sha256 !== 'string')
92
119
  return null;
93
- return { path: file.path, revision: undefined, version: file.sha256, ...headed(head) };
120
+ return {
121
+ path: file.path,
122
+ revision: binary?.sha256,
123
+ version: file.sha256,
124
+ ...headed(head),
125
+ ...binaried(binary),
126
+ };
94
127
  }
95
128
  if (typeof file.revision !== 'string')
96
129
  return null;
97
- return { path: file.path, revision: file.revision, version: file.revision, ...headed(head) };
130
+ return {
131
+ path: file.path,
132
+ revision: file.revision,
133
+ version: file.revision,
134
+ ...(typeof file.sha256 === 'string' ? { sha256: file.sha256 } : {}),
135
+ ...headed(head),
136
+ ...binaried(binary),
137
+ };
98
138
  }
99
- function parseScope(value, mode) {
139
+ function parseRoomParts(value) {
100
140
  if (typeof value !== 'object' || value === null)
101
141
  return null;
102
142
  const held = value;
103
143
  if (typeof held.manifest !== 'object' || held.manifest === null)
104
144
  return null;
105
- if (!Array.isArray(held.contents))
145
+ if (!Array.isArray(held.parts))
106
146
  return null;
107
147
  const manifest = held.manifest;
108
148
  if (manifest.scope !== 'room')
@@ -112,47 +152,89 @@ function parseScope(value, mode) {
112
152
  return null;
113
153
  if (typeof manifest.room_handle !== 'string' || manifest.room_handle.length === 0)
114
154
  return null;
115
- if (!Array.isArray(manifest.files))
116
- return null;
117
- const files = [];
118
- for (const entry of manifest.files) {
119
- const file = parseFile(entry, mode);
120
- if (file === null)
121
- return null;
122
- files.push(file);
123
- }
124
- const contents = [];
125
- for (const entry of held.contents) {
126
- if (typeof entry !== 'object' || entry === null)
127
- return null;
128
- const content = entry;
129
- if (typeof content.path !== 'string' || typeof content.content !== 'string')
155
+ const parts = [];
156
+ for (const entry of held.parts) {
157
+ const part = parsePart(entry);
158
+ if (part === null)
130
159
  return null;
131
- contents.push({ path: content.path, content: content.content });
160
+ parts.push(part);
132
161
  }
133
- if (mode === 'site')
134
- return { anchor: manifest.anchor, ...at, files, contents };
135
- const attachments = parseOriginals(held.originals);
136
- if (attachments === null)
137
- return null;
138
- return { anchor: manifest.anchor, ...at, files, contents, attachments };
162
+ return { anchor: manifest.anchor, ...at, parts };
139
163
  }
140
- export function parseEnvelope(body) {
164
+ export function parseParted(body) {
141
165
  if (typeof body !== 'object' || body === null)
142
166
  return null;
143
167
  if (!('scopes' in body) || !Array.isArray(body.scopes))
144
168
  return null;
145
- const scopes = [];
169
+ const rooms = [];
146
170
  for (const entry of body.scopes) {
147
- const scope = parseScope(entry, 'credential');
148
- if (scope === null)
171
+ const room = parseRoomParts(entry);
172
+ if (room === null)
149
173
  return null;
150
- scopes.push(scope);
174
+ rooms.push(room);
151
175
  }
152
- return { scopes };
176
+ if (!('next' in body) || body.next === undefined)
177
+ return { rooms };
178
+ const next = body.next;
179
+ if (typeof next !== 'object' || next === null || typeof next.room !== 'string')
180
+ return null;
181
+ return { rooms, next: next.room };
182
+ }
183
+ export function parseSiteParted(body) {
184
+ return parseRoomParts(body);
153
185
  }
154
- export function parseSiteBootstrap(body) {
155
- return parseScope(body, 'site');
186
+ export function emptyScope(room) {
187
+ return {
188
+ anchor: room.anchor,
189
+ position: room.position,
190
+ logEpoch: room.logEpoch,
191
+ files: [],
192
+ contents: [],
193
+ };
194
+ }
195
+ function* partLines(text, mode) {
196
+ const files = [];
197
+ const contents = [];
198
+ let start = 0;
199
+ while (start < text.length) {
200
+ const end = text.indexOf('\n', start);
201
+ if (end === -1)
202
+ return null;
203
+ let entry;
204
+ try {
205
+ entry = JSON.parse(text.slice(start, end));
206
+ }
207
+ catch {
208
+ return null;
209
+ }
210
+ start = end + 1;
211
+ if (folderLine(entry))
212
+ continue;
213
+ const file = parseFile(entry, mode);
214
+ if (file === null)
215
+ return null;
216
+ files.push(file);
217
+ const { content } = entry;
218
+ if (typeof content === 'string')
219
+ contents.push({ path: file.path, content });
220
+ else if (content !== undefined)
221
+ return null;
222
+ yield ROW_WEIGHT;
223
+ }
224
+ return { files, contents };
225
+ }
226
+ function folderLine(entry) {
227
+ if (typeof entry !== 'object' || entry === null || !('folder' in entry))
228
+ return false;
229
+ return typeof entry.folder === 'string' && Object.keys(entry).length === 1;
230
+ }
231
+ export async function housePart(room, body, listed, mode) {
232
+ const payload = await checkedPayload(body, listed);
233
+ if (payload === null)
234
+ return null;
235
+ const text = await gunzipped(payload);
236
+ const read = text === null ? null : await stepped(partLines(text, mode));
237
+ return read === null ? { kind: 'transport-uncertainty' } : { ...emptyScope(room), ...read };
156
238
  }
157
239
  function parseChange(value, mode) {
158
240
  if (typeof value !== 'object' || value === null)
@@ -163,8 +245,15 @@ function parseChange(value, mode) {
163
245
  if (held.removed === true)
164
246
  return { path: held.path, removed: true };
165
247
  const head = headChange(held);
166
- if (head === null)
248
+ const binary = binaryFileOf(held);
249
+ if (head === null || binary === null)
167
250
  return null;
251
+ if (binary !== undefined) {
252
+ if (mode === 'credential' && typeof held.revision !== 'string')
253
+ return null;
254
+ const revision = typeof held.revision === 'string' ? held.revision : binary.sha256;
255
+ return { path: held.path, binary, revision, version: revision, ...headed(head) };
256
+ }
168
257
  if (mode === 'site') {
169
258
  if (typeof held.content !== 'string' || typeof held.sha256 !== 'string')
170
259
  return null;
@@ -185,12 +274,6 @@ function parseChange(value, mode) {
185
274
  ...headed(head),
186
275
  };
187
276
  }
188
- if (typeof held.reference === 'object' && held.reference !== null) {
189
- const reference = held.reference;
190
- if (typeof reference.revision !== 'string')
191
- return null;
192
- return { path: held.path, reference: { revision: reference.revision } };
193
- }
194
277
  return null;
195
278
  }
196
279
  export function parseEnumeration(body, mode) {
@@ -215,75 +298,121 @@ export function parseEnumeration(body, mode) {
215
298
  return null;
216
299
  changes.push(mapped);
217
300
  }
218
- if (mode === 'site') {
219
- authorities.push({ authority: held.authority, ...at, changes });
220
- continue;
221
- }
222
- const attachments = parseOriginals(held.originals);
223
- if (attachments === null)
301
+ const next = held.next === undefined ? undefined : readPage(held.next);
302
+ if (next === null)
224
303
  return null;
225
- authorities.push({ authority: held.authority, ...at, changes, attachments });
304
+ authorities.push({
305
+ authority: held.authority,
306
+ ...at,
307
+ changes,
308
+ ...(next === undefined ? {} : { next }),
309
+ });
226
310
  }
227
311
  return { authorities };
228
312
  }
229
- export function advancedScope(scope, view) {
230
- const files = new Map(scope.files.map((file) => [file.path, file]));
231
- const contents = new Map(scope.contents.map((entry) => [entry.path, entry.content]));
313
+ function readPage(held) {
314
+ if (typeof held !== 'object' || held === null)
315
+ return null;
316
+ const { after, through, read } = held;
317
+ if (typeof after !== 'string' || !DECIMAL.test(after))
318
+ return null;
319
+ if (typeof through !== 'string' || !DECIMAL.test(through))
320
+ return null;
321
+ if (typeof read !== 'number' || !Number.isSafeInteger(read) || read < 0)
322
+ return null;
323
+ return { after, through, read };
324
+ }
325
+ function advances(asked, next) {
326
+ const moved = BigInt(next.through) - BigInt(asked.through);
327
+ return moved > 0n || (moved === 0n && next.after === asked.after && next.read > asked.read);
328
+ }
329
+ export async function wholeView(first, more) {
330
+ const changes = new Map(first.changes.map((change) => [change.path, change]));
331
+ let view = first;
332
+ while (view.next !== undefined) {
333
+ const asked = view.next;
334
+ const page = await more(asked);
335
+ if ('kind' in page)
336
+ return page;
337
+ if (page.position !== asked.through ||
338
+ page.logEpoch !== first.logEpoch ||
339
+ (page.next !== undefined && !advances(asked, page.next))) {
340
+ return { kind: 'transport-uncertainty' };
341
+ }
342
+ for (const change of page.changes) {
343
+ changes.delete(change.path);
344
+ changes.set(change.path, change);
345
+ }
346
+ view = page;
347
+ }
348
+ return {
349
+ authority: first.authority,
350
+ position: view.position,
351
+ logEpoch: first.logEpoch,
352
+ changes: [...changes.values()],
353
+ };
354
+ }
355
+ export function* advancedScope(scope, view) {
356
+ const files = new Map();
357
+ for (const file of scope.files) {
358
+ files.set(file.path, file);
359
+ yield ROW_WEIGHT;
360
+ }
361
+ const contents = new Map();
362
+ for (const entry of scope.contents) {
363
+ contents.set(entry.path, entry.content);
364
+ yield ROW_WEIGHT;
365
+ }
232
366
  for (const change of view.changes) {
233
367
  files.delete(change.path);
234
368
  contents.delete(change.path);
369
+ yield ROW_WEIGHT;
235
370
  if ('removed' in change)
236
371
  continue;
237
- if ('content' in change) {
238
- files.set(change.path, {
239
- path: change.path,
240
- revision: change.revision,
241
- version: change.version,
242
- ...headed(change.head),
243
- });
372
+ files.set(change.path, {
373
+ path: change.path,
374
+ revision: change.revision,
375
+ version: change.version,
376
+ ...headed(change.head),
377
+ ...('binary' in change ? { binary: change.binary } : {}),
378
+ });
379
+ if ('content' in change)
244
380
  contents.set(change.path, change.content);
245
- continue;
246
- }
247
- const { revision } = change.reference;
248
- files.set(change.path, { path: change.path, revision, version: revision });
381
+ }
382
+ const listed = [];
383
+ for (const [path, content] of contents) {
384
+ listed.push({ path, content });
385
+ yield ROW_WEIGHT;
249
386
  }
250
387
  return {
251
388
  ...scope,
252
389
  position: view.position,
253
390
  logEpoch: view.logEpoch,
254
391
  files: [...files.values()],
255
- contents: [...contents].map(([path, content]) => ({ path, content })),
392
+ contents: listed,
256
393
  };
257
394
  }
258
- export function matchesScope(scope, tracked) {
259
- return scope.anchor === tracked.authority;
260
- }
261
- export function bootstrapOf(scope) {
262
- const contents = new Map(scope.contents.map((entry) => [entry.path, entry.content]));
263
- const documents = {};
264
- const revisions = {};
265
- const changes = {};
266
- const binaryTargets = [];
395
+ export function* bootstrapping(scope) {
396
+ const contents = new Map();
397
+ for (const entry of scope.contents) {
398
+ contents.set(entry.path, entry.content);
399
+ yield ROW_WEIGHT;
400
+ }
401
+ const answer = answering();
267
402
  for (const file of scope.files) {
268
- if (file.revision !== undefined)
269
- revisions[file.path] = file.revision;
403
+ yield ROW_WEIGHT;
270
404
  if (file.head !== undefined)
271
- changes[file.path] = file.head;
405
+ answer.changes.set(file.path, file.head);
272
406
  const content = contents.get(file.path);
273
- if (content === undefined)
274
- binaryTargets.push(file.path);
275
- else
276
- documents[file.path] = content;
407
+ if (file.binary !== undefined)
408
+ answer.binaryFiles.set(file.path, file.binary);
409
+ else if (content !== undefined)
410
+ answer.documents.set(file.path, content);
411
+ if (file.revision !== undefined)
412
+ revised(answer, file.path, file.revision);
277
413
  }
278
- return {
279
- kind: 'bootstrap',
280
- roomVersion: roomVersion(scope),
281
- documents,
282
- revisions,
283
- changes,
284
- binaryTargets: binaryTargets.sort(),
285
- ...declared(scope.attachments),
286
- };
414
+ const { removals: _removals, ...page } = yield* answered(answer);
415
+ return { kind: 'bootstrap', roomVersion: roomVersion(scope), ...page };
287
416
  }
288
417
  export function schemaOf(scope, schema) {
289
418
  const file = scope.files.find((entry) => entry.path === schema);
@@ -297,38 +426,27 @@ export function schemaOf(scope, schema) {
297
426
  export function viewOf(enumeration, tracked) {
298
427
  return enumeration.authorities.find((entry) => entry.authority === tracked.authority);
299
428
  }
300
- export function refreshFrom(view, fromRoomVersion) {
429
+ function* refreshing(view, fromRoomVersion) {
301
430
  if (roomVersion(view) === fromRoomVersion)
302
431
  return { kind: 'still-current' };
303
- const documents = {};
304
- const revisions = {};
305
- const changes = {};
306
- const binaryTargets = [];
307
- const removals = [];
432
+ const answer = answering();
308
433
  for (const change of view.changes) {
434
+ yield ROW_WEIGHT;
309
435
  if ('removed' in change) {
310
- removals.push(change.path);
436
+ answer.removals.add(change.path);
311
437
  continue;
312
438
  }
313
- if ('content' in change) {
314
- documents[change.path] = change.content;
315
- if (change.revision !== undefined)
316
- revisions[change.path] = change.revision;
317
- if (change.head !== undefined)
318
- changes[change.path] = change.head;
319
- continue;
320
- }
321
- binaryTargets.push(change.path);
322
- revisions[change.path] = change.reference.revision;
439
+ if ('content' in change)
440
+ answer.documents.set(change.path, change.content);
441
+ else
442
+ answer.binaryFiles.set(change.path, change.binary);
443
+ if (change.head !== undefined)
444
+ answer.changes.set(change.path, change.head);
445
+ if (change.revision !== undefined)
446
+ revised(answer, change.path, change.revision);
323
447
  }
324
- return {
325
- kind: 'net-advancement',
326
- roomVersion: roomVersion(view),
327
- documents,
328
- revisions,
329
- changes,
330
- binaryTargets: binaryTargets.sort(),
331
- removals: removals.sort(),
332
- ...declared(view.attachments),
333
- };
448
+ return { kind: 'net-advancement', roomVersion: roomVersion(view), ...(yield* answered(answer)) };
449
+ }
450
+ export async function refreshFrom(view, fromRoomVersion) {
451
+ return stepped(refreshing(view, fromRoomVersion));
334
452
  }
@@ -0,0 +1,7 @@
1
+ import type { TrackedAuthority } from './discovery.js';
2
+ export type HouseReferrer = {
3
+ locator: string;
4
+ referrer: Readonly<Record<string, string>>;
5
+ };
6
+ export declare function houseReferrer(referrer: unknown, tracked: ReadonlyMap<string, TrackedAuthority>): HouseReferrer | null;
7
+ //# sourceMappingURL=referrer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"referrer.d.ts","sourceRoot":"","sources":["../src/referrer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,MAAM,MAAM,aAAa,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAAE,CAAC;AAgB5F,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAC7C,aAAa,GAAG,IAAI,CAoBtB"}
@@ -0,0 +1,33 @@
1
+ function fields(value) {
2
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
3
+ ? value
4
+ : null;
5
+ }
6
+ function named(held, ...keys) {
7
+ const present = Object.keys(held);
8
+ return (present.length === keys.length &&
9
+ keys.every((key) => typeof held[key] === 'string' && held[key] !== ''));
10
+ }
11
+ export function houseReferrer(referrer, tracked) {
12
+ const held = fields(referrer);
13
+ if (held === null)
14
+ return null;
15
+ if (named(held, 'room', 'path')) {
16
+ const entry = tracked.get(held.room);
17
+ if (entry === undefined)
18
+ return null;
19
+ return {
20
+ locator: entry.locator,
21
+ referrer: { room_ref: entry.authority, path: held.path },
22
+ };
23
+ }
24
+ if (named(held, 'room_ref', 'record')) {
25
+ const roomRef = held.room_ref;
26
+ const entry = [...tracked.values()].find((candidate) => candidate.authority === roomRef);
27
+ return {
28
+ locator: entry?.locator ?? roomRef,
29
+ referrer: { room_ref: roomRef, record: held.record },
30
+ };
31
+ }
32
+ return null;
33
+ }
package/dist/refusal.d.ts CHANGED
@@ -1,9 +1,6 @@
1
1
  import type { AdapterFailure, DiscoverResult, ProviderRefusal, ScopedRefusal } from '@agentshouse/mdruntime';
2
- export type DoorRefusal = ProviderRefusal & {
3
- retryable: boolean;
4
- };
5
- export declare function doorRefusal(body: unknown): DoorRefusal | null;
6
- export declare function scopedRefusal(locator: string, scope: ScopedRefusal['scope'], refusal: DoorRefusal): ScopedRefusal;
2
+ export declare function doorRefusal(body: unknown): ProviderRefusal | null;
3
+ export declare function scopedRefusal(locator: string, scope: ScopedRefusal['scope'], refusal: ProviderRefusal): ScopedRefusal;
7
4
  export declare function classifyDoor(status: number, body: unknown, locator: string): AdapterFailure | null;
8
5
  export declare function classifyRead(status: number, body: unknown, locator: string): AdapterFailure | {
9
6
  kind: 'beyond-horizon';
@@ -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,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC;AAEnE,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CAO7D;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAC7B,OAAO,EAAE,WAAW,GACnB,aAAa,CAEf;AAmBD,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,CAYrF"}
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"}
package/dist/refusal.js CHANGED
@@ -6,11 +6,11 @@ export function doorRefusal(body) {
6
6
  const error = body.error;
7
7
  if (typeof error.code !== 'string')
8
8
  return null;
9
- const { code, ...fields } = error;
10
- return { code, fields, retryable: error.retryable === true };
9
+ const { code, retryable, ...fields } = error;
10
+ return { code, fields, retryable: retryable === true };
11
11
  }
12
12
  export function scopedRefusal(locator, scope, refusal) {
13
- return { kind: 'scoped-refusal', locator, scope, code: refusal.code, fields: refusal.fields };
13
+ return { kind: 'scoped-refusal', locator, scope, ...refusal };
14
14
  }
15
15
  function doorFailure(status, body) {
16
16
  if (status === 0)
@@ -18,8 +18,9 @@ function doorFailure(status, body) {
18
18
  const refusal = doorRefusal(body);
19
19
  if (status === 401)
20
20
  return { kind: 'revoked-authorization' };
21
- if (refusal?.retryable === true)
21
+ if (refusal?.retryable === true || refusal?.code === 'update_required') {
22
22
  return { kind: 'transport-uncertainty' };
23
+ }
23
24
  if (status === 404 || refusal?.code === 'room_not_found')
24
25
  return { kind: 'room-not-readable' };
25
26
  if (status < 400)
@@ -50,11 +51,7 @@ export function discoveryFailure(status, body) {
50
51
  if (failure.kind === 'revoked-authorization')
51
52
  return failure;
52
53
  if (failure.kind === 'refused') {
53
- return {
54
- kind: 'contract-unavailable',
55
- code: failure.refusal.code,
56
- fields: failure.refusal.fields,
57
- };
54
+ return { kind: 'contract-unavailable', ...failure.refusal };
58
55
  }
59
56
  return { kind: 'transport-uncertainty' };
60
57
  }
package/dist/site.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import type { Adapter } from '@agentshouse/mdruntime';
2
2
  import { type HouseSiteTransport } from './transport.js';
3
- export declare function createSiteAdapter(transport: HouseSiteTransport): Adapter;
3
+ export declare function createSiteAdapter(transport: HouseSiteTransport, snapshot?: boolean): Adapter;
4
4
  //# sourceMappingURL=site.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAMR,MAAM,wBAAwB,CAAC;AAsBhC,OAAO,EAKL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAgCxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,GAAG,OAAO,CAkIxE"}
1
+ {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAUR,MAAM,wBAAwB,CAAC;AA6BhC,OAAO,EAOL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAuCxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAkQ1F"}