@agentshouse/mdruntime-adapter 0.1.0-alpha.9 → 0.1.0-c506c7d6e6199

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 (61) hide show
  1. package/AGENTS.md +156 -27
  2. package/README.md +32 -0
  3. package/dist/actions.d.ts +4 -12
  4. package/dist/actions.d.ts.map +1 -1
  5. package/dist/actions.js +239 -332
  6. package/dist/adapter.d.ts.map +1 -1
  7. package/dist/adapter.js +271 -197
  8. package/dist/digest.js +1 -5
  9. package/dist/discovery.d.ts +22 -26
  10. package/dist/discovery.d.ts.map +1 -1
  11. package/dist/discovery.js +154 -223
  12. package/dist/gather.d.ts +3 -0
  13. package/dist/gather.d.ts.map +1 -0
  14. package/dist/gather.js +40 -0
  15. package/dist/index.d.ts +1 -2
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +0 -3
  18. package/dist/links.d.ts +12 -0
  19. package/dist/links.d.ts.map +1 -0
  20. package/dist/links.js +66 -0
  21. package/dist/map.d.ts +2 -2
  22. package/dist/map.d.ts.map +1 -1
  23. package/dist/map.js +6 -7
  24. package/dist/model.d.ts +2 -2
  25. package/dist/model.d.ts.map +1 -1
  26. package/dist/model.js +21 -39
  27. package/dist/read.d.ts +31 -26
  28. package/dist/read.d.ts.map +1 -1
  29. package/dist/read.js +208 -199
  30. package/dist/refusal.d.ts +3 -1
  31. package/dist/refusal.d.ts.map +1 -1
  32. package/dist/refusal.js +27 -62
  33. package/dist/site.d.ts.map +1 -1
  34. package/dist/site.js +110 -124
  35. package/dist/stream.d.ts +11 -5
  36. package/dist/stream.d.ts.map +1 -1
  37. package/dist/stream.js +209 -213
  38. package/dist/transport.d.ts +45 -28
  39. package/dist/transport.d.ts.map +1 -1
  40. package/dist/transport.js +2 -3
  41. package/dist/version.d.ts +1 -0
  42. package/dist/version.d.ts.map +1 -1
  43. package/dist/version.js +23 -18
  44. package/dist/write.d.ts +5 -7
  45. package/dist/write.d.ts.map +1 -1
  46. package/dist/write.js +127 -215
  47. package/package.json +4 -12
  48. package/dist/actions.js.map +0 -1
  49. package/dist/adapter.js.map +0 -1
  50. package/dist/digest.js.map +0 -1
  51. package/dist/discovery.js.map +0 -1
  52. package/dist/index.js.map +0 -1
  53. package/dist/map.js.map +0 -1
  54. package/dist/model.js.map +0 -1
  55. package/dist/read.js.map +0 -1
  56. package/dist/refusal.js.map +0 -1
  57. package/dist/site.js.map +0 -1
  58. package/dist/stream.js.map +0 -1
  59. package/dist/transport.js.map +0 -1
  60. package/dist/version.js.map +0 -1
  61. package/dist/write.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,OAAO,EACP,aAAa,EAad,MAAM,wBAAwB,CAAC;AAqChC,OAAO,EAQL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AAiBxB,MAAM,MAAM,yBAAyB,GACjC;IACE,SAAS,EAAE,cAAc,CAAC;IAC1B,SAAS,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;CACrC,GACD;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAAC;AA2BjC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAuQpF"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,OAAO,EACP,aAAa,EAad,MAAM,wBAAwB,CAAC;AAyChC,OAAO,EAQL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AAuBxB,MAAM,MAAM,yBAAyB,GACjC;IACE,SAAS,EAAE,cAAc,CAAC;IAC1B,SAAS,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;CACrC,GACD;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAiCjC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CA2ZpF"}
