@agentshouse/mdruntime-adapter 0.1.0-cf22c8563f9f4 → 0.1.0-cf9ab9b7cbbca

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 (50) hide show
  1. package/AGENTS.md +269 -214
  2. package/dist/actions.d.ts +62 -1
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +153 -133
  5. package/dist/adapter.d.ts +1 -0
  6. package/dist/adapter.d.ts.map +1 -1
  7. package/dist/adapter.js +286 -91
  8. package/dist/discovery.d.ts +3 -1
  9. package/dist/discovery.d.ts.map +1 -1
  10. package/dist/discovery.js +18 -3
  11. package/dist/gather.d.ts +1 -0
  12. package/dist/gather.d.ts.map +1 -1
  13. package/dist/gather.js +11 -6
  14. package/dist/handed.d.ts +15 -0
  15. package/dist/handed.d.ts.map +1 -0
  16. package/dist/handed.js +38 -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 +21 -7
  23. package/dist/read.d.ts +35 -7
  24. package/dist/read.d.ts.map +1 -1
  25. package/dist/read.js +160 -79
  26. package/dist/referrer.d.ts +7 -0
  27. package/dist/referrer.d.ts.map +1 -0
  28. package/dist/referrer.js +35 -0
  29. package/dist/refusal.d.ts +2 -5
  30. package/dist/refusal.d.ts.map +1 -1
  31. package/dist/refusal.js +6 -9
  32. package/dist/site.d.ts +1 -1
  33. package/dist/site.d.ts.map +1 -1
  34. package/dist/site.js +165 -48
  35. package/dist/stream.d.ts +6 -4
  36. package/dist/stream.d.ts.map +1 -1
  37. package/dist/stream.js +308 -16
  38. package/dist/transport.d.ts +54 -11
  39. package/dist/transport.d.ts.map +1 -1
  40. package/dist/transport.js +3 -0
  41. package/dist/version.d.ts +1 -0
  42. package/dist/version.d.ts.map +1 -1
  43. package/dist/version.js +1 -1
  44. package/dist/write.d.ts +3 -9
  45. package/dist/write.d.ts.map +1 -1
  46. package/dist/write.js +92 -14
  47. package/package.json +3 -4
  48. package/dist/links.d.ts +0 -20
  49. package/dist/links.d.ts.map +0 -1
  50. package/dist/links.js +0 -104
