@agentshouse/mdruntime-adapter 0.1.0-cb6436097e8a2 → 0.1.0-cb8fc491b1a92

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 (64) hide show
  1. package/README.md +2 -2
  2. package/dist/actions.d.ts +122 -23
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +27 -141
  5. package/dist/adapter.d.ts.map +1 -1
  6. package/dist/adapter.js +220 -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 +6 -10
  14. package/dist/discovery.d.ts.map +1 -1
  15. package/dist/discovery.js +36 -40
  16. package/dist/house-model.d.ts +2983 -0
  17. package/dist/house-model.d.ts.map +1 -0
  18. package/dist/house-model.js +1643 -0
  19. package/dist/index.d.ts +9 -2
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +8 -1
  22. package/dist/model.d.ts +5 -2
  23. package/dist/model.d.ts.map +1 -1
  24. package/dist/model.js +10 -29
  25. package/dist/part.d.ts +14 -0
  26. package/dist/part.d.ts.map +1 -0
  27. package/dist/part.js +90 -0
  28. package/dist/read.d.ts +46 -63
  29. package/dist/read.d.ts.map +1 -1
  30. package/dist/read.js +216 -283
  31. package/dist/refusal.d.ts +0 -3
  32. package/dist/refusal.d.ts.map +1 -1
  33. package/dist/refusal.js +0 -5
  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 +126 -0
  40. package/dist/site.d.ts.map +1 -1
  41. package/dist/site.js +80 -179
  42. package/dist/stream.d.ts +4 -14
  43. package/dist/stream.d.ts.map +1 -1
  44. package/dist/stream.js +125 -413
  45. package/dist/transport.d.ts +53 -43
  46. package/dist/transport.d.ts.map +1 -1
  47. package/dist/transport.js +49 -11
  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 +16 -1
  52. package/dist/write.d.ts.map +1 -1
  53. package/dist/write.js +101 -56
  54. package/package.json +8 -4
  55. package/AGENTS.md +0 -299
  56. package/dist/gather.d.ts +0 -4
  57. package/dist/gather.d.ts.map +0 -1
  58. package/dist/gather.js +0 -45
  59. package/dist/handed.d.ts +0 -15
  60. package/dist/handed.d.ts.map +0 -1
  61. package/dist/handed.js +0 -38
  62. package/dist/referrer.d.ts +0 -7
  63. package/dist/referrer.d.ts.map +0 -1
  64. package/dist/referrer.js +0 -35