package/dist/adapter.js CHANGED
@@ -1,61 +1,96 @@
1
- import { DISCOVER_PREFIXES, PROVIDER_SELECTION_MODEL_ROOT, capabilities, discoveredRoom, locatorOf, mapDiscovery, parseDiscovery, providerSelection, trackedFrom } from './discovery.js';
2
- import { MODEL_ABSENT, failedModel, heldModel, modelKey, modelShelf } from './model.js';
1
+ import { DISCOVER_PREFIXES, capabilities, discoveredRoom, locatorOf, mapDiscovery, parseDiscovery, trackedFrom, } from './discovery.js';
2
+ import { MODEL_ABSENT, failedModel, heldModel, modelKey, modelShelf, } from './model.js';
3
+ import { gathered, selections } from './gather.js';
3
4
  import { createSiteAdapter } from './site.js';
4
- import { authorityRoot, bootstrapFrom, contentPrefixes, definitionsFrom, modelPrefix, parseEnumeration, parseEnvelope, parseGrant, refreshFrom } from './read.js';
5
+ import { bootstrapOf, contentPrefixes, matchesScope, parseEnumeration, parseEnvelope, parseGrant, refreshFrom, schemaFrom, schemaPath, viewOf, } from './read.js';
6
+ import { enumeratedLinks, scopeLinks, streamedLinks } from './links.js';
5
7
  import { houseAction } from './actions.js';
6
- import { classifyDoor, discoveryFailure } from './refusal.js';
8
+ import { classifyDoor, discoveryFailure, doorRefusal } from './refusal.js';
7
9
  import { houseNotifications } from './stream.js';
8
- import { DOOR_BATCH, DOOR_BATCH_UPLOAD, DOOR_BOOTSTRAP, DOOR_DISCOVER, DOOR_ENUMERATE, DOOR_REVISIONS, PRIVATE_AUTHORITY } from './transport.js';
9
- import { batchPaths, deltaBody, deltaBytes, deltaDigest, historyOutcome, houseChanges, mutationOutcome, operationHead, rejectedMapping, revisionBody, uploadable } from './write.js';
10
- import { logPosition, presented } from './version.js';
11
- const UNCERTAIN = {
12
- kind: 'transport-uncertainty'
13
- };
14
- const RESOLVED_OUTCOMES = new Set([
15
- 'accepted',
16
- 'conflicted',
17
- 'rejected',
18
- 'expired'
19
- ]);
10
+ import { DOOR_BATCH, DOOR_BATCH_UPLOAD, DOOR_BOOTSTRAP, DOOR_DISCOVER, DOOR_ENUMERATE, DOOR_REVISIONS, PRIVATE_LOCATOR, } from './transport.js';
11
+ import { batchPaths, deltaBody, deltaBytes, deltaDigest, historyOutcome, houseChanges, mutationOutcome, operationHead, rejectedMapping, revisionBody, uploadable, } from './write.js';
12
+ import { logPosition, presented, reachedVersion, roomVersion, } from './version.js';
13
+ const UNCERTAIN = { kind: 'transport-uncertainty' };
14
+ const UNCERTAIN_READ = { kind: 'transport-uncertainty' };
20
15
  function lapsedGrant(outcome) {
21
16
  return outcome.kind === 'rejected' && outcome.code === 'upload_unavailable';
22
17
  }
23
18
  function modelFailure(classified, envelope) {
24
19
  if (classified === null) {
25
- return envelope === null ? {
26
- kind: 'transport-uncertainty'
27
- } : MODEL_ABSENT;
20
+ return envelope === null ? { kind: 'transport-uncertainty' } : MODEL_ABSENT;
28
21
  }
29
22
  return failedModel(classified);
30
23
  }