package/dist/gather.js CHANGED
@@ -1,13 +1,11 @@
1
- export function gathered(send) {
1
+ export function gatheredEach(send) {
2
2
  let held = [];
3
3
  function flush() {
4
4
  const taken = held;
5
5
  held = [];
6
- send(taken.map((entry) => entry.ask)).then((answers) => {
7
- taken.forEach((entry, index) => {
8
- entry.resolve(answers[index]);
9
- });
10
- }, (reason) => {
6
+ send(taken.map((entry) => entry.ask), (ask, result) => {
7
+ taken[ask]?.resolve(result);
8
+ }).catch((reason) => {
11
9
  for (const entry of taken)
12
10
  entry.reject(reason);
13
11
  });
@@ -20,6 +18,13 @@ export function gathered(send) {
20
18
  held.push({ ask, resolve, reject });
21
19
  });
22
20
  }
21
+ export function gathered(send) {
22
+ return gatheredEach(async (asks, answer) => {
23
+ (await send(asks)).forEach((result, ask) => {
24
+ answer(ask, result);
25
+ });
26
+ });
27
+ }
23
28
  export function selections(items, weight, limit) {
24
29
  const parts = [];
25
30
  let part = [];
@@ -0,0 +1,15 @@
1
+ import type { HeldRoom, MutationResult } from '@agentshouse/mdruntime';
2
+ import type { HouseScope, HouseView } from './read.js';
3
+ import type { StreamedAdvancement } from './stream.js';
4
+ export type HandedRoom = {
5
+ roomVersion: string;
6
+ revisions: ReadonlyMap<string, string>;
7
+ };
8
+ export declare function scopeHanded(scope: HouseScope): HandedRoom;
9
+ export declare function heldHanded(held: HeldRoom): HandedRoom;
10
+ export declare function acceptedHanded(held: HandedRoom, accepted: Extract<MutationResult, {
11
+ kind: 'accepted';
12
+ }>, roomVersion: string): HandedRoom;
13
+ export declare function enumeratedHanded(view: HouseView, earlier: HandedRoom | undefined): HandedRoom;
14
+ export declare function streamedHanded(held: HandedRoom, advanced: StreamedAdvancement): HandedRoom;
15
+ //# sourceMappingURL=handed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handed.d.ts","sourceRoot":"","sources":["../src/handed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGvD,MAAM,MAAM,UAAU,GAAG;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC,CAAC;AAEF,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CASzD;AAOD,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,CAErD;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,OAAO,CAAC,cAAc,EAAE;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,EACvD,WAAW,EAAE,MAAM,GAClB,UAAU,CAKZ;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,CAM7F;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,mBAAmB,GAAG,UAAU,CAM1F"}
package/dist/handed.js ADDED
@@ -0,0 +1,38 @@
1
+ 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
+ };
7
+ }
8
+ function revised(revisions, path, revision) {
9
+ if (revision === undefined)
10
+ revisions.delete(path);
11
+ else
12
+ revisions.set(path, revision);
13
+ }
14
+ 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);
27
+ for (const change of view.changes) {
28
+ revised(revisions, change.path, 'removed' in change ? undefined : change.revision);
29
+ }
30
+ return { roomVersion: roomVersion(view), revisions };
31
+ }
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);
36
+ }
37
+ return { roomVersion: advanced.page.roomVersion, revisions };
38
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { createAgentsHouseAdapter, type AgentsHouseAdapterOptions } from './adapter.js';
2
- export type { HouseByteAct, HouseByteAnswer, HouseByteTransfer, HouseDoorAnswer, HouseHeldRoom, HouseOpening, HouseStream, HouseStreamEntry, HouseStreamFrame, HouseSiteTransport, HouseTransport, } from './transport.js';
2
+ export { HOUSE_APP_ACTS, HOUSE_APP_BATCHES, HOUSE_SITE_ACTS } from './actions.js';
3
+ export type { HouseByteAct, HouseByteTransfer, HouseBytesAnswer, HouseClosing, HouseDemand, HouseDoorAnswer, HouseHeldRoom, HouseOpening, HouseStream, HouseStreamEntry, HouseStreamFrame, HouseSiteTransport, HouseTransport, } from './transport.js';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,KAAK,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACxF,YAAY,EACV,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,GACf,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,KAAK,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAClF,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,eAAe,EACf,aAAa,EACb,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,GACf,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
1
  export { createAgentsHouseAdapter } from './adapter.js';
2
+ export { HOUSE_APP_ACTS, HOUSE_APP_BATCHES, HOUSE_SITE_ACTS } from './actions.js';
package/dist/model.d.ts CHANGED
@@ -2,7 +2,7 @@ import type { RoomModels } from '@agentshouse/mdruntime';
2
2
  import type { TrackedAuthority } from './discovery.js';
3
3
  import { type HouseScope, type HouseView } from './read.js';
4
4
  import type { HouseMode, HouseStreamEntry } from './transport.js';
5
- export declare function scopeModels(scope: HouseScope, tracked: TrackedAuthority): Promise<RoomModels | undefined>;
5
+ export declare function partModels(scope: HouseScope, tracked: TrackedAuthority, seen: ReadonlySet<string>, final: boolean): Promise<RoomModels | undefined>;
6
6
  export declare function viewModels(view: HouseView, tracked: TrackedAuthority): Promise<RoomModels | undefined>;
7
7
  export declare function streamedModels(schemas: ReadonlyMap<string, HouseStreamEntry>, tracked: TrackedAuthority, mode: HouseMode): Promise<RoomModels | undefined>;
8
8
  //# sourceMappingURL=model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAA0C,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AACpG,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAiClE,wBAAgB,WAAW,CACzB,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAEjC;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAQjC;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,EAC9C,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CASjC"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAA0C,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AACpG,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAoClE,wBAAgB,UAAU,CACxB,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EACzB,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAKjC;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAcjC;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,EAC9C,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAWjC"}
package/dist/model.js CHANGED
@@ -1,12 +1,15 @@
1
1
  import { sha256Hex } from './digest.js';
2
2
  import { schemaOf, schemaPath } from './read.js';
3
3
  const MODEL_ABSENT = { kind: 'model-unavailable', reason: 'not-readable' };
4
- const ABSENT_SCHEMA = { schema: null, version: null };
4
+ const ABSENT_SCHEMA = { schema: null, version: null, revision: null };
5
5
  async function heldModel(read, identity) {
6
6
  if (read === null)
7
7
  return MODEL_ABSENT;
8
8
  const version = await sha256Hex(JSON.stringify(read.version));
9
- return { kind: 'model', snapshot: { identity, version, schema: read.schema } };
9
+ return {
10
+ kind: 'model',
11
+ snapshot: { identity, version, schema: read.schema, revision: read.revision },
12
+ };
10
13
  }