@@ -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) {
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);
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
+ }
@@ -0,0 +1,7 @@
1
+ export declare const INBOX_CHANNEL_KINDS: readonly ['telegram-bot', 'telegram-business', 'whatsapp', 'messenger', 'instagram', 'viber', 'tiktok'];
2
+ export type InboxChannelKind = (typeof INBOX_CHANNEL_KINDS)[number];
3
+ export declare const INBOX_CHAT_TYPE = "inbox-chat";
4
+ export declare const INBOX_MESSAGE_TYPE = "inbox-message";
5
+ export declare const HOUSE_NAMEABLE_ROOM_TYPES: string[];
6
+ export declare const HOUSE_ROOM_TYPES: string;
7
+ //# sourceMappingURL=room-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-types.d.ts","sourceRoot":"","sources":["../src/room-types.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB,YAC9B,cAAc,EACd,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,WAAW,EACX,OAAO,EACP,QAAQ,CACA,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE,eAAO,MAAM,eAAe,eAAe,CAAC;AAE5C,eAAO,MAAM,kBAAkB,kBAAkB,CAAC;AAElD,eAAO,MAAM,yBAAyB,UAAwC,CAAC;AAyB/E,eAAO,MAAM,gBAAgB,QA8FjB,CAAC"}
@@ -0,0 +1,126 @@
1
+ import { APP_REFERENCE_PATTERN } from './app-reference.js';
2
+ import { HOUSE_MODEL_TYPES } from './house-model.js';
3
+ export const INBOX_CHANNEL_KINDS = [
4
+ 'telegram-bot',
5
+ 'telegram-business',
6
+ 'whatsapp',
7
+ 'messenger',
8
+ 'instagram',
9
+ 'viber',
10
+ 'tiktok',
11
+ ];
12
+ export const INBOX_CHAT_TYPE = 'inbox-chat';
13
+ export const INBOX_MESSAGE_TYPE = 'inbox-message';
14
+ export const HOUSE_NAMEABLE_ROOM_TYPES = [INBOX_CHAT_TYPE, INBOX_MESSAGE_TYPE];
15
+ const WAYFINDING_MAP_TYPE = 'wayfinding-map';
16
+ const WAYFINDING_TICKET_TYPE = 'wayfinding-ticket';
17
+ const WAYFINDING_MAP_SECTIONS = [
18
+ 'Destination',
19
+ 'Notes',
20
+ 'Decisions so far',
21
+ 'Not yet specified',
22
+ 'Out of scope',
23
+ ];
24
+ const IDENTITY = "{ type: string, pattern: '^\\S+$' }";
25
+ const AGENT = [' agent: { type: string, format: uuid }', ' name: { type: string }'];
26
+ const ASSIGNEE = [
27
+ ' type: object',
28
+ ' properties:',
29
+ ' user: { type: string, format: uuid }',
30
+ ...AGENT,
31
+ ];
32
+ export const HOUSE_ROOM_TYPES = [
33
+ `${INBOX_CHAT_TYPE}:`,
34
+ ' properties:',
35
+ ' inbox: { type: string, format: uuid }',
36
+ ` channel: { enum: [${INBOX_CHANNEL_KINDS.join(', ')}] }`,
37
+ ` chat: ${IDENTITY}`,
38
+ ' customer:',
39
+ ' type: object',
40
+ ' properties:',
41
+ ' name: { type: string }',
42
+ ` username: ${IDENTITY}`,
43
+ ` phone: ${IDENTITY}`,
44
+ ' assignee:',
45
+ ...ASSIGNEE,
46
+ ' return_to:',
47
+ ' type: object',
48
+ ' properties:',
49
+ ...AGENT,
50
+ ' conversation: { type: string, format: uuid }',
51
+ ' required: [inbox, channel, chat, customer]',
52
+ `${INBOX_MESSAGE_TYPE}:`,
53
+ ' properties:',
54
+ ' direction: { enum: [in, out] }',
55
+ ' sender:',
56
+ ' type: object',
57
+ ' properties:',
58
+ ' name: { type: string }',
59
+ ` username: ${IDENTITY}`,
60
+ ' sent_at: { type: string, format: date-time }',
61
+ ` channel_message: ${IDENTITY}`,
62
+ ' state: { enum: [sending, sent, failed] }',
63
+ ' reason: { type: string }',
64
+ ' labelled: { const: true }',
65
+ ' reactions:',
66
+ ' type: array',
67
+ ' items:',
68
+ ' type: object',
69
+ ' properties:',
70
+ ' reaction: { type: string, minLength: 1 }',
71
+ ' sender:',
72
+ ' type: object',
73
+ ' properties:',
74
+ ` id: ${IDENTITY}`,
75
+ ' name: { type: string }',
76
+ ` username: ${IDENTITY}`,
77
+ ' count: { type: integer, minimum: 1 }',
78
+ ' required: [reaction]',
79
+ ` post: ${IDENTITY}`,
80
+ ' assignee:',
81
+ ...ASSIGNEE,
82
+ ' sent_outside: { const: true }',
83
+ ' template:',
84
+ ' type: object',
85
+ ' properties:',
86
+ ' name: { type: string, minLength: 1 }',
87
+ ' language: { type: string, minLength: 1 }',
88
+ ' required: [name, language]',
89
+ ' values:',
90
+ ' type: object',
91
+ ' additionalProperties: { type: string }',
92
+ ' withheld: { const: true }',
93
+ ' required: [direction]',
94
+ ' if: { properties: { direction: { const: in } } }',
95
+ ' then: { required: [sent_at] }',
96
+ `${WAYFINDING_MAP_TYPE}:`,
97
+ ' properties:',
98
+ ' title: { type: string }',
99
+ ' required: [title]',
100
+ ' sections:',
101
+ ...WAYFINDING_MAP_SECTIONS.map((name) => ` ${name}: { kind: text, required: true }`),
102
+ `${WAYFINDING_TICKET_TYPE}:`,
103
+ ' properties:',
104
+ ' title: { type: string }',
105
+ ' kind: { enum: [research, prototype, grilling, task] }',
106
+ ' status: { enum: [open, in-progress, done, out-of-scope] }',
107
+ ` map: { type: string, reference: ${WAYFINDING_MAP_TYPE} }`,
108
+ ` blocked_by: { type: array, items: { type: string, reference: ${WAYFINDING_TICKET_TYPE} } }`,
109
+ ' assignee:',
110
+ ...ASSIGNEE,
111
+ ' conversation: { type: string, format: uuid }',
112
+ ` app: { type: string, pattern: '${APP_REFERENCE_PATTERN.source}' }`,
113
+ ' required: [title, kind, status, map, blocked_by]',
114
+ ' sections:',
115
+ ' Question: { kind: text }',
116
+ ' Answer: { kind: text }',
117
+ ' allOf:',
118
+ ' - if: { properties: { status: { enum: [in-progress, done, out-of-scope] } }, required: [status] }',
119
+ ' then: { required: [assignee] }',
120
+ ' else: { properties: { assignee: false } }',
121
+ ' - if: { properties: { assignee: { required: [agent] } }, required: [assignee] }',
122
+ ' else: { properties: { conversation: false } }',
123
+ ' - if: { properties: { status: { enum: [done, out-of-scope] } }, required: [status] }',
124
+ ' then: { sections: { Answer: { kind: text, required: true } } }',
125
+ HOUSE_MODEL_TYPES,
126
+ ].join('\n');
@@ -1 +1 @@
1
- {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAOR,MAAM,wBAAwB,CAAC;AA2BhC,OAAO,EAOL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAmCxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,UAAQ,GAAG,OAAO,CA+Q1F"}
1
+ {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAQR,MAAM,wBAAwB,CAAC;AAehC,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAuBxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,UAAQ,GAAG,OAAO,CA6J1F"}
package/dist/site.js CHANGED
@@ -1,147 +1,72 @@
1
+ import { stepped } from '@agentshouse/mdruntime';
1
2
  import { actionOutcome, SITE_SUBMIT } from './actions.js';
2
3
  import { mapDiscovery, parseSiteDiscovery, siteCapabilities, siteTracked, } from './discovery.js';
3
- import { partModels, streamedModels, viewModels } from './model.js';
4
- import { advancedScope, bootstrapOf, parseEnumeration, parseSiteBootstrap, refreshFrom, siteBootstrapNext, siteBootstrapOffset, viewOf, wholeView, } from './read.js';
5
- import { sha256Hex } from './digest.js';
6
- import { classifyDoor, classifyRead, discoveryFailure } from './refusal.js';
4
+ import { bootstrapping } from './read.js';
5
+ import { roomStreams } from './room-stream.js';
6
+ import { classifyDoor, discoveryFailure } from './refusal.js';
7
+ import { HOUSE_NAMEABLE_ROOM_TYPES, HOUSE_ROOM_TYPES } from './room-types.js';
7
8
  import { houseNotifications } from './stream.js';
8
- import { SITE_DOOR_BOOTSTRAP, SITE_DOOR_DISCOVER, SITE_DOOR_ENUMERATE, SITE_DOOR_SUBMIT, SITE_FILE_RECORD, SITE_FILES, } from './transport.js';
9
- import { houseReferrer } from './referrer.js';
10
- import { followsVersion, logPosition, presented, reachedVersion, roomVersion, } from './version.js';
9
+ import { houseSiteRoute, SITE_DOOR_SUBMIT, SITE_FILES, } from './transport.js';
10
+ import { followsVersion, logPosition, presented, reachedVersion, roomVersion } from './version.js';
11
11
  const UNCERTAIN = { kind: 'transport-uncertainty' };
12
+ function unfound() {
13
+ return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
14
+ }
12
15
  function siteRoom(tracked) {
13
16
  return {
14
17
  name: tracked.handle,
15
18
  locator: tracked.locator,
16
19
  handle: tracked.handle,
17
20
  roomVersion: roomVersion(tracked),
18
- operations: { read: [''], sync: [''], write: [], delete: [] },
19
- replica: { selection: tracked.locator, admission: 'admitted' },
21
+ operations: { write: [], delete: [] },
22
+ replica: { selection: tracked.locator, admission: 'admitted', offline: 'open' },
20
23
  providerOwnedPaths: [],
21
24
  };
22
25
  }
23
- function settled(refused) {
24
- return refused.kind === 'beyond-horizon' ? UNCERTAIN : refused;
25
- }
26
26
  export function createSiteAdapter(transport, snapshot = false) {
27
27
  const notifications = houseNotifications(transport, 'site');
28
28
  const tracked = new Map();
29
- function published(referrer) {
30
- const named = houseReferrer(referrer, tracked);
31
- return named === null || !tracked.has(named.locator) ? null : named;
32
- }
33
- async function enumerated(entry, from, page) {
34
- const answer = await transport.door(SITE_DOOR_ENUMERATE, {
35
- positions: [
36
- page === undefined
37
- ? presented(entry.authority, from)
38
- : {
39
- ...presented(entry.authority, { position: page.after, logEpoch: from.logEpoch }),
40
- page: { through: page.through, read: page.read },
41
- },
42
- ],
43
- });
44
- const classified = classifyRead(answer.status, answer.body, entry.locator);
45
- if (classified !== null)
46
- return classified;
47
- const found = parseEnumeration(answer.body, 'site');
48
- if (found === null)
49
- return UNCERTAIN;
50
- return viewOf(found, entry) ?? { kind: 'room-not-readable', locator: entry.locator };
29
+ const read = new Map();
30
+ const rooms = roomStreams('site');
31
+ function fileRoute(request) {
32
+ const entry = tracked.get(request.locator);
33
+ if (entry === undefined)
34
+ return { kind: 'room-not-readable', locator: request.locator };
35
+ return `${SITE_FILES}${entry.authority}/${encodeURIComponent(request.revision)}/${encodeURIComponent(request.path)}`;
51
36
  }
52
- async function enumeration(entry, from) {
53
- const first = await enumerated(entry, from);
54
- return 'kind' in first ? first : wholeView(first, (page) => enumerated(entry, from, page));
55
- }
56
- async function bootstrapPart(entry, after, offset) {
57
- const query = [
58
- ...(after === null ? [] : [`after=${encodeURIComponent(after)}`]),
59
- ...(offset === null ? [] : [`offset=${offset}`]),
60
- ];
61
- const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}${query.length === 0 ? '' : `?${query.join('&')}`}`);
62
- const classified = classifyDoor(answer.status, answer.body, entry.locator);
63
- if (classified !== null)
64
- return { failure: classified };
65
- const scope = parseSiteBootstrap(answer.body);
66
- return scope === null ? { failure: UNCERTAIN } : { body: answer.body, scope };
67
- }
68
- async function assembled(entry, scope, path, offset) {
69
- const opened = scope.contents.at(-1);
70
- if (opened === undefined || opened.path !== path || opened.content.length !== offset) {
71
- return UNCERTAIN;
72
- }
73
- let text = opened.content;
74
- for (;;) {
75
- const part = await bootstrapPart(entry, path, text.length);
76
- if ('failure' in part)
77
- return part.failure;
78
- const [piece] = part.scope.contents;
79
- if (piece === undefined ||
80
- part.scope.contents.length !== 1 ||
81
- piece.path !== path ||
82
- piece.content.length === 0) {
83
- return UNCERTAIN;
84
- }
85
- text += piece.content;
86
- const more = siteBootstrapOffset(part.body);
87
- if (more === null)
88
- break;
89
- if (more !== text.length)
90
- return UNCERTAIN;
91
- }
92
- const file = scope.files.find((held) => held.path === path);
93
- if (file === undefined || (await sha256Hex(text)) !== file.version)
94
- return UNCERTAIN;
95
- return { ...scope, contents: [...scope.contents.slice(0, -1), { path, content: text }] };
37
+ async function openedRoom(entry, arriving, signal) {
38
+ const cut = read.get(entry.locator);
39
+ const answered = await transport.streamed(`${houseSiteRoute('bootstrap')}/${entry.authority}${cut === undefined ? '' : `?expired=${cut}`}`, signal ?? new AbortController().signal);
40
+ if (answered.room === null)
41
+ return classifyDoor(answered.status, answered.body, entry.locator) ?? UNCERTAIN;
42
+ const head = await rooms.head(entry, answered.room, arriving, signal);
43
+ const at = head.kind === 'bootstrap' ? logPosition(head.roomVersion) : null;
44
+ if (at !== null)
45
+ read.set(entry.locator, at.position);
46
+ return head;
96
47
  }
97
- async function caughtUp(entry, after) {
98
- const part = await bootstrapPart(entry, after, null);
99
- if ('failure' in part)
48
+ async function streamedPage(entry, token) {
49
+ const part = await rooms.part(entry, token);
50
+ if ('kind' in part)
100
51
  return part;
101
- const next = siteBootstrapNext(part.body);
102
- const offset = siteBootstrapOffset(part.body);
103
- if (offset !== null) {
104
- if (next === null)
105
- return { failure: UNCERTAIN };
106
- const scope = await assembled(entry, part.scope, next, offset);
107
- return 'kind' in scope ? { failure: scope } : { scope, next };
108
- }
109
- const { scope } = part;
110
- if (after !== null || next !== null || roomVersion(scope) === roomVersion(entry)) {
111
- return { scope, next };
112
- }
113
- const view = await enumeration(entry, scope);
114
- if ('kind' in view)
115
- return { failure: settled(view) };
116
- return { scope: advancedScope(scope, view), next: null };
117
- }
118
- async function refreshed(entry, fromRoomVersion) {
119
- const from = logPosition(fromRoomVersion);
120
- if (from === null)
121
- return { kind: 'beyond-horizon' };
122
- const streamed = notifications.advance(entry, from);
123
- if (streamed !== null) {
124
- const models = await streamedModels(streamed.schemas, entry, 'site');
125
- return models === undefined ? streamed.page : { ...streamed.page, models };
126
- }
127
- const view = await enumeration(entry, from);
128
- if ('kind' in view)
129
- return view;
130
- notifications.reach(entry.authority, view);
131
- const answer = refreshFrom(view, fromRoomVersion);
132
- if (answer.kind !== 'net-advancement')
133
- return answer;
134
- const models = await viewModels(view, entry);
135
- return models === undefined ? answer : { ...answer, models };
52
+ const { folders: _folders, ...page } = await stepped(bootstrapping(part.scope));
53
+ return {
54
+ ...page,
55
+ ...(part.models === undefined ? {} : { models: part.models }),
56
+ ...(part.pageToken === undefined ? {} : { pageToken: part.pageToken }),
57
+ bytes: part.bytes,
58
+ };
136
59
  }
137
60
  return {
138
61
  localSaves: true,
139
62
  exhaustiveDiscovery: true,
63
+ roomTypes: HOUSE_ROOM_TYPES,
64
+ nameableRoomTypes: HOUSE_NAMEABLE_ROOM_TYPES,
140
65
  async authorize() {
141
66
  return {};
142
67
  },
143
68
  async discover() {
144
- const answer = await transport.read(SITE_DOOR_DISCOVER);
69
+ const answer = await transport.read(houseSiteRoute('discover'));
145
70
  const failed = discoveryFailure(answer.status, answer.body);
146
71
  if (failed !== null)
147
72
  return failed;
@@ -159,69 +84,53 @@ export function createSiteAdapter(transport, snapshot = false) {
159
84
  const entry = tracked.get(request.locator);
160
85
  if (entry === undefined)
161
86
  return { kind: 'room-not-readable', locator: request.locator };
162
- const continued = request.pageToken === undefined
163
- ? null
164
- : JSON.parse(request.pageToken);
165
- const held = await caughtUp(entry, continued?.after ?? null);
166
- if ('failure' in held)
167
- return held.failure;
168
- notifications.reach(entry.authority, held.scope);
169
- const seen = [
170
- ...(continued?.seen ?? []),
171
- ...entry.schemas.filter((schema) => held.scope.files.some((file) => file.path === schema)),
172
- ];
173
- const models = await partModels(held.scope, entry, new Set(seen), held.next === null);
174
- const continuation = held.next === null ? null : { after: held.next, seen };
175
- return {
176
- ...bootstrapOf(held.scope),
177
- ...(models === undefined ? {} : { models }),
178
- ...(continuation === null ? {} : { pageToken: JSON.stringify(continuation) }),
179
- };
87
+ return request.pageToken === undefined
88
+ ? openedRoom(entry, request.arriving, request.signal)
89
+ : streamedPage(entry, request.pageToken);
180
90
  },
181
- async refresh(_authorization, request) {
182
- const entry = tracked.get(request.locator);
183
- if (entry === undefined)
184
- return { kind: 'room-not-readable', locator: request.locator };
185
- if (request.pageToken !== undefined)
186
- return UNCERTAIN;
187
- if (snapshot) {
188
- return request.fromRoomVersion === roomVersion(entry)
189
- ? { kind: 'still-current' }
190
- : { kind: 'beyond-horizon' };
91
+ ...(snapshot
92
+ ? {
93
+ async refresh(_authorization, request) {
94
+ const entry = tracked.get(request.locator);
95
+ if (entry === undefined)
96
+ return { kind: 'room-not-readable', locator: request.locator };
97
+ if (request.pageToken !== undefined)
98
+ return UNCERTAIN;
99
+ return request.fromRoomVersion === roomVersion(entry)
100
+ ? { kind: 'still-current' }
101
+ : { kind: 'beyond-horizon' };
102
+ },
191
103
  }
192
- return refreshed(entry, request.fromRoomVersion);
193
- },
104
+ : {}),
194
105
  async mutate() {
195
106
  return { kind: 'rejected', affected: {}, code: 'write-grant', fields: {}, retryable: false };
196
107
  },
108
+ async attach() {
109
+ return { kind: 'rejected', code: 'write-grant', fields: {}, retryable: false };
110
+ },
197
111
  async history() {
198
112
  return { kind: 'no-history' };
199
113
  },
200
114
  async binary(_authorization, request) {
201
- const named = published(request.kind === 'path' ? { room: request.locator, path: request.path } : request.referrer);
202
- if (named === null) {
203
- return { kind: 'rejected', code: 'referrer_unknown', fields: {}, retryable: false };
204
- }
205
- if (request.fileRef === undefined) {
206
- return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
207
- }
208
- const { room_ref, path, record } = named.referrer;
209
- const read = await transport.download(`${SITE_FILES}${room_ref}/${encodeURIComponent(request.fileRef)}/${path === undefined
210
- ? `${SITE_FILE_RECORD}/${encodeURIComponent(record)}`
211
- : encodeURIComponent(path)}`);
212
- if (read.status === 404) {
213
- return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
214
- }
215
- return read.status === 200 && read.blob !== null
216
- ? { kind: 'binary', blob: read.blob }
115
+ const route = fileRoute(request);
116
+ if (typeof route !== 'string')
117
+ return route;
118
+ const read = await transport.download(route);
119
+ if (read.status === 404)
120
+ return unfound();
121
+ return read.status === 200 && read.body !== null
122
+ ? { kind: 'binary', body: read.body, mediaType: read.mediaType }
217
123
  : UNCERTAIN;
218
124
  },
219
- referrerScope(referrer) {
220
- const named = published(referrer);
221
- if (named === null)
222
- return null;
223
- const { path } = named.referrer;
224
- return { kind: 'room', locator: named.locator, ...(path === undefined ? {} : { path }) };
125
+ async link(_authorization, request) {
126
+ const route = fileRoute(request);
127
+ if (typeof route !== 'string')
128
+ return route;
129
+ return {
130
+ kind: 'link',
131
+ url: route,
132
+ name: request.path.slice(request.path.lastIndexOf('/') + 1),
133
+ };
225
134
  },
226
135
  reached(locator, version, target) {
227
136
  return reachedVersion(version, target, tracked.get(locator)?.logEpoch);
@@ -249,19 +158,11 @@ export function createSiteAdapter(transport, snapshot = false) {
249
158
  notifications.send(rooms.flatMap((room) => {
250
159
  const entry = tracked.get(room.locator);
251
160
  const at = logPosition(room.roomVersion);
252
- if (entry === undefined || at === null)
253
- return [];
254
- notifications.reach(entry.authority, at);
255
- return [presented(entry.authority, at)];
256
- }), null);
161
+ return entry === undefined || at === null ? [] : [presented(entry.authority, at)];
162
+ }));
257
163
  },
258
164
  reopen: notifications.reopen,
259
165
  observe: notifications.observe,
260
- published(locator, roomVersion) {
261
- const at = logPosition(roomVersion);
262
- if (at !== null)
263
- notifications.published(locator, at);
264
- },
265
166
  },
266
167
  serviceMode: notifications.serviceMode,
267
168
  };
package/dist/stream.d.ts CHANGED
@@ -1,22 +1,12 @@
1
- import type { ConversationStream, RefreshPage, RoomStreamEvent, ServiceModeSignal, StreamReceipts } from '@agentshouse/mdruntime';
1
+ import { type ConversationStream, type RoomStreamEvent, type ServiceModeSignal } from '@agentshouse/mdruntime';
2
2
  import type { TrackedAuthority } from './discovery.js';
3
- import type { HouseDemand, HouseDoor, HouseHeldRoom, HouseMode, HouseStreamEntry } from './transport.js';
4
- import { type LogPosition } from './version.js';
5
- export type HeldRevision = (path: string, revision: string) => boolean;
6
- export type StreamedAdvancement = {
7
- page: RefreshPage;
8
- entries: readonly HouseStreamEntry[];
9
- schemas: ReadonlyMap<string, HouseStreamEntry>;
10
- };
3
+ import { type HouseDoor, type HouseHeldRoom, type HouseMode } from './transport.js';
11
4
  export type HouseNotifications = {
12
5
  runtime: string;
13
- observe(notify: (event: RoomStreamEvent) => void, receipts: StreamReceipts): () => void;
14
- send(rooms: readonly HouseHeldRoom[], demand: HouseDemand | null): void;
15
- published(locator: string, at: LogPosition): void;
6
+ observe(notify: (event: RoomStreamEvent) => void): () => void;
7
+ send(rooms: readonly HouseHeldRoom[]): void;
16
8
  reopen(): void;
17
9
  track(authorities: readonly TrackedAuthority[]): void;
18
- reach(authority: string, at: LogPosition): void;
19
- advance(tracked: TrackedAuthority, from: LogPosition, holds?: HeldRevision): StreamedAdvancement | null;
20
10
  conversations: ConversationStream;
21
11
  serviceMode: ServiceModeSignal;
22
12
  };
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,kBAAkB,EAElB,WAAW,EACX,eAAe,EAEf,iBAAiB,EACjB,cAAc,EAEf,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,aAAa,EAEb,SAAS,EAET,gBAAgB,EAEjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AA0C7D,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;AAEvE,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACrC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM,IAAI,CAAC;IACxF,IAAI,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAAC;IACxE,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI,CAAC;IAClD,MAAM,IAAI,IAAI,CAAC;IACf,KAAK,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACtD,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI,CAAC;IAChD,OAAO,CACL,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,WAAW,EACjB,KAAK,CAAC,EAAE,YAAY,GACnB,mBAAmB,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,kBAAkB,CAAC;IAClC,WAAW,EAAE,iBAAiB,CAAC;CAChC,CAAC;AAkFF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,kBAAkB,CAohB5F"}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,kBAAkB,EAIvB,KAAK,eAAe,EAEpB,KAAK,iBAAiB,EAEvB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAWvD,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,aAAa,EAElB,KAAK,SAAS,EAIf,MAAM,gBAAgB,CAAC;AAaxB,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC9D,IAAI,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI,CAAC;IAC5C,MAAM,IAAI,IAAI,CAAC;IACf,KAAK,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACtD,aAAa,EAAE,kBAAkB,CAAC;IAClC,WAAW,EAAE,iBAAiB,CAAC;CAChC,CAAC;AAkFF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,kBAAkB,CA2Q5F"}