@agentshouse/mdruntime 0.1.0-cee9c8aa4cd86 → 0.1.0-cefbc8bb8a1c0

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 (190) hide show
  1. package/README.md +10 -8
  2. package/dist/adapter.d.ts +31 -18
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/attached-model.d.ts +2 -1
  5. package/dist/attached-model.d.ts.map +1 -1
  6. package/dist/attached-model.js +28 -4
  7. package/dist/binary.d.ts +0 -5
  8. package/dist/binary.d.ts.map +1 -1
  9. package/dist/binary.js +1 -1
  10. package/dist/bootstrap.d.ts +15 -4
  11. package/dist/bootstrap.d.ts.map +1 -1
  12. package/dist/bootstrap.js +140 -90
  13. package/dist/client.d.ts +6 -7
  14. package/dist/client.d.ts.map +1 -1
  15. package/dist/client.js +54 -7
  16. package/dist/collection.d.ts +5 -0
  17. package/dist/collection.d.ts.map +1 -1
  18. package/dist/collection.js +23 -2
  19. package/dist/compile.d.ts.map +1 -1
  20. package/dist/compile.js +85 -30
  21. package/dist/connection.d.ts +9 -7
  22. package/dist/connection.d.ts.map +1 -1
  23. package/dist/connection.js +961 -476
  24. package/dist/conversation.d.ts +7 -5
  25. package/dist/conversation.d.ts.map +1 -1
  26. package/dist/conversation.js +166 -41
  27. package/dist/durability.d.ts +2 -5
  28. package/dist/durability.d.ts.map +1 -1
  29. package/dist/durability.js +5 -0
  30. package/dist/entry.d.ts +1 -0
  31. package/dist/entry.d.ts.map +1 -1
  32. package/dist/entry.js +1 -1
  33. package/dist/file.d.ts +2 -11
  34. package/dist/file.d.ts.map +1 -1
  35. package/dist/file.js +6 -4
  36. package/dist/fulltext.d.ts.map +1 -1
  37. package/dist/fulltext.js +8 -6
  38. package/dist/host.d.ts +4 -3
  39. package/dist/host.d.ts.map +1 -1
  40. package/dist/host.js +43 -15
  41. package/dist/index.d.ts +9 -9
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +4 -3
  44. package/dist/live.d.ts.map +1 -1
  45. package/dist/live.js +2 -1
  46. package/dist/media.d.ts +8 -0
  47. package/dist/media.d.ts.map +1 -0
  48. package/dist/media.js +218 -0
  49. package/dist/memory.d.ts +2 -2
  50. package/dist/memory.d.ts.map +1 -1
  51. package/dist/memory.js +46 -19
  52. package/dist/model.d.ts +6 -0
  53. package/dist/model.d.ts.map +1 -1
  54. package/dist/model.js +7 -1
  55. package/dist/observation.d.ts +1 -0
  56. package/dist/observation.d.ts.map +1 -1
  57. package/dist/observation.js +1 -1
  58. package/dist/outcome.d.ts +13 -3
  59. package/dist/outcome.d.ts.map +1 -1
  60. package/dist/outcome.js +16 -5
  61. package/dist/overlay.js +1 -1
  62. package/dist/paths.d.ts +1 -0
  63. package/dist/paths.d.ts.map +1 -1
  64. package/dist/paths.js +4 -0
  65. package/dist/query.d.ts +9 -0
  66. package/dist/query.d.ts.map +1 -1
  67. package/dist/query.js +12 -1
  68. package/dist/reach.d.ts +8 -3
  69. package/dist/reach.d.ts.map +1 -1
  70. package/dist/reach.js +68 -45
  71. package/dist/readiness.d.ts +17 -7
  72. package/dist/readiness.d.ts.map +1 -1
  73. package/dist/readiness.js +6 -6
  74. package/dist/reads.d.ts.map +1 -1
  75. package/dist/reads.js +10 -17
  76. package/dist/recovery.d.ts +1 -0
  77. package/dist/recovery.d.ts.map +1 -1
  78. package/dist/recovery.js +26 -0
  79. package/dist/refresh.d.ts +6 -2
  80. package/dist/refresh.d.ts.map +1 -1
  81. package/dist/refresh.js +61 -27
  82. package/dist/replica.d.ts +5 -4
  83. package/dist/replica.d.ts.map +1 -1
  84. package/dist/replica.js +4 -3
  85. package/dist/room-draft.d.ts +18 -2
  86. package/dist/room-draft.d.ts.map +1 -1
  87. package/dist/room-draft.js +73 -6
  88. package/dist/rows.d.ts +15 -6
  89. package/dist/rows.d.ts.map +1 -1
  90. package/dist/rows.js +102 -74
  91. package/dist/save.d.ts +2 -0
  92. package/dist/save.d.ts.map +1 -1
  93. package/dist/save.js +13 -7
  94. package/dist/status.d.ts +5 -0
  95. package/dist/status.d.ts.map +1 -1
  96. package/dist/status.js +3 -1
  97. package/dist/store.d.ts +18 -12
  98. package/dist/store.d.ts.map +1 -1
  99. package/dist/store.js +25 -20
  100. package/dist/stored.d.ts +10 -13
  101. package/dist/stored.d.ts.map +1 -1
  102. package/dist/stored.js +210 -174
  103. package/dist/tables.d.ts +26 -6
  104. package/dist/tables.d.ts.map +1 -1
  105. package/dist/tables.js +57 -6
  106. package/dist/wire.d.ts +5 -5
  107. package/dist/wire.d.ts.map +1 -1
  108. package/dist/wire.js +2 -2
  109. package/dist/words.d.ts.map +1 -1
  110. package/dist/words.js +8 -2
  111. package/package.json +11 -18
  112. package/AGENTS.md +0 -320
  113. package/dist/chat/acts.d.ts +0 -33
  114. package/dist/chat/acts.d.ts.map +0 -1
  115. package/dist/chat/acts.js +0 -36
  116. package/dist/chat/context.d.ts +0 -3
  117. package/dist/chat/context.d.ts.map +0 -1
  118. package/dist/chat/context.js +0 -10
  119. package/dist/chat/earlier.d.ts +0 -10
  120. package/dist/chat/earlier.d.ts.map +0 -1
  121. package/dist/chat/earlier.js +0 -54
  122. package/dist/chat/house.d.ts +0 -25
  123. package/dist/chat/house.d.ts.map +0 -1
  124. package/dist/chat/house.js +0 -38
  125. package/dist/chat/input.d.ts +0 -11
  126. package/dist/chat/input.d.ts.map +0 -1
  127. package/dist/chat/input.js +0 -92
  128. package/dist/chat/kit.d.ts +0 -61
  129. package/dist/chat/kit.d.ts.map +0 -1
  130. package/dist/chat/kit.js +0 -123
  131. package/dist/chat/lasting.d.ts +0 -6
  132. package/dist/chat/lasting.d.ts.map +0 -1
  133. package/dist/chat/lasting.js +0 -19
  134. package/dist/chat/list.d.ts +0 -28
  135. package/dist/chat/list.d.ts.map +0 -1
  136. package/dist/chat/list.js +0 -103
  137. package/dist/chat/markdown.d.ts +0 -21
  138. package/dist/chat/markdown.d.ts.map +0 -1
  139. package/dist/chat/markdown.js +0 -246
  140. package/dist/chat/message.d.ts +0 -7
  141. package/dist/chat/message.d.ts.map +0 -1
  142. package/dist/chat/message.js +0 -254
  143. package/dist/chat/messages.d.ts +0 -35
  144. package/dist/chat/messages.d.ts.map +0 -1
  145. package/dist/chat/messages.js +0 -210
  146. package/dist/chat/name.d.ts +0 -7
  147. package/dist/chat/name.d.ts.map +0 -1
  148. package/dist/chat/name.js +0 -37
  149. package/dist/chat/opened.d.ts +0 -12
  150. package/dist/chat/opened.d.ts.map +0 -1
  151. package/dist/chat/opened.js +0 -19
  152. package/dist/chat/overlay.d.ts +0 -32
  153. package/dist/chat/overlay.d.ts.map +0 -1
  154. package/dist/chat/overlay.js +0 -103
  155. package/dist/chat/parts.d.ts +0 -58
  156. package/dist/chat/parts.d.ts.map +0 -1
  157. package/dist/chat/parts.js +0 -120
  158. package/dist/chat/pieces.d.ts +0 -62
  159. package/dist/chat/pieces.d.ts.map +0 -1
  160. package/dist/chat/pieces.js +0 -1110
  161. package/dist/chat/process.d.ts +0 -20
  162. package/dist/chat/process.d.ts.map +0 -1
  163. package/dist/chat/process.js +0 -32
  164. package/dist/chat/provider.d.ts +0 -70
  165. package/dist/chat/provider.d.ts.map +0 -1
  166. package/dist/chat/provider.js +0 -635
  167. package/dist/chat/question.d.ts +0 -9
  168. package/dist/chat/question.d.ts.map +0 -1
  169. package/dist/chat/question.js +0 -69
  170. package/dist/chat/questions.d.ts +0 -31
  171. package/dist/chat/questions.d.ts.map +0 -1
  172. package/dist/chat/questions.js +0 -111
  173. package/dist/chat/read.d.ts +0 -5
  174. package/dist/chat/read.d.ts.map +0 -1
  175. package/dist/chat/read.js +0 -13
  176. package/dist/chat/ready.d.ts +0 -37
  177. package/dist/chat/ready.d.ts.map +0 -1
  178. package/dist/chat/ready.js +0 -93
  179. package/dist/chat/room-file.d.ts +0 -8
  180. package/dist/chat/room-file.d.ts.map +0 -1
  181. package/dist/chat/room-file.js +0 -72
  182. package/dist/chat/steady.d.ts +0 -3
  183. package/dist/chat/steady.d.ts.map +0 -1
  184. package/dist/chat/steady.js +0 -26
  185. package/dist/chat/style.d.ts +0 -4
  186. package/dist/chat/style.d.ts.map +0 -1
  187. package/dist/chat/style.js +0 -307
  188. package/dist/chat.d.ts +0 -15
  189. package/dist/chat.d.ts.map +0 -1
  190. package/dist/chat.js +0 -8