11
14
  async function modelsOf(tracked, read) {
12
15
  const models = {};
@@ -23,8 +26,12 @@ async function modelsOf(tracked, read) {
23
26
  }
24
27
  return models.collection === undefined && models.selection === undefined ? undefined : models;
25
28
  }
26
- export function scopeModels(scope, tracked) {
27
- return modelsOf(tracked, (schema) => schemaOf(scope, schema));
29
+ export function partModels(scope, tracked, seen, final) {
30
+ return modelsOf(tracked, (schema) => {
31
+ if (scope.files.some((file) => file.path === schema))
32
+ return schemaOf(scope, schema);
33
+ return final && !seen.has(schema) ? ABSENT_SCHEMA : undefined;
34
+ });
28
35
  }
29
36
  export function viewModels(view, tracked) {
30
37
  return modelsOf(tracked, (schema) => {
@@ -33,8 +40,13 @@ export function viewModels(view, tracked) {
33
40
  return undefined;
34
41
  if ('removed' in change)
35
42
  return ABSENT_SCHEMA;
36
- if ('content' in change)
37
- return { schema: change.content, version: change.version };
43
+ if ('content' in change) {
44
+ return {
45
+ schema: change.content,
46
+ version: change.version,
47
+ revision: change.revision ?? null,
48
+ };
49
+ }
38
50
  return null;
39
51
  });
40
52
  }
@@ -48,6 +60,8 @@ export function streamedModels(schemas, tracked, mode) {
48
60
  if (entry.text === undefined)
49
61
  return null;
50
62
  const version = mode === 'site' ? entry.sha256 : entry.revision;
51
- return version === undefined ? null : { schema: entry.text, version };
63
+ return version === undefined
64
+ ? null
65
+ : { schema: entry.text, version, revision: mode === 'site' ? null : version };
52
66
  });
53
67
  }
package/dist/read.d.ts CHANGED
@@ -1,13 +1,18 @@
1
- import type { BootstrapPage, RefreshResult, RoomAttachment } from '@agentshouse/mdruntime';
1
+ import type { AdapterFailure, BinaryFile, BootstrapPage, RefreshResult } from '@agentshouse/mdruntime';
2
2
  import type { TrackedAuthority } from './discovery.js';
3
3
  import type { HouseMode } from './transport.js';
4
4
  import { type LogPosition } from './version.js';
5
5
  export type HeadChange = BootstrapPage['changes'][string];
6
+ export declare function identities(revisions: Readonly<Record<string, string>>): {
7
+ fileIds?: Record<string, string>;
8
+ };
6
9
  export type HouseManifestFile = {
7
10
  path: string;
8
11
  revision: string | undefined;
9
12
  version: string;
13
+ sha256?: string;
10
14
  head?: HeadChange;
15
+ binary?: BinaryFile;
11
16
  };
12
17
  export type HouseContent = {
13
18
  path: string;
@@ -17,10 +22,19 @@ export type HouseScope = LogPosition & {
17
22
  anchor: string;
18
23
  files: readonly HouseManifestFile[];
19
24
  contents: readonly HouseContent[];
20
- attachments?: readonly RoomAttachment[];
25
+ };
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;
21
34
  };
22
35
  export type HouseEnvelope = {
23
36
  scopes: readonly HouseScope[];
37
+ next?: HouseCursor;
24
38
  };
