@agentshouse/mdruntime-adapter 0.1.0-cd61dfca5d699 → 0.1.0-cd75dfaf57319

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 (73) hide show
  1. package/README.md +2 -2
  2. package/dist/actions.d.ts +4 -66
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +7 -339
  5. package/dist/adapter.d.ts.map +1 -1
  6. package/dist/adapter.js +229 -371
  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 +23 -14
  14. package/dist/discovery.d.ts.map +1 -1
  15. package/dist/discovery.js +92 -54
  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 +719 -0
  20. package/dist/house-model.d.ts.map +1 -0
  21. package/dist/house-model.js +393 -0
  22. package/dist/index.d.ts +11 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +10 -1
  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 +14 -0
  29. package/dist/part.d.ts.map +1 -0
  30. package/dist/part.js +90 -0
  31. package/dist/read.d.ts +56 -63
  32. package/dist/read.d.ts.map +1 -1
  33. package/dist/read.js +240 -285
  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 +7 -0
  41. package/dist/room-types.d.ts.map +1 -0
  42. package/dist/room-types.js +123 -0
  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 +88 -195
  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 +170 -422
  54. package/dist/transport.d.ts +55 -40
  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 +18 -2
  61. package/dist/write.d.ts.map +1 -1
  62. package/dist/write.js +105 -75
  63. package/package.json +8 -4
  64. package/AGENTS.md +0 -299
  65. package/dist/gather.d.ts +0 -4
  66. package/dist/gather.d.ts.map +0 -1
  67. package/dist/gather.js +0 -45
  68. package/dist/handed.d.ts +0 -15
  69. package/dist/handed.d.ts.map +0 -1
  70. package/dist/handed.js +0 -38
  71. package/dist/referrer.d.ts +0 -7
  72. package/dist/referrer.d.ts.map +0 -1
  73. 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, 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