package/dist/reach.js CHANGED
@@ -2,7 +2,7 @@ import { unheldView } from './conversation.js';
2
2
  import { modelTypes, NO_MODEL } from './model.js';
3
3
  import { changeOf, digestApplied, digestOf, observing, } from './observation.js';
4
4
  import { runtimeError } from './failure.js';
5
- import { absentReference, failure, lockedRoom, ROOM_LOCKED, undeclared, UNREADABLE, } from './outcome.js';
5
+ import { failure, lockedRoom, ROOM_LOCKED, undeclared, UNREADABLE, } from './outcome.js';
6
6
  import { beneath } from './paths.js';
7
7
  import { moveTarget, readParts, staleWrite, } from './room-draft.js';
8
8
  import { documentKey } from './rows.js';
@@ -16,7 +16,6 @@ const NO_CONVERSATION = {
16
16
  read: (conversation) => Promise.resolve(unheldView(conversation)),
17
17
  create: unconversed('conversation.create'),
18
18
  send: unconversed('conversation.send'),
19
- attach: unconversed('conversation.attach'),
20
19
  answer: unconversed('conversation.answer'),
21
20
  interrupt: unconversed('conversation.interrupt'),
22
21
  kill: unconversed('conversation.kill'),
@@ -28,10 +27,20 @@ const NO_CHAT_DRAFT = {
28
27
  prepend: () => Promise.resolve(),
29
28
  discard: () => Promise.resolve(),
30
29
  };
30
+ function areasOf(reach) {
31
+ return reach.areas ?? [];
32
+ }
33
+ function typedAreas(reach, room) {
34
+ return areasOf(reach).filter((area) => area.room === room && area.types.length > 0);
35
+ }
36
+ function fenced(reach, room, path) {
37
+ return areasOf(reach).some((area) => area.room === room && beneath(area.path, path));
38
+ }
31
39
  export function holds(reach, room) {
32
40
  return (reach === null ||
33
41
  reach.rooms.includes(room) ||
34
- reach.documents.some((document) => document.room === room));
42
+ reach.documents.some((document) => document.room === room) ||
43
+ typedAreas(reach, room).length > 0);
35
44
  }