25
39
  export type HouseGrant = {
26
40
  method: 'GET';
@@ -41,14 +55,23 @@ export type HouseChange = {
41
55
  head?: HeadChange;
42
56
  } | {
43
57
  path: string;
44
- reference: {
45
- revision: string;
46
- };
58
+ binary: BinaryFile;
59
+ revision: string | undefined;
60
+ version: string;
61
+ head?: HeadChange;
62
+ };
63
+ export type HousePage = {
64
+ after: string;
65
+ through: string;
66
+ read: number;
47
67
  };
48
68
  export type HouseView = LogPosition & {
49
69
  authority: string;
50
70
  changes: readonly HouseChange[];
51
- attachments?: readonly RoomAttachment[];
71
+ next?: HousePage;
72
+ };
73
+ type PageFailure = AdapterFailure | {
74
+ kind: 'beyond-horizon';
52
75
  };
53
76
  export type HouseEnumeration = {
54
77
  authorities: readonly HouseView[];
@@ -61,18 +84,23 @@ export declare function headChange(held: {
61
84
  readonly author?: unknown;
62
85
  readonly created_at?: unknown;
63
86
  }): HeadChange | undefined | null;
64
- export declare function parseOriginals(value: unknown): readonly RoomAttachment[] | null;
87
+ export declare function binaryFileOf(held: Readonly<Record<string, unknown>>): BinaryFile | undefined | null;
65
88
  export declare function parseEnvelope(body: unknown): HouseEnvelope | null;
66
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;
67
92
  export declare function parseEnumeration(body: unknown, mode: HouseMode): HouseEnumeration | null;
93
+ export declare function wholeView(first: HouseView, more: (page: HousePage) => Promise<HouseView | PageFailure>): Promise<HouseView | PageFailure>;
68
94
  export declare function advancedScope(scope: HouseScope, view: HouseView): HouseScope;
69
95
  export declare function matchesScope(scope: HouseScope, tracked: TrackedAuthority): boolean;
70
96
  export declare function bootstrapOf(scope: HouseScope): BootstrapPage;
71
97
  export type HouseSchema = {
72
98
  schema: string | null;
73
99
  version: string | null;
100
+ revision: string | null;
74
101
  };
75
102
  export declare function schemaOf(scope: HouseScope, schema: string): HouseSchema | null;
76
103
  export declare function viewOf(enumeration: HouseEnumeration, tracked: TrackedAuthority): HouseView | undefined;
77
104
  export declare function refreshFrom(view: HouseView, fromRoomVersion: string): RefreshResult;
105
+ export {};
78
106
  //# 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,4 +1,12 @@
1
- import { readPosition, roomVersion } from './version.js';
1
+ import { DECIMAL, readPosition, roomVersion } from './version.js';
2
+ 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 };
9
+ }
2
10
  export function authorityRoot(handle) {
3
11
  return `/rooms/${handle}`;
4
12
  }
@@ -51,32 +59,19 @@ export function headChange(held) {
51
59
  function headed(head) {
52
60
  return head === undefined ? {} : { head };
53
61
  }
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))
62
+ export function binaryFileOf(held) {
63
+ if (held.file === undefined)
64
+ return undefined;
65
+ const { file, bytes, media_type: mediaType, sha256 } = held;
66
+ if (typeof file !== 'string' ||
67
+ typeof bytes !== 'number' ||
68
+ typeof mediaType !== 'string' ||
69
+ typeof sha256 !== 'string')
68
70
  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;
71
+ return { fileRef: file, byteLength: bytes, mediaType, sha256 };
77
72
  }
78
- function declared(attachments) {
79
- return attachments === undefined ? {} : { attachments };
73
+ function binaried(binary) {
74
+ return binary === undefined ? {} : { binary };
80
75
  }
81
76
  function parseFile(value, mode) {
82
77
  if (typeof value !== 'object' || value === null)
@@ -85,16 +80,30 @@ function parseFile(value, mode) {
85
80
  if (typeof file.path !== 'string')
86
81
  return null;
87
82
  const head = headChange(file);
88
- if (head === null)
83
+ const binary = binaryFileOf(file);
84
+ if (head === null || binary === null)
89
85
  return null;
90
86
  if (mode === 'site') {
91
87
  if (typeof file.sha256 !== 'string')
92
88
  return null;
93
- return { path: file.path, revision: undefined, version: file.sha256, ...headed(head) };
89
+ return {
90
+ path: file.path,
91
+ revision: binary?.sha256,
92
+ version: file.sha256,
93
+ ...headed(head),
94
+ ...binaried(binary),
95
+ };
94
96
  }
95
97
  if (typeof file.revision !== 'string')
96
98
  return null;
97
- return { path: file.path, revision: file.revision, version: file.revision, ...headed(head) };
99
+ return {
100
+ path: file.path,
101
+ revision: file.revision,
102
+ version: file.revision,
103
+ ...(typeof file.sha256 === 'string' ? { sha256: file.sha256 } : {}),
104
+ ...headed(head),
105
+ ...binaried(binary),
106
+ };
98
107
  }
99
108
  function parseScope(value, mode) {
100
109
  if (typeof value !== 'object' || value === null)
@@ -130,12 +139,28 @@ function parseScope(value, mode) {
130
139
  return null;
131
140
  contents.push({ path: content.path, content: content.content });
132
141
  }
133
- if (mode === 'site')
134
- return { anchor: manifest.anchor, ...at, files, contents };
135
- const attachments = parseOriginals(held.originals);
136
- if (attachments === null)
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)
137
148
  return null;
138
- return { anchor: manifest.anchor, ...at, files, contents, attachments };
149
+ const { position, log_epoch: logEpoch } = value;
150
+ if (typeof position !== 'string' || typeof logEpoch !== 'string')
151
+ return null;
152
+ return { position, log_epoch: logEpoch };
153
+ }
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 }) };
139
164
  }