31
24
  export function createAgentsHouseAdapter(options) {
32
- if ('site' in options) return createSiteAdapter(options.site);
25
+ if ('site' in options)
26
+ return createSiteAdapter(options.site);
33
27
  const transport = options.transport;
34
28
  const notifications = houseNotifications(transport, 'credential');
35
29
  const tracked = new Map();
30
+ const handed = new Map();
36
31
  const models = modelShelf();
37
- const submissions = new Map();
38
- function held(envelope, entry, modelRoot, identity, failure) {
39
- return heldModel(envelope === null ? null : definitionsFrom(envelope, entry, modelRoot), identity, failure);
32
+ let bounds;
33
+ function declared() {
34
+ if (bounds === undefined)
35
+ throw new Error('no Discovery declared the bounds');
36
+ return bounds;
37
+ }
38
+ function bootstrappedRoom(envelope, entry) {
39
+ const scope = envelope.scopes.find((candidate) => matchesScope(candidate, entry));
40
+ if (scope === undefined)
41
+ return { kind: 'room-not-readable', locator: entry.locator };
42
+ handed.set(entry.locator, scopeLinks(scope));
43
+ notifications.hold(entry.authority, scope);
44
+ return bootstrapOf(scope);
45
+ }
46
+ function enumeratedRoom(enumeration, ask) {
47
+ const view = viewOf(enumeration, ask.entry);
48
+ if (view === undefined)
49
+ return { kind: 'room-not-readable', locator: ask.entry.locator };
50
+ notifications.hold(ask.entry.authority, view);
51
+ const answer = refreshFrom(view, ask.fromRoomVersion);
52
+ if (answer.kind === 'net-advancement') {
53
+ handed.set(ask.entry.locator, enumeratedLinks(view, handed.get(ask.entry.locator)));
54
+ }
55
+ return answer;
56
+ }
57
+ function streamed(entry, request, from) {
58
+ const links = handed.get(entry.locator);
59
+ if (links?.roomVersion !== request.fromRoomVersion)
60
+ return null;
61
+ const advanced = notifications.advance(entry, from, (path, revision) => links.revisions.get(path) === revision);
62
+ if (advanced === null)
63
+ return null;
64
+ if (request.minPosition !== undefined &&
65
+ !reachedVersion(advanced.page.roomVersion, request.minPosition, entry.logEpoch))
66
+ return null;
67
+ const relinked = streamedLinks(links, advanced);
68
+ if (relinked === null)
69
+ return null;
70
+ handed.set(entry.locator, relinked);
71
+ return advanced.page;
72
+ }
73
+ function held(envelope, entry, schema, failure) {
74
+ return heldModel(envelope === null ? null : schemaFrom(envelope, entry, schema), schemaPath(entry.handle, schema), failure);
75
+ }
76
+ function modelPrefixes(entry) {
77
+ return entry.schemas.map((schema) => schemaPath(entry.handle, schema));
40
78
  }
41
79
  async function acquireModels(entries) {
42
80
  const acquired = new Map();
43
- const privateEntry = entries.find((entry)=>entry.authority === PRIVATE_AUTHORITY);
44
- const prefixes = entries.map((entry)=>modelPrefix(entry, entry.modelRoot));
45
- if (privateEntry !== undefined) {
46
- prefixes.push(`${authorityRoot(undefined)}/${PROVIDER_SELECTION_MODEL_ROOT}`);
47
- }
48
- const answer = await transport.door(DOOR_BOOTSTRAP, {
49
- prefixes
50
- });
51
- const classified = classifyDoor(answer.status, answer.body, PRIVATE_AUTHORITY);
52
- const envelope = classified === null ? parseEnvelope(await bundled(answer.body)) : null;
53
- const failure = modelFailure(classified, envelope);
54
- for (const entry of entries){
55
- acquired.set(modelKey(entry.locator, 'collection'), await held(envelope, entry, entry.modelRoot, `${authorityRoot(entry.handle)}/${entry.modelRoot}`, failure));
56
- }
57
- if (privateEntry !== undefined) {
58
- acquired.set(modelKey(privateEntry.locator, 'typed-selection'), await held(envelope, privateEntry, PROVIDER_SELECTION_MODEL_ROOT, `${authorityRoot(undefined)}/${PROVIDER_SELECTION_MODEL_ROOT}`, failure));
81
+ for (const part of selections(entries, (entry) => modelPrefixes(entry).length, declared().max_prefixes)) {
82
+ const answer = await transport.door(DOOR_BOOTSTRAP, {
83
+ prefixes: part.flatMap((entry) => modelPrefixes(entry)),
84
+ });
85
+ const classified = classifyDoor(answer.status, answer.body, PRIVATE_LOCATOR);
86
+ const envelope = classified === null ? parseEnvelope(await bundled(answer.body)) : null;
87
+ const failure = modelFailure(classified, envelope);
88
+ for (const entry of part) {
89
+ acquired.set(modelKey(entry.locator, 'collection'), await held(envelope, entry, entry.schema, failure));
90
+ if (entry.houseModel === null)
91
+ continue;
92
+ acquired.set(modelKey(entry.locator, 'typed-selection'), await held(envelope, entry, entry.houseModel.root, failure));
93
+ }
59
94
  }
60
95
  return acquired;
61
96
  }
@@ -63,223 +98,262 @@ export function createAgentsHouseAdapter(options) {
63
98
  const locator = locatorOf(authority);
64
99
  const key = modelKey(locator, 'collection');
65
100
  const collection = models.retain(key, acquired.get(key));
66
- if (authority.kind !== 'private') {
67
- return discoveredRoom(authority, collection?.identity ?? null, undefined);
68
- }
69
- const selection = models.retain(modelKey(locator, 'typed-selection'), acquired.get(modelKey(locator, 'typed-selection')));
70
- return discoveredRoom(authority, collection?.identity ?? null, providerSelection(selection?.identity ?? null));
101
+ const selection = authority.houseModel === null
102
+ ? undefined
103
+ : models.retain(modelKey(locator, 'typed-selection'), acquired.get(modelKey(locator, 'typed-selection')));
104
+ return discoveredRoom(authority, collection?.identity ?? null, selection?.identity ?? null);
71
105
  }
72
106
  function authorityFor(locator) {
73
107
  return tracked.get(locator);
74
108
  }
109
+ function withAt(result) {
110
+ if (result.kind !== 'action')
111
+ return result;
112
+ const body = result.result;
113
+ if (typeof body !== 'object' || body === null)
114
+ return result;
115
+ const { authority, position, log_epoch: logEpoch } = body;
116
+ if (typeof position !== 'string' || typeof logEpoch !== 'string')
117
+ return result;
118
+ const locator = authority === undefined
119
+ ? PRIVATE_LOCATOR
120
+ : [...tracked.values()].find((entry) => entry.authority === authority)?.locator;
121
+ if (locator === undefined)
122
+ return result;
123
+ return { ...result, at: { locator, roomVersion: roomVersion({ position, logEpoch }) } };
124
+ }
75
125
  async function bundled(body) {
76
126
  const grant = parseGrant(body);
77
- if (grant === null) return body;
78
- if (grant.method !== 'GET') return null;
127
+ if (grant === null)
128
+ return body;
129
+ if (grant.method !== 'GET')
130
+ return null;
79
131
  const answer = await transport.transfer({
80
- act: 'working_copy_bundle',
132
+ act: 'local_copy_bundle',
81
133
  method: 'GET',
82
- url: grant.url
134
+ url: grant.url,
135
+ answer: 'json',
83
136
  });
84
137
  return answer.status === 200 ? answer.body : null;
85
138
  }
86
- async function uploaded(head, changes, delta, bytes, entry) {
139
+ function weight(entry) {
140
+ return contentPrefixes(entry).length;
141
+ }
142
+ async function bootstrapped(entries) {
143
+ const answers = [];
144
+ for (const part of selections(entries, weight, declared().max_prefixes)) {
145
+ const answer = await transport.door(DOOR_BOOTSTRAP, {
146
+ prefixes: part.flatMap((entry) => contentPrefixes(entry)),
147
+ });
148
+ const classified = part.map((entry) => classifyDoor(answer.status, answer.body, entry.locator));
149
+ const envelope = classified[0] === null ? parseEnvelope(await bundled(answer.body)) : null;
150
+ part.forEach((entry, index) => {
151
+ const failure = classified[index];
152
+ if (failure === null || failure === undefined) {
153
+ answers.push(envelope === null ? UNCERTAIN_READ : bootstrappedRoom(envelope, entry));
154
+ return;
155
+ }
156
+ answers.push(failure.kind === 'beyond-horizon' ? UNCERTAIN_READ : failure);
157
+ });
158
+ }
159
+ return answers;
160
+ }
161
+ function layered(asks) {
162
+ const depths = new Map();
163
+ const layers = [];
164
+ for (const ask of asks) {
165
+ const depth = depths.get(ask.entry.authority) ?? 0;
166
+ depths.set(ask.entry.authority, depth + 1);
167
+ (layers[depth] ??= []).push(ask);
168
+ }
169
+ return layers;
170
+ }
171
+ async function enumerated(asks) {
172
+ const answers = new Map();
173
+ const parts = layered(asks).flatMap((layer) => selections(layer, (ask) => weight(ask.entry), declared().max_prefixes));
174
+ for (const part of parts) {
175
+ let open = [...part];
176
+ while (open.length > 0) {
177
+ const answer = await transport.door(DOOR_ENUMERATE, {
178
+ prefixes: open.flatMap((ask) => contentPrefixes(ask.entry)),
179
+ positions: open.map((ask) => ({
180
+ ...presented(ask.entry.authority, ask.from),
181
+ ...(ask.minPosition === undefined ? {} : { min_position: ask.minPosition }),
182
+ })),
183
+ });
184
+ const refusal = doorRefusal(answer.body);
185
+ if (refusal?.code === 'replica_behind') {
186
+ const named = open.filter((ask) => ask.entry.authority === refusal.fields.authority);
187
+ const behind = named.length === 0 ? open : named;
188
+ for (const ask of behind) {
189
+ answers.set(ask, refusal.retryable
190
+ ? { kind: 'retryable-refusal', code: refusal.code, fields: refusal.fields }
191
+ : (classifyDoor(answer.status, answer.body, ask.entry.locator) ?? UNCERTAIN_READ));
192
+ }
193
+ open = open.filter((ask) => !behind.includes(ask));
194
+ continue;
195
+ }
196
+ const classified = open.map((ask) => classifyDoor(answer.status, answer.body, ask.entry.locator));
197
+ if (classified[0]?.kind === 'beyond-horizon') {
198
+ const named = doorRefusal(answer.body)?.fields.authority;
199
+ const expired = open.filter((ask) => ask.entry.authority === named);
200
+ const answered = expired.length === 0 ? UNCERTAIN_READ : { kind: 'beyond-horizon' };
201
+ const gone = expired.length === 0 ? open : expired;
202
+ for (const ask of gone)
203
+ answers.set(ask, answered);
204
+ open = open.filter((ask) => !gone.includes(ask));
205
+ continue;
206
+ }
207
+ const enumeration = classified[0] === null ? parseEnumeration(answer.body, 'credential') : null;
208
+ open.forEach((ask, index) => {
209
+ const failure = classified[index];
210
+ if (failure !== null && failure !== undefined) {
211
+ answers.set(ask, failure);
212
+ return;
213
+ }
214
+ answers.set(ask, enumeration === null ? UNCERTAIN_READ : enumeratedRoom(enumeration, ask));
215
+ });
216
+ open = [];
217
+ }
218
+ }
219
+ return asks.map((ask) => answers.get(ask) ?? UNCERTAIN_READ);
220
+ }
221
+ const bootstrapTogether = gathered(bootstrapped);
222
+ const enumerateTogether = gathered(enumerated);
223
+ async function uploaded(head, changes, delta, bytes, entry, handed, keep) {
87
224
  const paths = batchPaths(changes);
88
225
  const sha256 = await deltaDigest(delta);
89
- const retained = submissions.get(head.operation_id);
90
- if (retained !== undefined && retained.sha256 === sha256 && retained.body.app_ref === head.app_ref && retained.body.release === head.release) return {
91
- body: retained.body
92
- };
93
- const minted = await transport.door(DOOR_BATCH_UPLOAD, {
94
- ...head,
95
- paths,
96
- bytes,
97
- sha256
98
- });
226
+ if (handed !== undefined && handed.sha256 === sha256) {
227
+ return { body: { ...head, paths, upload: handed } };
228
+ }
229
+ const minted = await transport.door(DOOR_BATCH_UPLOAD, { ...head, paths, bytes, sha256 });
99
230
  if (minted.status !== 200) {
100
- return {
101
- outcome: mutationOutcome(minted.status, minted.body, entry.locator, entry.handle)
102
- };
231
+ return { outcome: mutationOutcome(minted.status, minted.body, entry.locator, entry.handle) };
103
232
  }
104
233
  const grant = parseGrant(minted.body);
105
- if (grant === null || grant.method !== 'POST') return {
106
- outcome: UNCERTAIN
107
- };
234
+ if (grant === null || grant.method !== 'POST')
235
+ return { outcome: UNCERTAIN };
108
236
  const delivered = await transport.transfer({
109
237
  act: 'authored_batch_upload',
110
238
  method: 'POST',
111
239
  url: grant.url,
112
- body: `${grant.operation}\n${delta}`
240
+ answer: 'json',
241
+ body: `${grant.operation}\n${delta}`,
113
242
  });
114
- if (delivered.status !== 200) return {
115
- outcome: UNCERTAIN
116
- };
243
+ if (delivered.status !== 200)
244
+ return { outcome: UNCERTAIN };
117
245
  const holding = parseGrant(delivered.body);
118
- if (holding === null) return {
119
- outcome: UNCERTAIN
120
- };
121
- const body = {
122
- ...head,
123
- paths,
124
- upload: {
125
- url: holding.url,
126
- operation: holding.operation,
127
- bytes,
128
- sha256
129
- }
130
- };
131
- submissions.set(head.operation_id, {
132
- sha256,
133
- body
134
- });
135
- return {
136
- body
137
- };
246
+ if (holding === null || holding.method !== 'POST')
247
+ return { outcome: UNCERTAIN };
248
+ const upload = { url: holding.url, operation: holding.operation, bytes, sha256 };
249
+ await keep(upload);
250
+ return { body: { ...head, paths, upload } };
138
251
  }
139
- async function submit(head, changes, delta, bytes, entry) {
140
- const prepared = uploadable(bytes) ? await uploaded(head, changes, delta, bytes, entry) : {
141
- body: {
142
- ...head,
143
- changes
144
- }
145
- };
146
- if ('outcome' in prepared) return prepared.outcome;
252
+ async function submit(head, changes, delta, bytes, entry, handed, keep) {
253
+ const inline = { ...head, changes };
254
+ const prepared = uploadable(inline, bytes, declared())
255
+ ? await uploaded(head, changes, delta, bytes, entry, handed, keep)
256
+ : { body: inline };
257
+ if ('outcome' in prepared)
258
+ return prepared.outcome;
147
259
  const answer = await transport.door(DOOR_BATCH, prepared.body);
148
260
  return mutationOutcome(answer.status, answer.body, entry.locator, entry.handle);
149
261
  }
150
262
  return {
151
- async authorize () {
263
+ async authorize() {
152
264
  return options.authorize();
153
265
  },
154
- async model (_authorization, request) {
266
+ async model(_authorization, request) {
155
267
  return models.answer(request);
156
268
  },
157
- async discover (_authorization) {
158
- const answer = await transport.door(DOOR_DISCOVER, {
159
- prefixes: [
160
- ...DISCOVER_PREFIXES
161
- ]
162
- });
163
- const classified = classifyDoor(answer.status, answer.body, PRIVATE_AUTHORITY);
164
- if (classified !== null) return discoveryFailure(classified);
269
+ async discover(_authorization) {
270
+ const answer = await transport.door(DOOR_DISCOVER, { prefixes: [...DISCOVER_PREFIXES] });
271
+ const classified = classifyDoor(answer.status, answer.body, PRIVATE_LOCATOR);
272
+ if (classified !== null)
273
+ return discoveryFailure(classified);
165
274
  const document = parseDiscovery(answer.body);
166
- if (document === null) return {
167
- kind: 'transport-uncertainty'
168
- };
275
+ if (document === null)
276
+ return { kind: 'transport-uncertainty' };
277
+ bounds = document.bounds;
169
278
  const entries = trackedFrom(document);
170
279
  tracked.clear();
171
- for (const entry of entries)tracked.set(entry.locator, entry);
280
+ for (const entry of entries)
281
+ tracked.set(entry.locator, entry);
282
+ for (const locator of handed.keys())
283
+ if (!tracked.has(locator))
284
+ handed.delete(locator);
172
285
  notifications.track(entries);
173
286
  const acquired = await acquireModels(entries);
174
- models.keep(entries.map((entry)=>entry.locator));
175
- return mapDiscovery(document, document.authorities.map((authority)=>roomOf(authority, acquired)), capabilities());
287
+ models.keep(entries.map((entry) => entry.locator));
288
+ return mapDiscovery(document, document.authorities.map((authority) => roomOf(authority, acquired)), capabilities(document.actions));
176
289
  },
177
- async bootstrap (_authorization, request) {
290
+ async bootstrap(_authorization, request) {
178
291
  const entry = authorityFor(request.locator);
179
- if (entry === undefined) return {
180
- kind: 'room-not-readable',
181
- locator: request.locator
182
- };
183
- if (request.pageToken !== undefined) return {
184
- kind: 'transport-uncertainty'
185
- };
186
- const answer = await transport.door(DOOR_BOOTSTRAP, {
187
- prefixes: [
188
- ...contentPrefixes(entry)
189
- ]
190
- });
191
- const classified = classifyDoor(answer.status, answer.body, entry.locator);
192
- if (classified !== null) {
193
- return classified.kind === 'beyond-horizon' ? {
194
- kind: 'transport-uncertainty'
195
- } : classified;
196
- }
197
- const envelope = parseEnvelope(await bundled(answer.body));
198
- if (envelope === null) return {
199
- kind: 'transport-uncertainty'
200
- };
201
- return bootstrapFrom(envelope, entry);
292
+ if (entry === undefined)
293
+ return { kind: 'room-not-readable', locator: request.locator };
294
+ if (request.pageToken !== undefined)
295
+ return { kind: 'transport-uncertainty' };
296
+ return bootstrapTogether(entry);
202
297
  },
203
- async refresh (_authorization, request) {
298
+ async refresh(_authorization, request) {
204
299
  const entry = authorityFor(request.locator);
205
- if (entry === undefined) return {
206
- kind: 'room-not-readable',
207
- locator: request.locator
208
- };
209
- if (request.pageToken !== undefined) return {
210
- kind: 'transport-uncertainty'
211
- };
300
+ if (entry === undefined)
301
+ return { kind: 'room-not-readable', locator: request.locator };
302
+ if (request.pageToken !== undefined)
303
+ return { kind: 'transport-uncertainty' };
212
304
  const from = logPosition(request.fromRoomVersion);
213
- if (from === null) return {
214
- kind: 'beyond-horizon'
215
- };
216
- const streamed = notifications.advance(entry, from);
217
- if (streamed !== null) return streamed;
218
- const answer = await transport.door(DOOR_ENUMERATE, {
219
- prefixes: [
220
- ...contentPrefixes(entry)
221
- ],
222
- positions: [
223
- presented(entry.authority, from)
224
- ]
305
+ if (from === null)
306
+ return { kind: 'beyond-horizon' };
307
+ const answered = streamed(entry, request, from);
308
+ if (answered !== null)
309
+ return answered;
310
+ const minPosition = request.minPosition === undefined ? null : logPosition(request.minPosition);
311
+ return enumerateTogether({
312
+ entry,
313
+ from,
314
+ fromRoomVersion: request.fromRoomVersion,
315
+ ...(minPosition?.logEpoch === from.logEpoch ? { minPosition: minPosition.position } : {}),
225
316
  });
226
- const classified = classifyDoor(answer.status, answer.body, entry.locator);
227
- if (classified !== null) return classified;
228
- const enumeration = parseEnumeration(answer.body, 'credential');
229
- if (enumeration === null) return {
230
- kind: 'transport-uncertainty'
231
- };
232
- return refreshFrom(enumeration, entry, request.fromRoomVersion);
233
317
  },
234
- async mutate (_authorization, request) {
318
+ async mutate(_authorization, request, keep) {
235
319
  const entry = authorityFor(request.locator);
236
- if (entry === undefined) return {
237
- kind: 'room-not-readable',
238
- locator: request.locator
239
- };
320
+ if (entry === undefined)
321
+ return { kind: 'room-not-readable', locator: request.locator };
240
322
  const mapped = houseChanges(request.changeBatch, entry.handle);
241
- if (mapped.kind === 'unmapped') return rejectedMapping(mapped);
323
+ if (mapped.kind === 'unmapped')
324
+ return rejectedMapping(mapped);
242
325
  const head = operationHead(request.changeBatch);
243
326
  const delta = deltaBody(mapped.changes);
244
327
  const bytes = deltaBytes(delta);
245
- const resent = submissions.has(head.operation_id);
246
- let outcome = await submit(head, mapped.changes, delta, bytes, entry);
247
- if (resent && lapsedGrant(outcome)) {
248
- submissions.delete(head.operation_id);
249
- outcome = await submit(head, mapped.changes, delta, bytes, entry);
250
- }
251
- if (RESOLVED_OUTCOMES.has(outcome.kind)) submissions.delete(head.operation_id);
252
- return outcome;
328
+ const handed = request.upload;
329
+ const outcome = await submit(head, mapped.changes, delta, bytes, entry, handed, keep);
330
+ if (handed === undefined || !lapsedGrant(outcome))
331
+ return outcome;
332
+ return submit(head, mapped.changes, delta, bytes, entry, undefined, keep);
253
333
  },
254
- async history (_authorization, request) {
334
+ async history(_authorization, request) {
255
335
  const entry = authorityFor(request.locator);
256
- if (entry === undefined) return {
257
- kind: 'room-not-readable',
258
- locator: request.locator
259
- };
336
+ if (entry === undefined)
337
+ return { kind: 'room-not-readable', locator: request.locator };
260
338
  const answer = await transport.door(DOOR_REVISIONS, revisionBody({
261
339
  path: request.path,
262
340
  handle: entry.handle,
263
- ...request.revision === undefined ? {} : {
264
- revision: request.revision
265
- },
266
- ...request.pageToken === undefined ? {} : {
267
- pageToken: request.pageToken
268
- }
341
+ ...(request.revision === undefined ? {} : { revision: request.revision }),
342
+ ...(request.pageToken === undefined ? {} : { pageToken: request.pageToken }),
269
343
  }));
270
344
  return historyOutcome(answer.status, answer.body, entry.locator, {
271
345
  path: request.path,
272
- ...request.revision === undefined ? {} : {
273
- revision: request.revision
274
- }
346
+ ...(request.revision === undefined ? {} : { revision: request.revision }),
275
347
  });
276
348
  },
277
- async action (_authorization, request) {
278
- return houseAction(transport, request);
349
+ reached(locator, version, target) {
350
+ return reachedVersion(version, target, authorityFor(locator)?.logEpoch);
351
+ },
352
+ async action(_authorization, request) {
353
+ return withAt(await houseAction(transport, request));
279
354
  },
280
355
  roomVersions: notifications,
281
- conversations: notifications.conversations
356
+ conversations: notifications.conversations,
357
+ serviceMode: notifications.serviceMode,
282
358
  };
283
359
  }
284
-
285
- //# sourceMappingURL=adapter.js.map
package/dist/digest.js CHANGED
@@ -3,9 +3,5 @@ export function textBytes(value) {
3
3
  }
4
4
  export async function sha256Hex(value) {
5
5
  const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(value));
6
- return [
7
- ...new Uint8Array(digest)
8
- ].map((byte)=>byte.toString(16).padStart(2, '0')).join('');
6
+ return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, '0')).join('');
9
7
  }
10
-
11
- //# sourceMappingURL=digest.js.map