@agentshouse/mdruntime-adapter 0.1.0-ccd2ccb1f7214 → 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.
package/dist/handed.js CHANGED
@@ -1,38 +1,45 @@
1
+ import { entriesIn, patching } from '@agentshouse/mdruntime';
1
2
  import { roomVersion } from './version.js';
2
- export function scopeHanded(scope) {
3
- return {
4
- roomVersion: roomVersion(scope),
5
- revisions: new Map(scope.files.flatMap(({ path, revision }) => revision === undefined ? [] : [[path, revision]])),
6
- };
3
+ function* revised(files) {
4
+ for (const { path, revision } of files)
5
+ if (revision !== undefined)
6
+ yield [path, revision];
7
7
  }
8
- function revised(revisions, path, revision) {
9
- if (revision === undefined)
10
- revisions.delete(path);
11
- else
12
- revisions.set(path, revision);
8
+ export function* scopeHanded(scope) {
9
+ return { roomVersion: roomVersion(scope), revisions: yield* patching({}, revised(scope.files)) };
13
10
  }
14
11
  export function heldHanded(held) {
15
- return { roomVersion: held.roomVersion, revisions: new Map(Object.entries(held.revisions)) };
16
- }
17
- export function acceptedHanded(held, accepted, roomVersion) {
18
- const revisions = new Map(held.revisions);
19
- for (const [path, revision] of Object.entries(accepted.revisions))
20
- revisions.set(path, revision);
21
- for (const path of accepted.removals)
22
- revisions.delete(path);
23
- return { roomVersion, revisions };
24
- }
25
- export function enumeratedHanded(view, earlier) {
26
- const revisions = new Map(earlier?.revisions);
12
+ return { roomVersion: held.roomVersion, revisions: held.revisions };
13
+ }
14
+ export function* acceptedHanded(held, accepted, roomVersion) {
15
+ return {
16
+ roomVersion,
17
+ revisions: yield* patching(held.revisions, entriesIn(accepted.revisions), accepted.removals),
18
+ };
19
+ }
20
+ function* kept(view) {
27
21
  for (const change of view.changes) {
28
- revised(revisions, change.path, 'removed' in change ? undefined : change.revision);
22
+ if (!('removed' in change) && change.revision !== undefined) {
23
+ yield [change.path, change.revision];
24
+ }
29
25
  }
30
- return { roomVersion: roomVersion(view), revisions };
31
26
  }
32
- export function streamedHanded(held, advanced) {
33
- const revisions = new Map(held.revisions);
34
- for (const entry of advanced.entries) {
35
- revised(revisions, entry.path, entry.kind === 'removed' ? undefined : entry.revision);
27
+ function* dropped(view) {
28
+ for (const change of view.changes) {
29
+ if ('removed' in change || change.revision === undefined)
30
+ yield change.path;
36
31
  }
37
- return { roomVersion: advanced.page.roomVersion, revisions };
32
+ }
33
+ export function* enumeratedHanded(view, earlier) {
34
+ return {
35
+ roomVersion: roomVersion(view),
36
+ revisions: yield* patching(earlier?.revisions ?? {}, kept(view), dropped(view)),
37
+ };
38
+ }
39
+ export function* streamedHanded(held, advanced) {
40
+ const { page } = advanced;
41
+ return {
42
+ roomVersion: page.roomVersion,
43
+ revisions: yield* patching(held.revisions, entriesIn(page.revisions), page.removals),
44
+ };
38
45
  }
package/dist/part.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ import type { ScopedRefusal } from '@agentshouse/mdruntime';
2
+ export declare const PART_ATTEMPTS = 3;
3
+ export declare const PART_UNVERIFIED = "part_unverified";
4
+ export type HousePart = {
5
+ part: string;
6
+ bytes: number;
7
+ sha256: string;
8
+ };
9
+ export declare function parsePart(value: unknown): HousePart | null;
10
+ export declare function checkedPayload(body: unknown, listed: HousePart): Promise<Uint8Array<ArrayBuffer> | null>;
11
+ export declare function gunzipped(payload: Uint8Array<ArrayBuffer>): Promise<string | null>;
12
+ export declare function unverifiedPart(locator: string): ScopedRefusal;
13
+ //# sourceMappingURL=part.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"part.d.ts","sourceRoot":"","sources":["../src/part.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAU5D,eAAO,MAAM,aAAa,IAAI,CAAC;AAE/B,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAEjD,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAO1D;AAoBD,wBAAsB,cAAc,CAClC,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,SAAS,GAChB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,CAiBzC;AAED,wBAAsB,SAAS,CAAC,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOxF;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAS7D"}
package/dist/part.js ADDED
@@ -0,0 +1,80 @@
1
+ const PART_MAGIC = 0x48505431;
2
+ const PART_HEAD_BYTES = 8;
3
+ const PART_DIGEST_BYTES = 32;
4
+ const PART_SHA256 = /^[0-9a-f]{64}$/u;
5
+ export const PART_ATTEMPTS = 3;
6
+ export const PART_UNVERIFIED = 'part_unverified';
7
+ export function parsePart(value) {
8
+ if (typeof value !== 'object' || value === null)
9
+ return null;
10
+ const { part, bytes, sha256 } = value;
11
+ if (typeof part !== 'string' || part.length === 0)
12
+ return null;
13
+ if (typeof bytes !== 'number' || !Number.isSafeInteger(bytes) || bytes <= 0)
14
+ return null;
15
+ if (typeof sha256 !== 'string' || !PART_SHA256.test(sha256))
16
+ return null;
17
+ return { part, bytes, sha256 };
18
+ }
19
+ function decoded(text) {
20
+ let binary;
21
+ try {
22
+ binary = atob(text);
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ const bytes = new Uint8Array(binary.length);
28
+ for (let at = 0; at < binary.length; at += 1)
29
+ bytes[at] = binary.charCodeAt(at);
30
+ return bytes;
31
+ }
32
+ function hex(bytes) {
33
+ let text = '';
34
+ for (const byte of bytes)
35
+ text += byte.toString(16).padStart(2, '0');
36
+ return text;
37
+ }
38
+ export async function checkedPayload(body, listed) {
39
+ if (typeof body !== 'object' || body === null)
40
+ return null;
41
+ const { part } = body;
42
+ if (typeof part !== 'string')
43
+ return null;
44
+ const frame = decoded(part);
45
+ if (frame === null || frame.length !== listed.bytes)
46
+ return null;
47
+ if (frame.length < PART_HEAD_BYTES + PART_DIGEST_BYTES)
48
+ return null;
49
+ const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
50
+ if (view.getUint32(0) !== PART_MAGIC)
51
+ return null;
52
+ const length = view.getUint32(4);
53
+ if (PART_HEAD_BYTES + length + PART_DIGEST_BYTES !== frame.length)
54
+ return null;
55
+ const payload = frame.subarray(PART_HEAD_BYTES, PART_HEAD_BYTES + length);
56
+ const digest = hex(new Uint8Array(await crypto.subtle.digest('SHA-256', payload)));
57
+ if (digest !== listed.sha256 || hex(frame.subarray(PART_HEAD_BYTES + length)) !== digest) {
58
+ return null;
59
+ }
60
+ return payload;
61
+ }
62
+ export async function gunzipped(payload) {
63
+ try {
64
+ const stream = new Blob([payload]).stream().pipeThrough(new DecompressionStream('gzip'));
65
+ return await new Response(stream).text();
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ }
71
+ export function unverifiedPart(locator) {
72
+ return {
73
+ kind: 'scoped-refusal',
74
+ locator,
75
+ scope: 'undisclosed',
76
+ code: PART_UNVERIFIED,
77
+ fields: {},
78
+ retryable: true,
79
+ };
80
+ }
package/dist/read.d.ts CHANGED
@@ -1,11 +1,28 @@
1
- import type { AdapterFailure, BinaryFile, BootstrapPage, RefreshResult } from '@agentshouse/mdruntime';
1
+ import { type AdapterFailure, type BinaryFile, type BootstrapPage, type RefreshResult, type TransportUncertainty } from '@agentshouse/mdruntime';
2
2
  import type { TrackedAuthority } from './discovery.js';
3
+ import { type HousePart } from './part.js';
3
4
  import type { HouseMode } from './transport.js';
4
5
  import { type LogPosition } from './version.js';
5
6
  export type HeadChange = BootstrapPage['changes'][string];
6
- export declare function identities(revisions: Readonly<Record<string, string>>): {
7
- fileIds?: Record<string, string>;
7
+ export type Answered = {
8
+ readonly documents: Map<string, string>;
9
+ readonly revisions: Map<string, string>;
10
+ readonly fileIds: Map<string, string>;
11
+ readonly changes: Map<string, HeadChange>;
12
+ readonly binaryFiles: Map<string, BinaryFile>;
13
+ readonly removals: Set<string>;
8
14
  };
15
+ export declare function answering(): Answered;
16
+ export declare function revised(answer: Answered, path: string, revision: string): void;
17
+ export declare function forgotten(answer: Answered, path: string): void;
18
+ export declare function answered(answer: Answered): Generator<number, {
19
+ documents: Readonly<Record<string, string>>;
20
+ revisions: Readonly<Record<string, string>>;
21
+ fileIds?: Readonly<Record<string, string>>;
22
+ changes: Readonly<Record<string, HeadChange>>;
23
+ binaryFiles: Readonly<Record<string, BinaryFile>>;
24
+ removals: readonly string[];
25
+ }, void>;
9
26
  export type HouseManifestFile = {
10
27
  path: string;
11
28
  revision: string | undefined;
@@ -23,18 +40,13 @@ export type HouseScope = LogPosition & {
23
40
  files: readonly HouseManifestFile[];
24
41
  contents: readonly HouseContent[];
25
42
  };
26
- export type HouseCut = {
27
- position: string;
28
- log_epoch: string;
29
- };
30
- export type HouseCursor = {
31
- room: string;
32
- path: string | null;
33
- cut?: HouseCut;
43
+ export type HouseRoomParts = LogPosition & {
44
+ anchor: string;
45
+ parts: readonly HousePart[];
34
46
  };
35
- export type HouseEnvelope = {
36
- scopes: readonly HouseScope[];
37
- next?: HouseCursor;
47
+ export type HouseParted = {
48
+ rooms: readonly HouseRoomParts[];
49
+ next?: string;
38
50
  };
39
51
  export type HouseGrant = {
40
52
  method: 'GET';
@@ -77,7 +89,6 @@ export type HouseEnumeration = {
77
89
  authorities: readonly HouseView[];
78
90
  };
79
91
  export declare function authorityRoot(handle: string): string;
80
- export declare function contentPrefixes(tracked: TrackedAuthority): readonly string[];
81
92
  export declare function schemaPath(handle: string, schema: string): string;
82
93
  export declare function parseGrant(body: unknown): HouseGrant | null;
83
94
  export declare function headChange(held: {
@@ -85,15 +96,14 @@ export declare function headChange(held: {
85
96
  readonly created_at?: unknown;
86
97
  }): HeadChange | undefined | null;
87
98
  export declare function binaryFileOf(held: Readonly<Record<string, unknown>>): BinaryFile | undefined | null;
88
- export declare function parseEnvelope(body: unknown): HouseEnvelope | null;
89
- export declare function parseSiteBootstrap(body: unknown): HouseScope | null;
90
- export declare function siteBootstrapNext(body: unknown): string | null;
91
- export declare function siteBootstrapOffset(body: unknown): number | null;
99
+ export declare function parseParted(body: unknown): HouseParted | null;
100
+ export declare function parseSiteParted(body: unknown): HouseRoomParts | null;
101
+ export declare function emptyScope(room: HouseRoomParts): HouseScope;
102
+ export declare function housePart(room: HouseRoomParts, body: unknown, listed: HousePart, mode: HouseMode): Promise<HouseScope | TransportUncertainty | null>;
92
103
  export declare function parseEnumeration(body: unknown, mode: HouseMode): HouseEnumeration | null;
93
104
  export declare function wholeView(first: HouseView, more: (page: HousePage) => Promise<HouseView | PageFailure>): Promise<HouseView | PageFailure>;
94
- export declare function advancedScope(scope: HouseScope, view: HouseView): HouseScope;
95
- export declare function matchesScope(scope: HouseScope, tracked: TrackedAuthority): boolean;
96
- export declare function bootstrapOf(scope: HouseScope): BootstrapPage;
105
+ export declare function advancedScope(scope: HouseScope, view: HouseView): Generator<number, HouseScope, void>;
106
+ export declare function bootstrapping(scope: HouseScope): Generator<number, BootstrapPage, void>;
97
107
  export type HouseSchema = {
98
108
  schema: string | null;
99
109
  version: string | null;
@@ -101,6 +111,6 @@ export type HouseSchema = {
101
111
  };
102
112
  export declare function schemaOf(scope: HouseScope, schema: string): HouseSchema | null;
103
113
  export declare function viewOf(enumeration: HouseEnumeration, tracked: TrackedAuthority): HouseView | undefined;
104
- export declare function refreshFrom(view: HouseView, fromRoomVersion: string): RefreshResult;
114
+ export declare function refreshFrom(view: HouseView, fromRoomVersion: string): Promise<RefreshResult>;
105
115
  export {};
106
116
  //# sourceMappingURL=read.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../src/read.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../src/read.ts"],"names":[],"mappings":"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"}
package/dist/read.js CHANGED
@@ -1,21 +1,52 @@
1
+ import { patching, ROW_WEIGHT, stepped, } from '@agentshouse/mdruntime';
2
+ import { checkedPayload, gunzipped, parsePart } from './part.js';
1
3
  import { DECIMAL, readPosition, roomVersion } from './version.js';
2
4
  const REVISION_FILE = /^fr_([0-9a-z]+)\.[0-9a-z]+\.[0-9a-z]$/u;
3
- export function identities(revisions) {
4
- const fileIds = Object.fromEntries(Object.entries(revisions).flatMap(([path, revision]) => {
5
- const file = REVISION_FILE.exec(revision)?.[1];
6
- return file === undefined ? [] : [[path, file]];
7
- }));
8
- return Object.keys(fileIds).length === 0 ? {} : { fileIds };
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
+ };
9
46
  }
10
47
  export function authorityRoot(handle) {
11
48
  return `/rooms/${handle}`;
12
49
  }
13
- export function contentPrefixes(tracked) {
14
- return [
15
- authorityRoot(tracked.handle),
16
- ...tracked.schemas.map((schema) => schemaPath(tracked.handle, schema)),
17
- ];
18
- }
19
50
  export function schemaPath(handle, schema) {
20
51
  return `${authorityRoot(handle)}/${schema}`;
21
52
  }
@@ -105,13 +136,13 @@ function parseFile(value, mode) {
105
136
  ...binaried(binary),
106
137
  };
107
138
  }
108
- function parseScope(value, mode) {
139
+ function parseRoomParts(value) {
109
140
  if (typeof value !== 'object' || value === null)
110
141
  return null;
111
142
  const held = value;
112
143
  if (typeof held.manifest !== 'object' || held.manifest === null)
113
144
  return null;
114
- if (!Array.isArray(held.contents))
145
+ if (!Array.isArray(held.parts))
115
146
  return null;
116
147
  const manifest = held.manifest;
117
148
  if (manifest.scope !== 'room')
@@ -121,78 +152,89 @@ function parseScope(value, mode) {
121
152
  return null;
122
153
  if (typeof manifest.room_handle !== 'string' || manifest.room_handle.length === 0)
123
154
  return null;
124
- if (!Array.isArray(manifest.files))
125
- return null;
126
- const files = [];
127
- for (const entry of manifest.files) {
128
- const file = parseFile(entry, mode);
129
- if (file === null)
130
- return null;
131
- files.push(file);
132
- }
133
- const contents = [];
134
- for (const entry of held.contents) {
135
- if (typeof entry !== 'object' || entry === null)
155
+ const parts = [];
156
+ for (const entry of held.parts) {
157
+ const part = parsePart(entry);
158
+ if (part === null)
136
159
  return null;
137
- const content = entry;
138
- if (typeof content.path !== 'string' || typeof content.content !== 'string')
139
- return null;
140
- contents.push({ path: content.path, content: content.content });
160
+ parts.push(part);
141
161
  }
142
- return { anchor: manifest.anchor, ...at, files, contents };
143
- }
144
- function parseCut(value) {
145
- if (value === undefined)
146
- return undefined;
147
- if (typeof value !== 'object' || value === null)
148
- return null;
149
- const { position, log_epoch: logEpoch } = value;
150
- if (typeof position !== 'string' || typeof logEpoch !== 'string')
151
- return null;
152
- return { position, log_epoch: logEpoch };
162
+ return { anchor: manifest.anchor, ...at, parts };
153
163
  }
154
- function parseCursor(value) {
155
- if (typeof value !== 'object' || value === null)
156
- return null;
157
- const { room, path, cut } = value;
158
- if (typeof room !== 'string' || (path !== null && typeof path !== 'string'))
159
- return null;
160
- const parsed = parseCut(cut);
161
- if (parsed === null)
162
- return null;
163
- return { room, path, ...(parsed === undefined ? {} : { cut: parsed }) };
164
- }
165
- export function parseEnvelope(body) {
164
+ export function parseParted(body) {
166
165
  if (typeof body !== 'object' || body === null)
167
166
  return null;
168
167
  if (!('scopes' in body) || !Array.isArray(body.scopes))
169
168
  return null;
170
- const scopes = [];
169
+ const rooms = [];
171
170
  for (const entry of body.scopes) {
172
- const scope = parseScope(entry, 'credential');
173
- if (scope === null)
171
+ const room = parseRoomParts(entry);
172
+ if (room === null)
174
173
  return null;
175
- scopes.push(scope);
174
+ rooms.push(room);
176
175
  }
177
176
  if (!('next' in body) || body.next === undefined)
178
- return { scopes };
179
- const next = parseCursor(body.next);
180
- return next === null ? null : { scopes, next };
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 };
181
182
  }
182
- export function parseSiteBootstrap(body) {
183
- return parseScope(body, 'site');
183
+ export function parseSiteParted(body) {
184
+ return parseRoomParts(body);
184
185
  }
185
- export function siteBootstrapNext(body) {
186
- if (typeof body !== 'object' || body === null || !('next' in body))
187
- return null;
188
- return typeof body.next === 'string' && body.next.length > 0 ? body.next : null;
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;
189
230
  }
190
- export function siteBootstrapOffset(body) {
191
- if (typeof body !== 'object' || body === null || !('offset' in body))
231
+ export async function housePart(room, body, listed, mode) {
232
+ const payload = await checkedPayload(body, listed);
233
+ if (payload === null)
192
234
  return null;
193
- return Number.isSafeInteger(body.offset) && body.offset > 0
194
- ? body.offset
195
- : 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 };
196
238
  }
197
239
  function parseChange(value, mode) {
198
240
  if (typeof value !== 'object' || value === null)
@@ -310,12 +352,21 @@ export async function wholeView(first, more) {
310
352
  changes: [...changes.values()],
311
353
  };
312
354
  }
313
- export function advancedScope(scope, view) {
314
- const files = new Map(scope.files.map((file) => [file.path, file]));
315
- const contents = new Map(scope.contents.map((entry) => [entry.path, entry.content]));
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
+ }
316
366
  for (const change of view.changes) {
317
367
  files.delete(change.path);
318
368
  contents.delete(change.path);
369
+ yield ROW_WEIGHT;
319
370
  if ('removed' in change)
320
371
  continue;
321
372
  files.set(change.path, {
@@ -328,43 +379,40 @@ export function advancedScope(scope, view) {
328
379
  if ('content' in change)
329
380
  contents.set(change.path, change.content);
330
381
  }
382
+ const listed = [];
383
+ for (const [path, content] of contents) {
384
+ listed.push({ path, content });
385
+ yield ROW_WEIGHT;
386
+ }
331
387
  return {
332
388
  ...scope,
333
389
  position: view.position,
334
390
  logEpoch: view.logEpoch,
335
391
  files: [...files.values()],
336
- contents: [...contents].map(([path, content]) => ({ path, content })),
392
+ contents: listed,
337
393
  };
338
394
  }
339
- export function matchesScope(scope, tracked) {
340
- return scope.anchor === tracked.authority;
341
- }
342
- export function bootstrapOf(scope) {
343
- const contents = new Map(scope.contents.map((entry) => [entry.path, entry.content]));
344
- const documents = {};
345
- const revisions = {};
346
- const changes = {};
347
- const binaryFiles = {};
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();
348
402
  for (const file of scope.files) {
349
- if (file.revision !== undefined)
350
- revisions[file.path] = file.revision;
403
+ yield ROW_WEIGHT;
351
404
  if (file.head !== undefined)
352
- changes[file.path] = file.head;
405
+ answer.changes.set(file.path, file.head);
353
406
  const content = contents.get(file.path);
354
407
  if (file.binary !== undefined)
355
- binaryFiles[file.path] = file.binary;
408
+ answer.binaryFiles.set(file.path, file.binary);
356
409
  else if (content !== undefined)
357
- documents[file.path] = content;
410
+ answer.documents.set(file.path, content);
411
+ if (file.revision !== undefined)
412
+ revised(answer, file.path, file.revision);
358
413
  }
359
- return {
360
- kind: 'bootstrap',
361
- roomVersion: roomVersion(scope),
362
- documents,
363
- revisions,
364
- ...identities(revisions),
365
- changes,
366
- binaryFiles,
367
- };
414
+ const { removals: _removals, ...page } = yield* answered(answer);
415
+ return { kind: 'bootstrap', roomVersion: roomVersion(scope), ...page };
368
416
  }
369
417
  export function schemaOf(scope, schema) {
370
418
  const file = scope.files.find((entry) => entry.path === schema);
@@ -378,36 +426,27 @@ export function schemaOf(scope, schema) {
378
426
  export function viewOf(enumeration, tracked) {
379
427
  return enumeration.authorities.find((entry) => entry.authority === tracked.authority);
380
428
  }
381
- export function refreshFrom(view, fromRoomVersion) {
429
+ function* refreshing(view, fromRoomVersion) {
382
430
  if (roomVersion(view) === fromRoomVersion)
383
431
  return { kind: 'still-current' };
384
- const documents = {};
385
- const revisions = {};
386
- const changes = {};
387
- const binaryFiles = {};
388
- const removals = [];
432
+ const answer = answering();
389
433
  for (const change of view.changes) {
434
+ yield ROW_WEIGHT;
390
435
  if ('removed' in change) {
391
- removals.push(change.path);
436
+ answer.removals.add(change.path);
392
437
  continue;
393
438
  }
394
439
  if ('content' in change)
395
- documents[change.path] = change.content;
440
+ answer.documents.set(change.path, change.content);
396
441
  else
397
- binaryFiles[change.path] = change.binary;
398
- if (change.revision !== undefined)
399
- revisions[change.path] = change.revision;
442
+ answer.binaryFiles.set(change.path, change.binary);
400
443
  if (change.head !== undefined)
401
- changes[change.path] = change.head;
444
+ answer.changes.set(change.path, change.head);
445
+ if (change.revision !== undefined)
446
+ revised(answer, change.path, change.revision);
402
447
  }
403
- return {
404
- kind: 'net-advancement',
405
- roomVersion: roomVersion(view),
406
- documents,
407
- revisions,
408
- ...identities(revisions),
409
- changes,
410
- binaryFiles,
411
- removals: removals.sort(),
412
- };
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));
413
452
  }