140
165
  export function parseEnvelope(body) {
141
166
  if (typeof body !== 'object' || body === null)
@@ -149,11 +174,26 @@ export function parseEnvelope(body) {
149
174
  return null;
150
175
  scopes.push(scope);
151
176
  }
152
- return { scopes };
177
+ if (!('next' in body) || body.next === undefined)
178
+ return { scopes };
179
+ const next = parseCursor(body.next);
180
+ return next === null ? null : { scopes, next };
153
181
  }
154
182
  export function parseSiteBootstrap(body) {
155
183
  return parseScope(body, 'site');
156
184
  }
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;
189
+ }
190
+ export function siteBootstrapOffset(body) {
191
+ if (typeof body !== 'object' || body === null || !('offset' in body))
192
+ return null;
193
+ return Number.isSafeInteger(body.offset) && body.offset > 0
194
+ ? body.offset
195
+ : null;
196
+ }
157
197
  function parseChange(value, mode) {
158
198
  if (typeof value !== 'object' || value === null)
159
199
  return null;
@@ -163,8 +203,15 @@ function parseChange(value, mode) {
163
203
  if (held.removed === true)
164
204
  return { path: held.path, removed: true };
165
205
  const head = headChange(held);
166
- if (head === null)
206
+ const binary = binaryFileOf(held);
207
+ if (head === null || binary === null)
167
208
  return null;
209
+ if (binary !== undefined) {
210
+ if (mode === 'credential' && typeof held.revision !== 'string')
211
+ return null;
212
+ const revision = typeof held.revision === 'string' ? held.revision : binary.sha256;
213
+ return { path: held.path, binary, revision, version: revision, ...headed(head) };
214
+ }
168
215
  if (mode === 'site') {
169
216
  if (typeof held.content !== 'string' || typeof held.sha256 !== 'string')
170
217
  return null;
@@ -185,12 +232,6 @@ function parseChange(value, mode) {
185
232
  ...headed(head),
186
233
  };
187
234
  }
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
235
  return null;
195
236
  }
196
237
  export function parseEnumeration(body, mode) {
@@ -215,17 +256,60 @@ export function parseEnumeration(body, mode) {
215
256
  return null;
216
257
  changes.push(mapped);
217
258
  }
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)
259
+ const next = held.next === undefined ? undefined : readPage(held.next);
260
+ if (next === null)
224
261
  return null;
225
- authorities.push({ authority: held.authority, ...at, changes, attachments });
262
+ authorities.push({
263
+ authority: held.authority,
264
+ ...at,
265
+ changes,
266
+ ...(next === undefined ? {} : { next }),
267
+ });
226
268
  }
227
269
  return { authorities };
228
270
  }
271
+ function readPage(held) {
272
+ if (typeof held !== 'object' || held === null)
273
+ return null;
274
+ const { after, through, read } = held;
275
+ if (typeof after !== 'string' || !DECIMAL.test(after))
276
+ return null;
277
+ if (typeof through !== 'string' || !DECIMAL.test(through))
278
+ return null;
279
+ if (typeof read !== 'number' || !Number.isSafeInteger(read) || read < 0)
280
+ return null;
281
+ return { after, through, read };
282
+ }
283
+ function advances(asked, next) {
284
+ const moved = BigInt(next.through) - BigInt(asked.through);
285
+ return moved > 0n || (moved === 0n && next.after === asked.after && next.read > asked.read);
286
+ }
287
+ export async function wholeView(first, more) {
288
+ const changes = new Map(first.changes.map((change) => [change.path, change]));
289
+ let view = first;
290
+ while (view.next !== undefined) {
291
+ const asked = view.next;
292
+ const page = await more(asked);
293
+ if ('kind' in page)
294
+ return page;
295
+ if (page.position !== asked.through ||
296
+ page.logEpoch !== first.logEpoch ||
297
+ (page.next !== undefined && !advances(asked, page.next))) {
298
+ return { kind: 'transport-uncertainty' };
299
+ }
300
+ for (const change of page.changes) {
301
+ changes.delete(change.path);
302
+ changes.set(change.path, change);
303
+ }
304
+ view = page;
305
+ }
306
+ return {
307
+ authority: first.authority,
308
+ position: view.position,
309
+ logEpoch: first.logEpoch,
310
+ changes: [...changes.values()],
311
+ };
312
+ }
229
313
  export function advancedScope(scope, view) {
230
314
  const files = new Map(scope.files.map((file) => [file.path, file]));
231
315
  const contents = new Map(scope.contents.map((entry) => [entry.path, entry.content]));
@@ -234,18 +318,15 @@ export function advancedScope(scope, view) {
234
318
  contents.delete(change.path);
235
319
  if ('removed' in change)
236
320
  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
- });
321
+ files.set(change.path, {
322
+ path: change.path,
323
+ revision: change.revision,
324
+ version: change.version,
325
+ ...headed(change.head),
326
+ ...('binary' in change ? { binary: change.binary } : {}),
327
+ });
328
+ if ('content' in change)
244
329
  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 });