36
45
  function wholly(reach, room) {
37
46
  return reach === null || reach.rooms.includes(room);
@@ -41,28 +50,23 @@ export function governs(reach, room) {
41
50
  return { collection: true, selection: room.typedSelection !== null };
42
51
  }
43
52
  const selected = (path) => room.typedSelection?.roots.some((root) => beneath(root, path)) ?? false;
44
- const paths = reach.documents
45
- .filter((document) => document.room === room.locator)
46
- .map(({ path }) => path);
53
+ const paths = [
54
+ ...reach.documents
55
+ .filter((document) => document.room === room.locator)
56
+ .map(({ path }) => path),
57
+ ...typedAreas(reach, room.locator).map(({ path }) => path),
58
+ ];
47
59
  return { collection: paths.some((path) => !selected(path)), selection: paths.some(selected) };
48
60
  }
49
61
  function covers(reach, room, path) {
50
62
  return (reach === null ||
51
- reach.rooms.includes(room) ||
52
- reach.documents.some((document) => document.room === room && document.path === path));
63
+ (!fenced(reach, room, path) &&
64
+ (reach.rooms.includes(room) ||
65
+ reach.documents.some((document) => document.room === room && document.path === path))));
53
66
  }
54
67
  function conversing(reach) {
55
68
  return reach === null || reach.conversations;
56
69
  }
57
- function refers(reach, scope) {
58
- if (reach === null)
59
- return true;
60
- if (scope === null)
61
- return false;
62
- return scope.path === undefined
63
- ? wholly(reach, scope.locator)
64
- : covers(reach, scope.locator, scope.path);
65
- }
66
70
  export function planReach(reach) {
67
71
  return reach === null
68
72
  ? null
@@ -71,6 +75,9 @@ export function planReach(reach) {
71
75
  documents: [
72
76
  ...new Set(reach.documents.map(({ room, path }) => documentKey(room, path))),
73
77
  ].sort(),
78
+ areas: areasOf(reach)
79
+ .map(({ room, path, types }) => ({ room, path, types: [...new Set(types)].sort() }))
80
+ .sort((left, right) => documentKey(left.room, left.path) < documentKey(right.room, right.path) ? -1 : 1),
74
81
  };
75
82
  }