+ }
@@ -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 CHAT_TYPE = "chat";
4
+ export declare const CHAT_MESSAGE_TYPE = "chat-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,SAAS,SAAS,CAAC;AAEhC,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAEhD,eAAO,MAAM,yBAAyB,UAAiC,CAAC;AAyBxE,eAAO,MAAM,gBAAgB,QA2FjB,CAAC"}
@@ -0,0 +1,123 @@
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 CHAT_TYPE = 'chat';
13
+ export const CHAT_MESSAGE_TYPE = 'chat-message';
14
+ export const HOUSE_NAMEABLE_ROOM_TYPES = [CHAT_TYPE, CHAT_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
+ `${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
+ ' required: [chat, customer]',
51
+ `${CHAT_MESSAGE_TYPE}:`,
52
+ ' properties:',
53
+ ' direction: { enum: [in, out] }',
54
+ ' sender:',
55
+ ' type: object',
56
+ ' properties:',
57
+ ' name: { type: string }',
58
+ ` username: ${IDENTITY}`,
59
+ ' sent_at: { type: string, format: date-time }',
60
+ ` channel_message: ${IDENTITY}`,
61
+ ' labelled: { const: true }',
62
+ ' reactions:',
63
+ ' type: array',
64
+ ' items:',
65
+ ' type: object',
66
+ ' properties:',
67
+ ' reaction: { type: string, minLength: 1 }',
68
+ ' sender:',
69
+ ' type: object',
70
+ ' properties:',
71
+ ` id: ${IDENTITY}`,
72
+ ' name: { type: string }',
73
+ ` username: ${IDENTITY}`,
74
+ ' count: { type: integer, minimum: 1 }',
75
+ ' required: [reaction]',
76
+ ` post: ${IDENTITY}`,
77
+ ' assignee:',
78
+ ...ASSIGNEE,
79
+ ' sent_outside: { const: true }',
80
+ ' template:',
81
+ ' type: object',
82
+ ' properties:',
83
+ ' name: { type: string, minLength: 1 }',
84
+ ' language: { type: string, minLength: 1 }',
85
+ ' required: [name, language]',
86
+ ' values:',
87
+ ' type: object',
88
+ ' additionalProperties: { type: string }',
89
+ ' withheld: { const: true }',
90
+ ' required: [direction]',
91
+ ' if: { properties: { direction: { const: in } } }',
92
+ ' then: { required: [sent_at] }',
93
+ `${WAYFINDING_MAP_TYPE}:`,
94
+ ' properties:',
95
+ ' title: { type: string }',
96
+ ' required: [title]',
97
+ ' sections:',
98
+ ...WAYFINDING_MAP_SECTIONS.map((name) => ` ${name}: { kind: text, required: true }`),
99
+ `${WAYFINDING_TICKET_TYPE}:`,
100
+ ' properties:',
101
+ ' title: { type: string }',
102
+ ' kind: { enum: [research, prototype, grilling, task] }',
103
+ ' status: { enum: [open, in-progress, done, out-of-scope] }',
104
+ ` map: { type: string, reference: ${WAYFINDING_MAP_TYPE} }`,
105
+ ` blocked_by: { type: array, items: { type: string, reference: ${WAYFINDING_TICKET_TYPE} } }`,
106
+ ' assignee:',
107
+ ...ASSIGNEE,
108
+ ' conversation: { type: string, format: uuid }',
109
+ ` app: { type: string, pattern: '${APP_REFERENCE_PATTERN.source}' }`,
110
+ ' required: [title, kind, status, map, blocked_by]',
111
+ ' sections:',
112
+ ' Question: { kind: text }',
113
+ ' Answer: { kind: text }',
114
+ ' allOf:',
115
+ ' - if: { properties: { status: { enum: [in-progress, done, out-of-scope] } }, required: [status] }',
116
+ ' then: { required: [assignee] }',
117
+ ' else: { properties: { assignee: false } }',
118
+ ' - if: { properties: { assignee: { required: [agent] } }, required: [assignee] }',
119
+ ' else: { properties: { conversation: false } }',
120
+ ' - if: { properties: { status: { enum: [done, out-of-scope] } }, required: [status] }',
121
+ ' then: { sections: { Answer: { kind: text, required: true } } }',
122
+ HOUSE_MODEL_TYPES,
123
+ ].join('\n');
@@ -0,0 +1,5 @@
1
+ import type { SearchAnswer, SearchAsk } from '@agentshouse/mdruntime';
2
+ import type { TrackedAuthority } from './discovery.js';
3
+ import { type HouseTransport } from './transport.js';
4
+ export declare function houseSearch(transport: Pick<HouseTransport, 'door'>, tracked: readonly TrackedAuthority[], request: SearchAsk): Promise<SearchAnswer>;
5
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAa,MAAM,wBAAwB,CAAC;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAsBrE,wBAAsB,WAAW,CAC/B,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,EACvC,OAAO,EAAE,SAAS,gBAAgB,EAAE,EACpC,OAAO,EAAE,SAAS,GACjB,OAAO,CAAC,YAAY,CAAC,CAoBvB"}
package/dist/search.js ADDED
@@ -0,0 +1,47 @@
1
+ import { doorRefusal } from './refusal.js';
2
+ import { houseDoorRoute } from './transport.js';
3
+ const ROOMS = '/rooms/';
4
+ const UNCERTAIN = { kind: 'transport-uncertainty' };
5
+ function hitOf(file, locators) {
6
+ if (typeof file !== 'object' || file === null)
7
+ return null;
8
+ const { path, line, snippet } = file;
9
+ if (typeof path !== 'string' || !path.startsWith(ROOMS))
10
+ return null;
11
+ const slash = path.indexOf('/', ROOMS.length);
12
+ if (slash < 0)
13
+ return null;
14
+ const room = locators.get(path.slice(ROOMS.length, slash));
15
+ if (room === undefined)
16
+ return null;
17
+ return {
18
+ room,
19
+ path: path.slice(slash + 1),
20
+ ...(typeof line === 'number' ? { line } : {}),
21
+ ...(typeof snippet === 'string' ? { snippet } : {}),
22
+ };
23
+ }
24
+ export async function houseSearch(transport, tracked, request) {
25
+ const named = request.rooms === null
26
+ ? null
27
+ : tracked.filter((entry) => request.rooms.includes(entry.locator));
28
+ if (named !== null && named.length === 0)
29
+ return { kind: 'found', documents: [] };
30
+ const answer = await transport.door(houseDoorRoute('search'), {
31
+ query: request.text,
32
+ ...(named === null ? {} : { paths: named.map((entry) => `${ROOMS}${entry.handle}`) }),
33
+ });
34
+ if (answer.status === 401)
35
+ return { kind: 'revoked-authorization' };
36
+ const refusal = doorRefusal(answer.body);
37
+ if (refusal !== null)
38
+ return { kind: 'rejected', ...refusal };
39
+ const files = answer.body?.files;
40
+ if (answer.status !== 200 || !Array.isArray(files))
41
+ return UNCERTAIN;
42
+ const locators = new Map(tracked.map((entry) => [entry.handle, entry.locator]));
43
+ return {
44
+ kind: 'found',
45
+ documents: files.flatMap((file) => hitOf(file, locators) ?? []),
46
+ };
47
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAUR,MAAM,wBAAwB,CAAC;AA2BhC,OAAO,EAOL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAyCxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAwR1F"}
1
+ {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAQR,MAAM,wBAAwB,CAAC;AAiBhC,OAAO,EAKL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAuBxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,UAAQ,GAAG,OAAO,CA6K1F"}
package/dist/site.js CHANGED
@@ -1,13 +1,15 @@
1
- import { actionOutcome, SITE_SUBMIT } from './actions.js';
1
+ import { stepped } from '@agentshouse/mdruntime';
2
+ import { actionOutcome } 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 { spaceSchemas } from './space-schema.js';
7
+ import { classifyDoor, discoveryFailure } from './refusal.js';
8
+ import { HOUSE_TYPED_PATHS } from './house-model.js';
9
+ import { HOUSE_NAMEABLE_ROOM_TYPES, HOUSE_ROOM_TYPES } from './room-types.js';
7
10
  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';
11
+ import { houseSiteRoute, SITE_DOOR_SUBMIT, SITE_FILES, SITE_SUBMISSION, } from './transport.js';
12
+ import { followsVersion, logPosition, presented, reachedVersion, roomVersion } from './version.js';
11
13
  const UNCERTAIN = { kind: 'transport-uncertainty' };
12
14
  function unfound() {
13
15
  return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
@@ -18,197 +20,104 @@ function siteRoom(tracked) {
18
20
  locator: tracked.locator,
19
21
  handle: tracked.handle,
20
22
  roomVersion: roomVersion(tracked),
21
- operations: { read: [''], sync: [''], write: [], delete: [] },
22
- replica: { selection: tracked.locator, admission: 'admitted' },
23
+ operations: { write: [], erase: [] },
24
+ replica: { selection: tracked.locator, admission: 'admitted', offline: 'open' },
23
25
  providerOwnedPaths: [],
24
26
  };
25
27
  }
26
- function settled(refused) {
27
- return refused.kind === 'beyond-horizon' ? UNCERTAIN : refused;
28
- }
29
28
  export function createSiteAdapter(transport, snapshot = false) {
30
- const notifications = houseNotifications(transport, 'site');
29
+ const spaces = spaceSchemas();
30
+ const notifications = houseNotifications(transport, 'site', {
31
+ opened: async () => {
32
+ const found = await discovered();
33
+ return found.kind === 'discovery' ? found : null;
34
+ },
35
+ changed: () => null,
36
+ }, spaces);
31
37
  const tracked = new Map();
32
- function published(referrer) {
33
- const named = houseReferrer(referrer, tracked);
34
- return named === null || !tracked.has(named.locator) ? null : named;
35
- }
38
+ const read = new Map();
39
+ const rooms = roomStreams('site', spaces);
36
40
  function fileRoute(request) {
37
- const named = published(request.kind === 'path' ? { room: request.locator, path: request.path } : request.referrer);
38
- if (named === null) {
39
- return { kind: 'rejected', code: 'referrer_unknown', fields: {}, retryable: false };
40
- }
41
- if (request.fileRef === undefined)
42
- return unfound();
43
- const { room_ref, path, record } = named.referrer;
44
- return `${SITE_FILES}${room_ref}/${encodeURIComponent(request.fileRef)}/${path === undefined
45
- ? `${SITE_FILE_RECORD}/${encodeURIComponent(record)}`
46
- : encodeURIComponent(path)}`;
41
+ const entry = tracked.get(request.locator);
42
+ if (entry === undefined)
43
+ return { kind: 'room-not-readable', locator: request.locator };
44
+ return `${SITE_FILES}${entry.authority}/${encodeURIComponent(request.revision)}/${encodeURIComponent(request.path)}`;
47
45
  }
48
- async function enumerated(entry, from, page) {
49
- const answer = await transport.door(SITE_DOOR_ENUMERATE, {
50
- positions: [
51
- page === undefined
52
- ? presented(entry.authority, from)
53
- : {
54
- ...presented(entry.authority, { position: page.after, logEpoch: from.logEpoch }),
55
- page: { through: page.through, read: page.read },
56
- },
57
- ],
58
- });
59
- const classified = classifyRead(answer.status, answer.body, entry.locator);
60
- if (classified !== null)
61
- return classified;
62
- const found = parseEnumeration(answer.body, 'site');
63
- if (found === null)
64
- return UNCERTAIN;
65
- return viewOf(found, entry) ?? { kind: 'room-not-readable', locator: entry.locator };
46
+ async function openedRoom(entry, arriving, signal) {
47
+ const cut = read.get(entry.locator);
48
+ const answered = await transport.streamed(`${houseSiteRoute('bootstrap')}/${entry.authority}${cut === undefined ? '' : `?expired=${cut}`}`, signal ?? new AbortController().signal);
49
+ if (answered.room === null)
50
+ return classifyDoor(answered.status, answered.body, entry.locator) ?? UNCERTAIN;
51
+ const head = await rooms.head(entry, answered.room, arriving, signal);
52
+ const at = head.kind === 'bootstrap' ? logPosition(head.roomVersion) : null;
53
+ if (at !== null)
54
+ read.set(entry.locator, at.position);
55
+ return head;
66
56
  }
67
- async function enumeration(entry, from) {
68
- const first = await enumerated(entry, from);
69
- return 'kind' in first ? first : wholeView(first, (page) => enumerated(entry, from, page));
70
- }
71
- async function bootstrapPart(entry, after, offset) {
72
- const query = [
73
- ...(after === null ? [] : [`after=${encodeURIComponent(after)}`]),
74
- ...(offset === null ? [] : [`offset=${offset}`]),
75
- ];
76
- const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}${query.length === 0 ? '' : `?${query.join('&')}`}`);
77
- const classified = classifyDoor(answer.status, answer.body, entry.locator);
78
- if (classified !== null)
79
- return { failure: classified };
80
- const scope = parseSiteBootstrap(answer.body);
81
- return scope === null ? { failure: UNCERTAIN } : { body: answer.body, scope };
82
- }
83
- async function assembled(entry, scope, path, offset) {
84
- const opened = scope.contents.at(-1);
85
- if (opened === undefined || opened.path !== path || opened.content.length !== offset) {
86
- return UNCERTAIN;
87
- }
88
- let text = opened.content;
89
- for (;;) {
90
- const part = await bootstrapPart(entry, path, text.length);
91
- if ('failure' in part)
92
- return part.failure;
93
- const [piece] = part.scope.contents;
94
- if (piece === undefined ||
95
- part.scope.contents.length !== 1 ||
96
- piece.path !== path ||
97
- piece.content.length === 0) {
98
- return UNCERTAIN;
99
- }
100
- text += piece.content;
101
- const more = siteBootstrapOffset(part.body);
102
- if (more === null)
103
- break;
104
- if (more !== text.length)
105
- return UNCERTAIN;
106
- }
107
- const file = scope.files.find((held) => held.path === path);
108
- if (file === undefined || (await sha256Hex(text)) !== file.version)
109
- return UNCERTAIN;
110
- return { ...scope, contents: [...scope.contents.slice(0, -1), { path, content: text }] };
111
- }
112
- async function caughtUp(entry, after) {
113
- const part = await bootstrapPart(entry, after, null);
114
- if ('failure' in part)
57
+ async function streamedPage(entry, token) {
58
+ const part = await rooms.part(entry, token);
59
+ if ('kind' in part)
115
60
  return part;
116
- const next = siteBootstrapNext(part.body);
117
- const offset = siteBootstrapOffset(part.body);
118
- if (offset !== null) {
119
- if (next === null)
120
- return { failure: UNCERTAIN };
121
- const scope = await assembled(entry, part.scope, next, offset);
122
- return 'kind' in scope ? { failure: scope } : { scope, next };
123
- }
124
- const { scope } = part;
125
- if (after !== null || next !== null || roomVersion(scope) === roomVersion(entry)) {
126
- return { scope, next };
127
- }
128
- const view = await enumeration(entry, scope);
129
- if ('kind' in view)
130
- return { failure: settled(view) };
131
- return { scope: advancedScope(scope, view), next: null };
61
+ const { folders: _folders, ...page } = await stepped(bootstrapping(part.scope));
62
+ return {
63
+ ...page,
64
+ ...(part.models === undefined ? {} : { models: part.models }),
65
+ ...(part.pageToken === undefined ? {} : { pageToken: part.pageToken }),
66
+ bytes: part.bytes,
67
+ };
132
68
  }
133
- async function refreshed(entry, fromRoomVersion) {
134
- const from = logPosition(fromRoomVersion);
135
- if (from === null)
136
- return { kind: 'beyond-horizon' };
137
- const streamed = notifications.advance(entry, from);
138
- if (streamed !== null) {
139
- const models = await streamedModels(streamed.schemas, entry, 'site');
140
- return models === undefined ? streamed.page : { ...streamed.page, models };
141
- }
142
- const view = await enumeration(entry, from);
143
- if ('kind' in view)
144
- return view;
145
- notifications.reach(entry.authority, view);
146
- const answer = refreshFrom(view, fromRoomVersion);
147
- if (answer.kind !== 'net-advancement')
148
- return answer;
149
- const models = await viewModels(view, entry);
150
- return models === undefined ? answer : { ...answer, models };
69
+ async function discovered() {
70
+ const answer = await transport.read(houseSiteRoute('discover'));
71
+ const failed = discoveryFailure(answer.status, answer.body);
72
+ if (failed !== null)
73
+ return failed;
74
+ const document = parseSiteDiscovery(answer.body);
75
+ if (document === null)
76
+ return UNCERTAIN;
77
+ const entries = siteTracked(document);
78
+ tracked.clear();
79
+ for (const entry of entries)
80
+ tracked.set(entry.locator, entry);
81
+ notifications.track(entries);
82
+ return mapDiscovery(document, entries.map(siteRoom), siteCapabilities());
151
83
  }
152
84
  return {
153
85
  localSaves: true,
154
- exhaustiveDiscovery: true,
86
+ roomTypes: HOUSE_ROOM_TYPES,
87
+ nameableRoomTypes: HOUSE_NAMEABLE_ROOM_TYPES,
88
+ typedPaths: HOUSE_TYPED_PATHS,
155
89
  async authorize() {
156
90
  return {};
157
91
  },
158
- async discover() {
159
- const answer = await transport.read(SITE_DOOR_DISCOVER);
160
- const failed = discoveryFailure(answer.status, answer.body);
161
- if (failed !== null)
162
- return failed;
163
- const document = parseSiteDiscovery(answer.body);
164
- if (document === null)
165
- return UNCERTAIN;
166
- const entries = siteTracked(document);
167
- tracked.clear();
168
- for (const entry of entries)
169
- tracked.set(entry.locator, entry);
170
- notifications.track(entries);
171
- return mapDiscovery(document, entries.map(siteRoom), siteCapabilities());
172
- },
173
92
  async bootstrap(_authorization, request) {
174
93
  const entry = tracked.get(request.locator);
175
94
  if (entry === undefined)
176
95
  return { kind: 'room-not-readable', locator: request.locator };
177
- const continued = request.pageToken === undefined
178
- ? null
179
- : JSON.parse(request.pageToken);
180
- const held = await caughtUp(entry, continued?.after ?? null);
181
- if ('failure' in held)
182
- return held.failure;
183
- notifications.reach(entry.authority, held.scope);
184
- const seen = [
185
- ...(continued?.seen ?? []),
186
- ...entry.schemas.filter((schema) => held.scope.files.some((file) => file.path === schema)),
187
- ];
188
- const models = await partModels(held.scope, entry, new Set(seen), held.next === null);
189
- const continuation = held.next === null ? null : { after: held.next, seen };
190
- return {
191
- ...bootstrapOf(held.scope),
192
- ...(models === undefined ? {} : { models }),
193
- ...(continuation === null ? {} : { pageToken: JSON.stringify(continuation) }),
194
- };
96
+ return request.pageToken === undefined
97
+ ? openedRoom(entry, request.arriving, request.signal)
98
+ : streamedPage(entry, request.pageToken);
195
99
  },
196
- async refresh(_authorization, request) {
197
- const entry = tracked.get(request.locator);
198
- if (entry === undefined)
199
- return { kind: 'room-not-readable', locator: request.locator };
200
- if (request.pageToken !== undefined)
201
- return UNCERTAIN;
202
- if (snapshot) {
203
- return request.fromRoomVersion === roomVersion(entry)
204
- ? { kind: 'still-current' }
205
- : { kind: 'beyond-horizon' };
100
+ ...(snapshot
101
+ ? {
102
+ discover: discovered,
103
+ async refresh(_authorization, request) {
104
+ const entry = tracked.get(request.locator);
105
+ if (entry === undefined)
106
+ return { kind: 'room-not-readable', locator: request.locator };
107
+ if (request.pageToken !== undefined)
108
+ return UNCERTAIN;
109
+ return request.fromRoomVersion === roomVersion(entry)
110
+ ? { kind: 'still-current' }
111
+ : { kind: 'beyond-horizon' };
112
+ },
206
113
  }
207
- return refreshed(entry, request.fromRoomVersion);
208
- },
114
+ : {}),
209
115
  async mutate() {
210
116
  return { kind: 'rejected', affected: {}, code: 'write-grant', fields: {}, retryable: false };
211
117
  },
118
+ async attach() {
119
+ return { kind: 'rejected', code: 'write-grant', fields: {}, retryable: false };
120
+ },
212
121
  async history() {
213
122
  return { kind: 'no-history' };
214
123
  },
@@ -219,8 +128,8 @@ export function createSiteAdapter(transport, snapshot = false) {
219
128
  const read = await transport.download(route);
220
129
  if (read.status === 404)
221
130
  return unfound();
222
- return read.status === 200 && read.blob !== null
223
- ? { kind: 'binary', blob: read.blob }
131
+ return read.status === 200 && read.body !== null
132
+ ? { kind: 'binary', body: read.body, mediaType: read.mediaType }
224
133
  : UNCERTAIN;
225
134
  },
226
135
  async link(_authorization, request) {
@@ -233,13 +142,6 @@ export function createSiteAdapter(transport, snapshot = false) {
233
142
  name: request.path.slice(request.path.lastIndexOf('/') + 1),
234
143
  };
235
144
  },
236
- referrerScope(referrer) {
237
- const named = published(referrer);
238
- if (named === null)
239
- return null;
240
- const { path } = named.referrer;
241
- return { kind: 'room', locator: named.locator, ...(path === undefined ? {} : { path }) };
242
- },
243
145
  reached(locator, version, target) {
244
146
  return reachedVersion(version, target, tracked.get(locator)?.logEpoch);
245
147
  },
@@ -247,7 +149,7 @@ export function createSiteAdapter(transport, snapshot = false) {
247
149
  return followsVersion(version, next);
248
150
  },
249
151
  async action(_authorization, request) {
250
- if (request.name !== SITE_SUBMIT) {
152
+ if (request.name !== SITE_SUBMISSION) {
251
153
  return {
252
154
  kind: 'rejected',
253
155
  code: 'action-unimplemented',
@@ -257,7 +159,7 @@ export function createSiteAdapter(transport, snapshot = false) {
257
159
  }
258
160
  if (!transport.online())
259
161
  return UNCERTAIN;
260
- return actionOutcome(await transport.door(SITE_DOOR_SUBMIT, request.input), SITE_SUBMIT);
162
+ return actionOutcome(await transport.door(SITE_DOOR_SUBMIT, request.input), SITE_SUBMISSION, request.input);
261
163
  },
262
164
  roomStream: snapshot
263
165
  ? undefined
@@ -266,19 +168,10 @@ export function createSiteAdapter(transport, snapshot = false) {
266
168
  notifications.send(rooms.flatMap((room) => {
267
169
  const entry = tracked.get(room.locator);
268
170
  const at = logPosition(room.roomVersion);
269
- if (entry === undefined || at === null)
270
- return [];
271
- notifications.reach(entry.authority, at);
272
- return [presented(entry.authority, at)];
171
+ return entry === undefined || at === null ? [] : [presented(entry.authority, at)];
273
172
  }));
274
173
  },
275
- reopen: notifications.reopen,
276
174
  observe: notifications.observe,
277
- published(locator, roomVersion) {
278
- const at = logPosition(roomVersion);
279
- if (at !== null)
280
- notifications.published(locator, at);
281
- },
282
175
  },
283
176
  serviceMode: notifications.serviceMode,
284
177
  };
@@ -0,0 +1,7 @@
1
+ export type SpaceSchemas = {
2
+ held(space: string, revision: string): string | undefined;
3
+ keep(space: string, revision: string, text: string): void;
4
+ };
5
+ export declare function spaceSchemas(): SpaceSchemas;
6
+ export declare function spaceIdentity(space: string): string;
7
+ //# sourceMappingURL=space-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"space-schema.d.ts","sourceRoot":"","sources":["../src/space-schema.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAC1D,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3D,CAAC;AAEF,wBAAgB,YAAY,IAAI,YAAY,CAY3C;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD"}
@@ -0,0 +1,18 @@
1
+ const HELD_TEXTS = 16;
2
+ export function spaceSchemas() {
3
+ const texts = new Map();
4
+ const key = (space, revision) => `${space} ${revision}`;
5
+ return {
6
+ held: (space, revision) => texts.get(key(space, revision)),
7
+ keep(space, revision, text) {
8
+ const named = key(space, revision);
9
+ texts.delete(named);
10
+ texts.set(named, text);
11
+ if (texts.size > HELD_TEXTS)
12
+ texts.delete(texts.keys().next().value);
13
+ },
14
+ };
15
+ }
16
+ export function spaceIdentity(space) {
17
+ return `space:${space}`;
18
+ }