249
330
  }
250
331
  return {
251
332
  ...scope,
@@ -263,16 +344,16 @@ export function bootstrapOf(scope) {
263
344
  const documents = {};
264
345
  const revisions = {};
265
346
  const changes = {};
266
- const binaryTargets = [];
347
+ const binaryFiles = {};
267
348
  for (const file of scope.files) {
268
349
  if (file.revision !== undefined)
269
350
  revisions[file.path] = file.revision;
270
351
  if (file.head !== undefined)
271
352
  changes[file.path] = file.head;
272
353
  const content = contents.get(file.path);
273
- if (content === undefined)
274
- binaryTargets.push(file.path);
275
- else
354
+ if (file.binary !== undefined)
355
+ binaryFiles[file.path] = file.binary;
356
+ else if (content !== undefined)
276
357
  documents[file.path] = content;
277
358
  }
278
359
  return {
@@ -280,17 +361,19 @@ export function bootstrapOf(scope) {
280
361
  roomVersion: roomVersion(scope),
281
362
  documents,
282
363
  revisions,
364
+ ...identities(revisions),
283
365
  changes,
284
- binaryTargets: binaryTargets.sort(),
285
- ...declared(scope.attachments),
366
+ binaryFiles,
286
367
  };
287
368
  }
288
369
  export function schemaOf(scope, schema) {
289
370
  const file = scope.files.find((entry) => entry.path === schema);
290
371
  if (file === undefined)
291
- return { schema: null, version: null };
372
+ return { schema: null, version: null, revision: null };
292
373
  const content = scope.contents.find((entry) => entry.path === schema);
293
- return content === undefined ? null : { schema: content.content, version: file.version };
374
+ return content === undefined
375
+ ? null
376
+ : { schema: content.content, version: file.version, revision: file.revision ?? null };
294
377
  }
295
378
  export function viewOf(enumeration, tracked) {
296
379
  return enumeration.authorities.find((entry) => entry.authority === tracked.authority);
@@ -301,32 +384,30 @@ export function refreshFrom(view, fromRoomVersion) {
301
384
  const documents = {};
302
385
  const revisions = {};
303
386
  const changes = {};
304
- const binaryTargets = [];
387
+ const binaryFiles = {};
305
388
  const removals = [];
306
389
  for (const change of view.changes) {
307
390
  if ('removed' in change) {
308
391
  removals.push(change.path);
309
392
  continue;
310
393
  }
311
- if ('content' in change) {
394
+ if ('content' in change)
312
395
  documents[change.path] = change.content;
313
- if (change.revision !== undefined)
314
- revisions[change.path] = change.revision;
315
- if (change.head !== undefined)
316
- changes[change.path] = change.head;
317
- continue;
318
- }
319
- binaryTargets.push(change.path);
320
- revisions[change.path] = change.reference.revision;
396
+ else
397
+ binaryFiles[change.path] = change.binary;
398
+ if (change.revision !== undefined)
399
+ revisions[change.path] = change.revision;
400
+ if (change.head !== undefined)
401
+ changes[change.path] = change.head;
321
402
  }
322
403
  return {
323
404
  kind: 'net-advancement',
324
405
  roomVersion: roomVersion(view),
325
406
  documents,
326
407
  revisions,
408
+ ...identities(revisions),
327
409
  changes,
328
- binaryTargets: binaryTargets.sort(),
410
+ binaryFiles,
329
411
  removals: removals.sort(),
330
- ...declared(view.attachments),
331
412
  };
332
413
  }