76
83
  function roomsWithin(reach, rooms) {
@@ -120,6 +127,7 @@ function statusWithin(reach, status) {
120
127
  return {
121
128
  ...status,
122
129
  attentionRequired: status.attentionRequired.filter((entry) => 'refusal' in entry ? wholly(reach, entry.room) : covers(reach, entry.room, entry.path)),
130
+ unsent: status.unsent.filter((change) => covers(reach, change.room, change.path)),
123
131
  };
124
132
  }
125
133
  function queueWithin(reach, room, entries) {
@@ -144,6 +152,13 @@ function lockedError(room) {
144
152
  function deviceUnreached() {
145
153
  return runtimeError('device-unreached', 'Only the panel cleans up this device');
146
154
  }
155
+ const ATTACH_REQUIRED = 'attach-required';
156
+ function attachRequired() {
157
+ return runtimeError(ATTACH_REQUIRED, 'App code takes a file in with binaryFile.attach');
158
+ }
159
+ function carriesFile(parts) {
160
+ return parts !== null && typeof parts === 'object' && Object.hasOwn(parts, 'file');
161
+ }
147
162
  export function narrowed(runtime, given, told) {
148
163
  const { md, watch } = runtime;
149
164
  let reach = given;
@@ -254,7 +269,7 @@ export function narrowed(runtime, given, told) {
254
269
  };
255
270
  const files = new Map();
256
271
  let handed = 0;
257
- const hand = async (reading) => {
272
+ async function hand(reading) {
258
273
  const answer = await reading;
259
274
  if (answer.kind !== 'binary')
260
275
  return answer;
@@ -262,12 +277,12 @@ export function narrowed(runtime, given, told) {
262
277
  const file = String(handed);
263
278
  files.set(file, answer.file);
264
279
  return { ...answer, file };
265
- };
280
+ }
266
281
  const conversation = () => (conversing(reach) ? md.conversation : NO_CONVERSATION);
267
282
  const chatDraft = () => (conversing(reach) ? md.chatDraft : NO_CHAT_DRAFT);
268
283
  const view = {
269
284
  ...md,
270
- rooms: () => roomsWithin(reach, md.rooms()),
285
+ rooms: () => md.rooms().then((rooms) => roomsWithin(reach, rooms)),
271
286
  query: ((input) => {
272
287
  const plan = runtime.plan(input, reach);
273
288
  return Promise.resolve(unlocking(plan.rooms) ?? runtime.query({ ...plan, locked: runtime.lockedRooms() }));
@@ -282,8 +297,7 @@ export function narrowed(runtime, given, told) {
282
297
  return md.types(room);
283
298
  if (!holds(reach, room))
284
299
  return structuredClone(UNHELD_TYPES);
285
- const listed = md.rooms().find(({ locator }) => locator === room);
286
- return typesWithin(reach, listed, md.types(room));
300
+ return typesWithin(reach, runtime.room(room), md.types(room));
287
301
  },
288
302
  async save(room, roomDrafts, writtenBy) {
289
303
  if (!holds(reach, room))
@@ -302,6 +316,10 @@ export function narrowed(runtime, given, told) {
302
316
  async saveParts(room, parts, writtenBy) {
303
317
  if (!holds(reach, room))
304
318
  throw unreached(room);
319
+ const filed = reach === null ? undefined : parts.find(({ parts: one }) => carriesFile(one));
320
+ if (filed !== undefined) {
321
+ return { outcome: 'refused', code: ATTACH_REQUIRED, retryable: false, file: filed.path };
322
+ }
305
323
  if (runtime.locked(room))
306
324
  return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
307
325
  const held = parts.map(({ parts: one }) => readParts(one).move);
@@ -334,15 +352,16 @@ export function narrowed(runtime, given, told) {
334
352
  : runtime.locked(room)
335
353
  ? Promise.resolve(lockedRoom(room))
336
354
  : md.binaryFile.link(room, path, revision),
337
- readReference(reference) {
338
- const scope = runtime.referrerScope(reference.referrer);
339
- if (!refers(reach, scope))
340
- return Promise.resolve(absentReference(reference.fileRef));
341
- if (scope !== null && runtime.locked(scope.locator)) {
342
- return Promise.resolve(lockedRoom(scope.locator));
343
- }
344
- return hand(md.binaryFile.readReference(reference));
345
- },
355
+ show: (room, path, revision) => !covers(reach, room, path)
356
+ ? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
357
+ : runtime.locked(room)
358
+ ? Promise.resolve(lockedRoom(room))
359
+ : hand(md.binaryFile.show(room, path, revision)),
360
+ attach: (room, file) => !wholly(reach, room)
361
+ ? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
362
+ : runtime.locked(room)
363
+ ? Promise.resolve(lockedRoom(room))
364
+ : md.binaryFile.attach(room, file),
346
365
  async part(file, part) {
347
366
  const key = files.get(file);
348
367
  if (key === undefined)
@@ -367,15 +386,24 @@ export function narrowed(runtime, given, told) {
367
386
  throw lockedError(room);
368
387
  return shownDraft(reach, await md.roomDraft.read(room, path));
369
388
  },
370
- async write(room, path, revision, parts) {
371
- const move = readParts(parts).move;
372
- if (!covers(reach, room, path) || !moves(reach, room, move))
373
- throw unreached(room);
374
- if (runtime.locked(room))
375
- throw lockedError(room);
376
- if (intoLocked([move]))
377
- throw lockedError(move.room);
378
- return writeWithin(reach, await md.roomDraft.write(room, path, revision, parts));
389
+ write(room, path, revision, parts, next) {
390
+ try {
391
+ if (reach !== null && carriesFile(parts))
392
+ throw attachRequired();
393
+ const move = readParts(parts).move;
394
+ if (!covers(reach, room, path) || !moves(reach, room, move))
395
+ throw unreached(room);
396
+ if (runtime.locked(room))
397
+ throw lockedError(room);
398
+ if (intoLocked([move]))
399
+ throw lockedError(move.room);
400
+ }
401
+ catch (error) {
402
+ return Promise.reject(error);
403
+ }
404
+ return md.roomDraft
405
+ .write(room, path, revision, parts, next)
406
+ .then((written) => writeWithin(reach, written));
379
407
  },
380
408
  async discard(room, path, revision) {
381
409
  if (!covers(reach, room, path))
@@ -390,11 +418,6 @@ export function narrowed(runtime, given, told) {
390
418
  read: (id, options) => conversation().read(id, options),
391
419
  create: (input) => conversation().create(input),
392
420
  send: (id, operation, draft) => conversation().send(id, operation, draft),
393
- attach: (room, file) => !wholly(reach, room)
394
- ? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
395
- : runtime.locked(room)
396
- ? Promise.resolve(lockedRoom(room))
397
- : conversation().attach(room, file),
398
421
  answer: (id, answer) => conversation().answer(id, answer),
399
422
  interrupt: (id) => conversation().interrupt(id),
400
423
  kill: (id) => conversation().kill(id),
@@ -18,17 +18,27 @@ export type Persistence = Open<'granted' | 'denied' | 'unavailable'>;
18
18
  export type Durability = Open<'persistent' | 'best-effort'>;
19
19
  export type ConnectionAvailability = Open<'connected' | 'connecting' | 'unreachable'>;
20
20
  export type HouseOutcome = Open<'open' | 'write-halted' | 'refused'>;
21
- export type CapacityCause = {
22
- readonly cause: Open<'insufficient-space' | 'storage-exceeded'>;
23
- readonly needed: number | null;
24
- readonly available: number | null;
25
- };
21
+ export type Space = Open<'full'>;
26
22
  export type RefusedRoom = {
27
23
  readonly room: string;
24
+ readonly name: string;
28
25
  readonly file: string;
29
26
  readonly rule: string;
30
27
  readonly location: string | null;
31
28
  };
29
+ export type InstallationStep = Open<'downloading' | 'writing' | 'replaying'>;
30
+ export type InstallationPause = Open<'hidden'>;
31
+ export type InstallationAmount = {
32
+ readonly done: number;
33
+ readonly total: number;
34
+ };
35
+ export type Installation = {
36
+ readonly step: InstallationStep | null;
37
+ readonly paused: InstallationPause | null;
38
+ readonly rooms: InstallationAmount;
39
+ readonly parts: InstallationAmount;
40
+ readonly bytes: InstallationAmount;
41
+ };
32
42
  export type ReadinessStatus = Open<'preparing' | 'paused' | 'refused' | 'ready' | 'lost'>;
33
43
  export type Readiness = {
34
44
  readonly status: ReadinessStatus;
@@ -40,7 +50,8 @@ export type Readiness = {
40
50
  readonly persistence: Persistence;
41
51
  readonly connection: ConnectionAvailability;
42
52
  readonly house: HouseOutcome;
43
- readonly capacity: CapacityCause | null;
53
+ readonly space: Space | null;
54
+ readonly installation: Installation;
44
55
  readonly refused: readonly RefusedRoom[];
45
56
  readonly lost: boolean;
46
57
  };
@@ -48,6 +59,5 @@ export type ReadinessFacts = Omit<Readiness, 'status' | 'ready' | 'usable' | 'du
48
59
  readonly coverage: Omit<TargetCoverage, 'complete'>;
49
60
  readonly established: boolean;
50
61
  };
51
- export declare const SETTLED_ROOMS: ReadonlySet<string>;
52
62
  export declare function readinessOf(facts: ReadinessFacts): Readiness;
53
63
  //# sourceMappingURL=readiness.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"readiness.d.ts","sourceRoot":"","sources":["../src/readiness.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"readiness.d.ts","sourceRoot":"","sources":["../src/readiness.ts"],"names":[],"mappings":"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"}
package/dist/readiness.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const COMPLETE_ROOMS = new Set(['complete', 'unadmitted']);
2
- export const SETTLED_ROOMS = new Set([...COMPLETE_ROOMS, 'refused']);
2
+ const SETTLED_ROOMS = new Set([...COMPLETE_ROOMS, 'refused']);
3
3
  export function readinessOf(facts) {
4
4
  const { established, coverage: held, ...reported } = facts;
5
5
  const settledConversations = held.conversations === 'complete' || held.conversations === 'undeclared';
@@ -15,12 +15,12 @@ export function readinessOf(facts) {
15
15
  const usable = stored && (ready || established);
16
16
  const status = ready
17
17
  ? 'ready'
18
- : facts.capacity !== null
18
+ : facts.space !== null || facts.installation.paused !== null
19
19
  ? 'paused'
20
- : facts.lost && !established
21
- ? 'lost'
22
- : settled && !complete
23
- ? 'refused'
20
+ : settled && !complete
21
+ ? 'refused'
22
+ : facts.lost && !established
23
+ ? 'lost'
24
24
  : 'preparing';
25
25
  return {
26
26
  ...reported,
@@ -1 +1 @@
1
- {"version":3,"file":"reads.d.ts","sourceRoot":"","sources":["../src/reads.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAOR,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG;IAC9B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,IAAI,IAAI,CAAC;IAChB,IAAI,IAAI,IAAI,CAAC;CACd,CAAC;AAiCF,wBAAgB,SAAS,CACvB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,EACzC,UAAU,EAAE,MAAM,MAAM,GACvB,SAAS,CA0FX"}
1
+ {"version":3,"file":"reads.d.ts","sourceRoot":"","sources":["../src/reads.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgD,MAAM,cAAc,CAAC;AAC1F,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG;IAC9B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,IAAI,IAAI,CAAC;IAChB,IAAI,IAAI,IAAI,CAAC;CACd,CAAC;AA2BF,wBAAgB,SAAS,CACvB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,EACzC,UAAU,EAAE,MAAM,MAAM,GACvB,SAAS,CA4EX"}
package/dist/reads.js CHANGED
@@ -4,30 +4,24 @@ function declaredAs(declaration) {
4
4
  const { roomVersion: _version, ...declared } = declaration;
5
5
  return declared;
6
6
  }
7
- function sameHeld(one, other) {
8
- return one === other;
9
- }
10
7
  function failed(answer) {
11
- return answer?.kind === 'transport-uncertainty';
8
+ return answer.kind === 'transport-uncertainty';
12
9
  }
13
10
  function continues(answer) {
14
- const page = answer;
15
- return page?.kind === 'net-advancement' && page.pageToken !== undefined;
11
+ return answer?.kind === 'net-advancement' && answer.pageToken !== undefined;
16
12
  }
17
13
  export function doorReads(adapter, declaration, generation) {
18
14
  const reading = new Map();
19
15
  const taken = new Map();
20
16
  let carrying = false;
21
- function joined(read, authorization, request, ask) {
22
- const key = `${read} ${request.locator} ${request.pageToken ?? ''}`;
23
- const { held, ...named } = request;
24
- const asked = JSON.stringify([declaredAs(declaration(request.locator)), named]);
17
+ function joined(authorization, request) {
18
+ const key = `${request.locator} ${request.pageToken ?? ''}`;
19
+ const asked = JSON.stringify([declaredAs(declaration(request.locator)), request]);
25
20
  const asking = generation();
26
21
  const current = reading.get(key);
27
22
  if (current !== undefined &&
28
23
  current.authorization === authorization &&
29
24
  current.asked === asked &&
30
- sameHeld(current.held, held) &&
31
25
  (!current.settled || current.holder < asking)) {
32
26
  if (current.settled && !current.continued)
33
27
  reading.delete(key);
@@ -35,7 +29,7 @@ export function doorReads(adapter, declaration, generation) {
35
29
  current.holder = Math.max(current.holder, asking);
36
30
  if (current.from === asking)
37
31
  return current.answer;
38
- const again = () => joined(read, authorization, request, ask);
32
+ const again = () => joined(authorization, request);
39
33
  return current.answer.then((answer) => {
40
34
  if (failed(answer))
41
35
  return again();
@@ -43,12 +37,11 @@ export function doorReads(adapter, declaration, generation) {
43
37
  return answer;
44
38
  }, again);
45
39
  }
46
- const answer = ask();
40
+ const answer = adapter.refresh(authorization, request);
47
41
  const sent = {
48
42
  locator: request.locator,
49
43
  authorization,
50
44
  asked,
51
- held,
52
45
  answer,
53
46
  from: asking,
54
47
  holder: asking,
@@ -58,7 +51,7 @@ export function doorReads(adapter, declaration, generation) {
58
51
  reading.set(key, sent);
59
52
  const settled = (result, kept) => {
60
53
  sent.settled = true;
61
- sent.continued = kept && read === 'refresh' && continues(result);
54
+ sent.continued = kept && continues(result);
62
55
  if (reading.get(key) !== sent)
63
56
  return;
64
57
  const live = sent.holder === generation();
@@ -69,8 +62,8 @@ export function doorReads(adapter, declaration, generation) {
69
62
  return answer;
70
63
  }
71
64
  return {
72
- bootstrap: (authorization, request) => joined('bootstrap', authorization, request, () => adapter.bootstrap(authorization, request)),
73
- refresh: (authorization, request) => joined('refresh', authorization, request, () => adapter.refresh(authorization, request)),
65
+ bootstrap: (authorization, request) => adapter.bootstrap(authorization, request),
66
+ refresh: joined,
74
67
  reached: (locator, roomVersion, target) => adapter.reached(locator, roomVersion, target),
75
68
  carried: (locator) => taken.get(locator) ?? 0,
76
69
  finished(locator, turn) {
@@ -21,5 +21,6 @@ export type Recovery = {
21
21
  retire(): Promise<void>;
22
22
  };
23
23
  export declare function retryDelay(tries: number, firstMs?: number, maxMs?: number): number;
24
+ export declare function untilAnswered<T>(ask: () => Promise<T>, signal: AbortSignal, answered?: (answer: T) => boolean): Promise<T>;
24
25
  export declare function createRecovery(options?: RecoveryOptions): Recovery;
25
26
  //# sourceMappingURL=recovery.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;AAElE,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEhF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClF,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,MAAM,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IACnC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB,CAAC;AAsBF,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,SAAW,EAAE,KAAK,SAAS,GAAG,MAAM,CAGpF;AAwKD,wBAAgB,cAAc,CAAC,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAStE"}
1
+ {"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;AAElE,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEhF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClF,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,MAAM,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IACnC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB,CAAC;AAsBF,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,SAAW,EAAE,KAAK,SAAS,GAAG,MAAM,CAGpF;AAED,wBAAsB,aAAa,CAAC,CAAC,EACnC,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACrB,MAAM,EAAE,WAAW,EACnB,QAAQ,GAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAoB,GAC5C,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAwKD,wBAAgB,cAAc,CAAC,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAStE"}
package/dist/recovery.js CHANGED
@@ -7,6 +7,32 @@ export function retryDelay(tries, firstMs = FIRST_MS, maxMs = MAX_MS) {
7
7
  const longest = Math.min(maxMs, firstMs * 2 ** tries);
8
8
  return longest / 2 + (Math.random() * longest) / 2;
9
9
  }
10
+ export async function untilAnswered(ask, signal, answered = () => true) {
11
+ for (let tries = 0;; tries += 1) {
12
+ try {
13
+ const answer = await ask();
14
+ if (answered(answer) || signal.aborted)
15
+ return answer;
16
+ }
17
+ catch (error) {
18
+ if (signal.aborted)
19
+ throw error;
20
+ }
21
+ await new Promise((resume) => {
22
+ const stop = () => {
23
+ clearTimeout(again);
24
+ resume();
25
+ };
26
+ // A read that failed is asked again on the doubling backoff, so its asker is answered once the failure clears.
27
+ const again = setTimeout(() => {
28
+ signal.removeEventListener('abort', stop);
29
+ resume();
30
+ }, retryDelay(tries));
31
+ signal.addEventListener('abort', stop, { once: true });
32
+ });
33
+ signal.throwIfAborted();
34
+ }
35
+ }
10
36
  function owner(backoff, inFlight, release = () => { }) {
11
37
  const intents = new Map();
12
38
  const children = new Set();
package/dist/refresh.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import type { AdapterFailure, Authorization, RetryableRefusal } from './adapter.js';
1
+ import type { AdapterFailure, Authorization, RefreshPage, RetryableRefusal } from './adapter.js';
2
2
  import type { Reads, Remodel } from './bootstrap.js';
3
3
  import type { ReplicaRecord } from './replica.js';
4
4
  import type { RefreshedPage } from './store.js';
5
- import type { HeldEntry } from './tables.js';
5
+ import type { HeldEntry, StoredEntry } from './tables.js';
6
6
  import { type Unconfirmed } from './transfer.js';
7
7
  export type Advancement = {
8
8
  kind: 'still-current';
@@ -14,8 +14,12 @@ export type Advancement = {
14
14
  kind: 'beyond-horizon';
15
15
  } | RetryableRefusal | Unconfirmed | AdapterFailure;
16
16
  export type Refreshing = {
17
+ turn(): Promise<void>;
17
18
  prior(paths: readonly string[]): Promise<ReadonlyMap<string, HeldEntry>>;
18
19
  stage(page: RefreshedPage): Promise<boolean>;
19
20
  };
21
+ type PageContent = Pick<RefreshPage, 'documents' | 'revisions' | 'fileIds' | 'changes' | 'binaryFiles'>;
22
+ export declare function pageEntries(page: PageContent, removals: readonly string[], roomVersion: string, prior: (paths: readonly string[]) => Promise<ReadonlyMap<string, HeldEntry>>): Promise<StoredEntry[]>;
20
23
  export declare function advancement(adapter: Reads, authorization: Authorization, held: ReplicaRecord, remodel: Remodel, continuing: () => boolean, staging: Refreshing): Promise<Advancement>;
24
+ export {};
21
25
  //# sourceMappingURL=refresh.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAe,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACjG,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAE9D,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CAAE,GACzE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B,gBAAgB,GAChB,WAAW,GACX,cAAc,CAAC;AAEnB,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IACzE,KAAK,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9C,CAAC;AAkEF,wBAAsB,WAAW,CAC/B,OAAO,EAAE,KAAK,EACd,aAAa,EAAE,aAAa,EAC5B,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,OAAO,EACzB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,WAAW,CAAC,CA+CtB"}
1
+ {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACjG,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAG9D,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CAAE,GACzE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B,gBAAgB,GAChB,WAAW,GACX,cAAc,CAAC;AAEnB,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,KAAK,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IACzE,KAAK,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9C,CAAC;AASF,KAAK,WAAW,GAAG,IAAI,CACrB,WAAW,EACX,WAAW,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAClE,CAAC;AAmFF,wBAAsB,WAAW,CAC/B,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,GAC3E,OAAO,CAAC,WAAW,EAAE,CAAC,CAKxB;AAeD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,KAAK,EACd,aAAa,EAAE,aAAa,EAC5B,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,OAAO,EACzB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,WAAW,CAAC,CA8CtB"}
package/dist/refresh.js CHANGED
@@ -1,24 +1,47 @@
1
1
  import { unconfirmed } from './transfer.js';
2
- async function pageOf(page, roomVersion, staging) {
3
- const removed = new Set(page.removals);
4
- const documents = Object.keys(page.documents).filter((path) => !removed.has(path));
5
- const binaries = Object.keys(page.binaryFiles).filter((path) => !removed.has(path));
6
- const written = new Set([...documents, ...binaries]);
7
- const others = [
8
- ...new Set([
9
- ...Object.keys(page.revisions),
10
- ...Object.keys(page.fileIds ?? {}),
11
- ...Object.keys(page.changes),
12
- ]),
13
- ].filter((path) => !written.has(path) && !removed.has(path));
14
- const asked = [
15
- ...documents.filter((path) => page.revisions[path] === undefined),
16
- ...binaries.filter((path) => page.revisions[path] === undefined),
17
- ...others,
18
- ];
19
- const prior = asked.length === 0 ? new Map() : await staging.prior(asked);
2
+ import { ROW_WEIGHT, stepped, yielded } from './turn.js';
3
+ function* listing(page, removals) {
4
+ const removed = new Set();
5
+ for (const path of removals) {
6
+ removed.add(path);
7
+ yield ROW_WEIGHT;
8
+ }
9
+ const documents = [];
10
+ const binaries = [];
11
+ const asked = [];
12
+ const written = new Set();
13
+ for (const [kept, named] of [
14
+ [documents, page.documents],
15
+ [binaries, page.binaryFiles],
16
+ ]) {
17
+ for (const path of Object.keys(named)) {
18
+ yield ROW_WEIGHT;
19
+ if (removed.has(path))
20
+ continue;
21
+ kept.push(path);
22
+ written.add(path);
23
+ if (page.revisions[path] === undefined)
24
+ asked.push(path);
25
+ }
26
+ }
27
+ const others = [];
28
+ const seen = new Set();
29
+ for (const named of [page.revisions, page.fileIds ?? {}, page.changes]) {
30
+ for (const path of Object.keys(named)) {
31
+ yield ROW_WEIGHT;
32
+ if (seen.has(path))
33
+ continue;
34
+ seen.add(path);
35
+ if (!written.has(path) && !removed.has(path))
36
+ others.push(path);
37
+ }
38
+ }
39
+ return { documents, binaries, others, asked: [...asked, ...others] };
40
+ }
41
+ function* entering(page, roomVersion, listed, prior) {
20
42
  const entries = [];
21
- for (const path of documents) {
43
+ for (const path of listed.documents) {
44
+ yield ROW_WEIGHT;
22
45
  entries.push({
23
46
  path,
24
47
  content: page.documents[path],
@@ -29,7 +52,8 @@ async function pageOf(page, roomVersion, staging) {
29
52
  written: roomVersion,
30
53
  });
31
54
  }
32
- for (const path of binaries) {
55
+ for (const path of listed.binaries) {
56
+ yield ROW_WEIGHT;
33
57
  entries.push({
34
58
  path,
35
59
  content: null,
@@ -40,7 +64,8 @@ async function pageOf(page, roomVersion, staging) {
40
64
  written: null,
41
65
  });
42
66
  }
43
- for (const path of others) {
67
+ for (const path of listed.others) {
68
+ yield ROW_WEIGHT;
44
69
  const held = prior.get(path);
45
70
  if (held === undefined)
46
71
  continue;
@@ -52,8 +77,17 @@ async function pageOf(page, roomVersion, staging) {
52
77
  change: page.changes[path] ?? held.change,
53
78
  });
54
79
  }
80
+ return entries;
81
+ }
82
+ export async function pageEntries(page, removals, roomVersion, prior) {
83
+ await yielded();
84
+ const listed = await stepped(listing(page, removals));
85
+ const held = listed.asked.length === 0 ? new Map() : await prior(listed.asked);
86
+ return stepped(entering(page, roomVersion, listed, held));
87
+ }
88
+ async function pageOf(page, roomVersion, staging) {
55
89
  return {
56
- entries,
90
+ entries: await pageEntries(page, page.removals, roomVersion, (paths) => staging.prior(paths)),
57
91
  removals: page.removals,
58
92
  folders: page.folders ?? [],
59
93
  folderRemovals: page.folderRemovals ?? [],
@@ -62,6 +96,9 @@ async function pageOf(page, roomVersion, staging) {
62
96
  export async function advancement(adapter, authorization, held, remodel, continuing, staging) {
63
97
  const locator = held.locator;
64
98
  const fromRoomVersion = held.roomVersion;
99
+ await staging.turn();
100
+ if (!continuing())
101
+ return unconfirmed;
65
102
  const first = await adapter.refresh(authorization, {
66
103
  locator,
67
104
  selection: held.replica.selection,
@@ -70,10 +107,7 @@ export async function advancement(adapter, authorization, held, remodel, continu
70
107
  if (first.kind !== 'net-advancement')
71
108
  return first;
72
109
  const roomVersion = first.roomVersion;
73
- const models = remodel(first.models, {
74
- collection: held.model,
75
- selection: held.selectionModel,
76
- });
110
+ const models = remodel(first.models, { collection: held.model });
77
111
  const changed = new Set();
78
112
  const staged = async (page) => {
79
113
  const read = await pageOf(page, roomVersion, staging);
@@ -87,6 +121,7 @@ export async function advancement(adapter, authorization, held, remodel, continu
87
121
  return unconfirmed;
88
122
  let pageToken = first.pageToken;
89
123
  while (pageToken !== undefined) {
124
+ await staging.turn();
90
125
  if (!continuing())
91
126
  return unconfirmed;
92
127
  const page = await adapter.refresh(authorization, {
@@ -110,7 +145,6 @@ export async function advancement(adapter, authorization, held, remodel, continu
110
145
  record: {
111
146
  ...held,
112
147
  model: models.collection,
113
- selectionModel: models.selection,
114
148
  roomVersion,
115
149
  },
116
150
  changed,