@agentshouse/mdruntime 0.1.0-cc5745cd9af96 → 0.1.0-ccbb89b0ca151

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 (225) hide show
  1. package/README.md +18 -15
  2. package/dist/adapter.d.ts +56 -32
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/attached-model.d.ts +5 -1
  5. package/dist/attached-model.d.ts.map +1 -1
  6. package/dist/attached-model.js +21 -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 +30 -8
  11. package/dist/bootstrap.d.ts.map +1 -1
  12. package/dist/bootstrap.js +186 -85
  13. package/dist/chain.d.ts +11 -0
  14. package/dist/chain.d.ts.map +1 -0
  15. package/dist/chain.js +64 -0
  16. package/dist/change-set.d.ts +6 -16
  17. package/dist/change-set.d.ts.map +1 -1
  18. package/dist/change-set.js +11 -94
  19. package/dist/change.d.ts +31 -1
  20. package/dist/change.d.ts.map +1 -1
  21. package/dist/change.js +10 -1
  22. package/dist/client.d.ts +9 -5
  23. package/dist/client.d.ts.map +1 -1
  24. package/dist/client.js +80 -6
  25. package/dist/collection.d.ts +6 -20
  26. package/dist/collection.d.ts.map +1 -1
  27. package/dist/collection.js +31 -354
  28. package/dist/compile.d.ts +16 -0
  29. package/dist/compile.d.ts.map +1 -0
  30. package/dist/compile.js +765 -0
  31. package/dist/connection.d.ts +16 -9
  32. package/dist/connection.d.ts.map +1 -1
  33. package/dist/connection.js +2399 -952
  34. package/dist/conversation.d.ts +3 -3
  35. package/dist/conversation.d.ts.map +1 -1
  36. package/dist/conversation.js +80 -68
  37. package/dist/digest.d.ts +7 -0
  38. package/dist/digest.d.ts.map +1 -0
  39. package/dist/digest.js +113 -0
  40. package/dist/durability.d.ts +3 -5
  41. package/dist/durability.d.ts.map +1 -1
  42. package/dist/durability.js +5 -0
  43. package/dist/entry.d.ts +3 -1
  44. package/dist/entry.d.ts.map +1 -1
  45. package/dist/entry.js +18 -24
  46. package/dist/file.d.ts +2 -19
  47. package/dist/file.d.ts.map +1 -1
  48. package/dist/file.js +7 -122
  49. package/dist/fulltext.d.ts +27 -0
  50. package/dist/fulltext.d.ts.map +1 -0
  51. package/dist/fulltext.js +368 -0
  52. package/dist/host.d.ts +4 -4
  53. package/dist/host.d.ts.map +1 -1
  54. package/dist/host.js +45 -15
  55. package/dist/identity.d.ts +0 -1
  56. package/dist/identity.d.ts.map +1 -1
  57. package/dist/identity.js +0 -3
  58. package/dist/index.d.ts +11 -9
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +4 -1
  61. package/dist/live.d.ts +22 -0
  62. package/dist/live.d.ts.map +1 -0
  63. package/dist/live.js +124 -0
  64. package/dist/media.d.ts +8 -0
  65. package/dist/media.d.ts.map +1 -0
  66. package/dist/media.js +195 -0
  67. package/dist/memory.d.ts +2 -1
  68. package/dist/memory.d.ts.map +1 -1
  69. package/dist/memory.js +63 -22
  70. package/dist/messages.d.ts +28 -0
  71. package/dist/messages.d.ts.map +1 -0
  72. package/dist/messages.js +90 -0
  73. package/dist/model.d.ts.map +1 -1
  74. package/dist/model.js +1 -1
  75. package/dist/name.d.ts +4 -0
  76. package/dist/name.d.ts.map +1 -0
  77. package/dist/name.js +122 -0
  78. package/dist/observation.d.ts +12 -0
  79. package/dist/observation.d.ts.map +1 -1
  80. package/dist/observation.js +84 -0
  81. package/dist/opened.d.ts +22 -0
  82. package/dist/opened.d.ts.map +1 -0
  83. package/dist/opened.js +107 -0
  84. package/dist/outcome.d.ts +40 -5
  85. package/dist/outcome.d.ts.map +1 -1
  86. package/dist/outcome.js +36 -2
  87. package/dist/overlay.d.ts +1 -4
  88. package/dist/overlay.d.ts.map +1 -1
  89. package/dist/overlay.js +22 -148
  90. package/dist/query.d.ts +11 -1
  91. package/dist/query.d.ts.map +1 -1
  92. package/dist/query.js +13 -1
  93. package/dist/reach.d.ts +11 -3
  94. package/dist/reach.d.ts.map +1 -1
  95. package/dist/reach.js +198 -69
  96. package/dist/readiness.d.ts +20 -9
  97. package/dist/readiness.d.ts.map +1 -1
  98. package/dist/readiness.js +6 -6
  99. package/dist/reads.d.ts.map +1 -1
  100. package/dist/reads.js +4 -2
  101. package/dist/recovery.d.ts +2 -2
  102. package/dist/recovery.d.ts.map +1 -1
  103. package/dist/recovery.js +8 -7
  104. package/dist/refresh.d.ts +15 -14
  105. package/dist/refresh.d.ts.map +1 -1
  106. package/dist/refresh.js +113 -75
  107. package/dist/replica.d.ts +56 -39
  108. package/dist/replica.d.ts.map +1 -1
  109. package/dist/replica.js +277 -197
  110. package/dist/room-draft.d.ts +4 -1
  111. package/dist/room-draft.d.ts.map +1 -1
  112. package/dist/room-draft.js +54 -13
  113. package/dist/rows.d.ts +38 -31
  114. package/dist/rows.d.ts.map +1 -1
  115. package/dist/rows.js +173 -101
  116. package/dist/save.d.ts +49 -14
  117. package/dist/save.d.ts.map +1 -1
  118. package/dist/save.js +352 -98
  119. package/dist/search.d.ts +11 -43
  120. package/dist/search.d.ts.map +1 -1
  121. package/dist/search.js +0 -213
  122. package/dist/shared.d.ts +4 -3
  123. package/dist/shared.d.ts.map +1 -1
  124. package/dist/shared.js +67 -34
  125. package/dist/store.d.ts +83 -95
  126. package/dist/store.d.ts.map +1 -1
  127. package/dist/store.js +317 -720
  128. package/dist/stored.d.ts +152 -0
  129. package/dist/stored.d.ts.map +1 -0
  130. package/dist/stored.js +607 -0
  131. package/dist/tables.d.ts +352 -0
  132. package/dist/tables.d.ts.map +1 -0
  133. package/dist/tables.js +624 -0
  134. package/dist/turn.d.ts +1 -1
  135. package/dist/turn.d.ts.map +1 -1
  136. package/dist/turn.js +31 -20
  137. package/dist/validation.d.ts +30 -0
  138. package/dist/validation.d.ts.map +1 -0
  139. package/dist/validation.js +162 -0
  140. package/dist/windows.d.ts +2 -6
  141. package/dist/windows.d.ts.map +1 -1
  142. package/dist/windows.js +30 -34
  143. package/dist/wire.d.ts +17 -1
  144. package/dist/wire.d.ts.map +1 -1
  145. package/dist/wire.js +5 -1
  146. package/dist/words.d.ts +19 -0
  147. package/dist/words.d.ts.map +1 -0
  148. package/dist/words.js +150 -0
  149. package/package.json +18 -19
  150. package/AGENTS.md +0 -299
  151. package/dist/chat/acts.d.ts +0 -33
  152. package/dist/chat/acts.d.ts.map +0 -1
  153. package/dist/chat/acts.js +0 -36
  154. package/dist/chat/context.d.ts +0 -3
  155. package/dist/chat/context.d.ts.map +0 -1
  156. package/dist/chat/context.js +0 -10
  157. package/dist/chat/earlier.d.ts +0 -10
  158. package/dist/chat/earlier.d.ts.map +0 -1
  159. package/dist/chat/earlier.js +0 -54
  160. package/dist/chat/input.d.ts +0 -9
  161. package/dist/chat/input.d.ts.map +0 -1
  162. package/dist/chat/input.js +0 -99
  163. package/dist/chat/kit.d.ts +0 -61
  164. package/dist/chat/kit.d.ts.map +0 -1
  165. package/dist/chat/kit.js +0 -123
  166. package/dist/chat/lasting.d.ts +0 -6
  167. package/dist/chat/lasting.d.ts.map +0 -1
  168. package/dist/chat/lasting.js +0 -19
  169. package/dist/chat/list.d.ts +0 -28
  170. package/dist/chat/list.d.ts.map +0 -1
  171. package/dist/chat/list.js +0 -103
  172. package/dist/chat/markdown.d.ts +0 -21
  173. package/dist/chat/markdown.d.ts.map +0 -1
  174. package/dist/chat/markdown.js +0 -246
  175. package/dist/chat/message.d.ts +0 -7
  176. package/dist/chat/message.d.ts.map +0 -1
  177. package/dist/chat/message.js +0 -202
  178. package/dist/chat/messages.d.ts +0 -24
  179. package/dist/chat/messages.d.ts.map +0 -1
  180. package/dist/chat/messages.js +0 -187
  181. package/dist/chat/name.d.ts +0 -6
  182. package/dist/chat/name.d.ts.map +0 -1
  183. package/dist/chat/name.js +0 -37
  184. package/dist/chat/opened.d.ts +0 -11
  185. package/dist/chat/opened.d.ts.map +0 -1
  186. package/dist/chat/opened.js +0 -17
  187. package/dist/chat/overlay.d.ts +0 -32
  188. package/dist/chat/overlay.d.ts.map +0 -1
  189. package/dist/chat/overlay.js +0 -107
  190. package/dist/chat/parts.d.ts +0 -57
  191. package/dist/chat/parts.d.ts.map +0 -1
  192. package/dist/chat/parts.js +0 -119
  193. package/dist/chat/pieces.d.ts +0 -62
  194. package/dist/chat/pieces.d.ts.map +0 -1
  195. package/dist/chat/pieces.js +0 -1110
  196. package/dist/chat/process.d.ts +0 -20
  197. package/dist/chat/process.d.ts.map +0 -1
  198. package/dist/chat/process.js +0 -32
  199. package/dist/chat/provider.d.ts +0 -64
  200. package/dist/chat/provider.d.ts.map +0 -1
  201. package/dist/chat/provider.js +0 -638
  202. package/dist/chat/question.d.ts +0 -9
  203. package/dist/chat/question.d.ts.map +0 -1
  204. package/dist/chat/question.js +0 -69
  205. package/dist/chat/questions.d.ts +0 -31
  206. package/dist/chat/questions.d.ts.map +0 -1
  207. package/dist/chat/questions.js +0 -111
  208. package/dist/chat/read.d.ts +0 -5
  209. package/dist/chat/read.d.ts.map +0 -1
  210. package/dist/chat/read.js +0 -13
  211. package/dist/chat/ready.d.ts +0 -34
  212. package/dist/chat/ready.d.ts.map +0 -1
  213. package/dist/chat/ready.js +0 -91
  214. package/dist/chat/steady.d.ts +0 -3
  215. package/dist/chat/steady.d.ts.map +0 -1
  216. package/dist/chat/steady.js +0 -26
  217. package/dist/chat/style.d.ts +0 -4
  218. package/dist/chat/style.d.ts.map +0 -1
  219. package/dist/chat/style.js +0 -302
  220. package/dist/chat.d.ts +0 -14
  221. package/dist/chat.d.ts.map +0 -1
  222. package/dist/chat.js +0 -8
  223. package/dist/read-side.d.ts +0 -27
  224. package/dist/read-side.d.ts.map +0 -1
  225. package/dist/read-side.js +0 -826
package/dist/reach.js CHANGED
@@ -1,10 +1,9 @@
1
1
  import { unheldView } from './conversation.js';
2
2
  import { modelTypes, NO_MODEL } from './model.js';
3
- import { applied, observing } from './observation.js';
3
+ import { changeOf, digestApplied, digestOf, observing, } from './observation.js';
4
4
  import { runtimeError } from './failure.js';
5
- import { failure, undeclared, } from './outcome.js';
5
+ import { failure, lockedRoom, ROOM_LOCKED, undeclared, UNREADABLE, } from './outcome.js';
6
6
  import { beneath } from './paths.js';
7
- import { reconciled } from './read-side.js';
8
7
  import { moveTarget, readParts, staleWrite, } from './room-draft.js';
9
8
  import { documentKey } from './rows.js';
10
9
  import { undeclaredSearch } from './search.js';
@@ -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,33 +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
- if (scope.kind === 'conversations')
63
- return reach.conversations;
64
- return scope.path === undefined
65
- ? wholly(reach, scope.locator)
66
- : covers(reach, scope.locator, scope.path);
67
- }
68
- function unreachedReference(fileRef) {
69
- return { kind: 'absent', code: 'binary-file-absent', fields: { fileRef }, retryable: false };
70
- }
71
70
  export function planReach(reach) {
72
71
  return reach === null
73
72
  ? null
@@ -76,6 +75,9 @@ export function planReach(reach) {
76
75
  documents: [
77
76
  ...new Set(reach.documents.map(({ room, path }) => documentKey(room, path))),
78
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),
79
81
  };
80
82
  }
81
83
  function roomsWithin(reach, rooms) {
@@ -91,7 +93,7 @@ function typesWithin(reach, room, types) {
91
93
  };
92
94
  }
93
95
  function moves(reach, room, move) {
94
- return move === undefined || covers(reach, room, moveTarget(move));
96
+ return move === undefined || covers(reach, move.room ?? room, moveTarget(move));
95
97
  }
96
98
  function draftWithin(reach, draft) {
97
99
  return covers(reach, draft.room, draft.path) && moves(reach, draft.room, draft.parts.move);
@@ -128,29 +130,61 @@ function statusWithin(reach, status) {
128
130
  };
129
131
  }
130
132
  function queueWithin(reach, room, entries) {
131
- return entries.filter(({ batch }) => batch.changes.every((change) => covers(reach, room, change.path) &&
132
- (change.kind !== 'move' || covers(reach, room, change.to))));
133
+ return entries
134
+ .filter(({ batch }) => batch.changes.every((change) => covers(reach, room, change.path) &&
135
+ (change.kind !== 'move' || covers(reach, room, change.to))))
136
+ .map((entry) => {
137
+ const { between, ...batch } = entry.batch;
138
+ if (between === undefined)
139
+ return entry;
140
+ return wholly(reach, between.source.room) && wholly(reach, between.destination.room)
141
+ ? entry
142
+ : { ...entry, batch };
143
+ });
133
144
  }
134
145
  function unreached(room) {
135
146
  return runtimeError('room-not-held', `No Local Replica for ${room}`);
136
147
  }
148
+ function lockedError(room) {
149
+ return runtimeError(ROOM_LOCKED, `${room} is locked until House confirms its access`, true);
150
+ }
151
+ function deviceUnreached() {
152
+ return runtimeError('device-unreached', 'Only the panel cleans up this device');
153
+ }
154
+ const ATTACH_REQUIRED = 'attach-required';
155
+ function attachRequired() {
156
+ return runtimeError(ATTACH_REQUIRED, 'App code takes a file in with binaryFile.attach');
157
+ }
158
+ function carriesFile(parts) {
159
+ return parts !== null && typeof parts === 'object' && Object.hasOwn(parts, 'file');
160
+ }
137
161
  export function narrowed(runtime, given, told) {
138
162
  const { md, watch } = runtime;
139
163
  let reach = given;
140
164
  let port = told;
141
165
  const open = new Set();
142
- function following(begin) {
166
+ function following(begin, locking = false) {
143
167
  let stop = begin();
144
168
  const restart = () => {
145
169
  stop();
146
170
  stop = begin();
147
171
  };
148
172
  open.add(restart);
173
+ const unwatch = locking ? runtime.watchLocks(restart) : () => { };
149
174
  return () => {
150
175
  open.delete(restart);
176
+ unwatch();
151
177
  stop();
152
178
  };
153
179
  }
180
+ const unlocking = (rooms) => {
181
+ const locked = (rooms ?? []).filter((room) => runtime.locked(room));
182
+ return locked.length === 0
183
+ ? null
184
+ : { pending: locked.map((room) => ({ room, awaits: 'unlock' })) };
185
+ };
186
+ const unlocked = (entries) => entries.filter((entry) => !runtime.locked(entry.room));
187
+ const intoLocked = (held) => held.some((move) => move?.room !== undefined && runtime.locked(move.room));
154
188
  const within = (topic, input, deliver) => {
155
189
  if (topic === 'rooms') {
156
190
  return following(() => watch(topic, input, (rooms) => deliver(roomsWithin(reach, rooms))));
@@ -159,45 +193,60 @@ export function narrowed(runtime, given, told) {
159
193
  return following(() => runtime.watchReadiness(port, reach, deliver));
160
194
  }
161
195
  if (topic === 'sync-status') {
162
- return following(() => watch(topic, input, (status) => deliver(statusWithin(reach, status))));
196
+ return following(() => watch(topic, input, (status) => {
197
+ const within = statusWithin(reach, status);
198
+ deliver({ ...within, attentionRequired: unlocked(within.attentionRequired) });
199
+ }), true);
163
200
  }
164
201
  if (topic === 'room-drafts') {
165
- return following(() => watch(topic, input, (drafts) => deliver(draftsWithin(reach, drafts))));
202
+ return following(() => watch(topic, input, (drafts) => deliver(unlocked(draftsWithin(reach, drafts)))), true);
166
203
  }
167
204
  if (topic === 'queue') {
168
205
  const room = input[0];
169
206
  return following(() => {
170
- if (!holds(reach, room)) {
207
+ if (!holds(reach, room) || runtime.locked(room)) {
171
208
  deliver([]);
172
209
  return () => { };
173
210
  }
174
211
  return watch(topic, input, (entries) => deliver(queueWithin(reach, room, entries)));
175
- });
212
+ }, true);
176
213
  }
177
214
  if (topic === 'query') {
178
215
  const plan = runtime.plan(input[0], reach);
179
216
  let held = null;
180
217
  return following(() => {
218
+ const locked = unlocking(plan.rooms);
219
+ if (locked !== null) {
220
+ const answer = { result: locked, keys: [] };
221
+ if (held === null || changeOf(held, answer) !== null)
222
+ deliver(answer);
223
+ held = digestOf(answer);
224
+ return () => { };
225
+ }
181
226
  let first = true;
182
- return runtime.watchPlan({ ...plan, reach: planReach(reach) }, (message) => {
227
+ let open = true;
228
+ const heard = (message) => {
183
229
  if (!first) {
184
- held = applied(held, message);
230
+ held = digestApplied(held, message);
185
231
  deliver(message);
186
232
  return;
187
233
  }
188
234
  first = false;
189
- if (held === null) {
190
- held = message;
191
- deliver(message);
192
- return;
193
- }
194
- const next = reconciled(held, message);
195
- if (next === null)
196
- return;
197
- held = next.keyed;
198
- deliver(next.message);
235
+ const change = held === null ? message : changeOf(held, message);
236
+ held = digestOf(message);
237
+ if (change !== null)
238
+ deliver(change);
239
+ };
240
+ const current = { ...plan, reach: planReach(reach), locked: runtime.lockedRooms() };
241
+ const stop = runtime.watchPlan(current, (message) => {
242
+ if (open)
243
+ heard(message);
199
244
  });
200
- });
245
+ return () => {
246
+ open = false;
247
+ stop();
248
+ };
249
+ }, true);
201
250
  }
202
251
  if (topic === 'conversation') {
203
252
  return following(() => {
@@ -217,16 +266,32 @@ export function narrowed(runtime, given, told) {
217
266
  }
218
267
  return watch(topic, input, deliver);
219
268
  };
269
+ const files = new Map();
270
+ let handed = 0;
271
+ async function hand(reading) {
272
+ const answer = await reading;
273
+ if (answer.kind !== 'binary')
274
+ return answer;
275
+ handed += 1;
276
+ const file = String(handed);
277
+ files.set(file, answer.file);
278
+ return { ...answer, file };
279
+ }
220
280
  const conversation = () => (conversing(reach) ? md.conversation : NO_CONVERSATION);
221
281
  const chatDraft = () => (conversing(reach) ? md.chatDraft : NO_CHAT_DRAFT);
222
282
  const view = {
223
283
  ...md,
224
284
  rooms: () => roomsWithin(reach, md.rooms()),
225
- query: ((input) => runtime.query(runtime.plan(input, reach))),
285
+ query: ((input) => {
286
+ const plan = runtime.plan(input, reach);
287
+ return Promise.resolve(unlocking(plan.rooms) ?? runtime.query({ ...plan, locked: runtime.lockedRooms() }));
288
+ }),
226
289
  search: (input) => port.search === 'required'
227
- ? runtime.search(input, reach)
290
+ ? runtime.search(input, reach, runtime.lockedRooms())
228
291
  : Promise.resolve(undeclaredSearch()),
229
292
  types(room) {
293
+ if (holds(reach, room) && runtime.locked(room))
294
+ throw lockedError(room);
230
295
  if (wholly(reach, room))
231
296
  return md.types(room);
232
297
  if (!holds(reach, room))
@@ -237,50 +302,114 @@ export function narrowed(runtime, given, told) {
237
302
  async save(room, roomDrafts, writtenBy) {
238
303
  if (!holds(reach, room))
239
304
  throw unreached(room);
240
- const outside = roomDrafts.find(({ path }) => !covers(reach, room, path) ||
241
- !moves(reach, room, md.roomDraft.read(room, path)?.parts.move));
305
+ if (runtime.locked(room))
306
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
307
+ const held = (await Promise.all(roomDrafts.map(({ path }) => md.roomDraft.read(room, path)))).map((draft) => draft?.parts.move);
308
+ const outside = roomDrafts.find(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]));
242
309
  if (outside !== undefined) {
243
310
  return { outcome: 'refused', code: 'stale', retryable: false, file: outside.path };
244
311
  }
312
+ if (intoLocked(held))
313
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
245
314
  return savedWithin(reach, room, await md.save(room, roomDrafts, writtenBy));
246
315
  },
247
316
  async saveParts(room, parts, writtenBy) {
248
317
  if (!holds(reach, room))
249
318
  throw unreached(room);
250
- if (parts.some(({ path, parts: one }) => !covers(reach, room, path) || !moves(reach, room, readParts(one).move))) {
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
+ }
323
+ if (runtime.locked(room))
324
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
325
+ const held = parts.map(({ parts: one }) => readParts(one).move);
326
+ if (parts.some(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]))) {
251
327
  throw unreached(room);
252
328
  }
329
+ if (intoLocked(held))
330
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
253
331
  return savedWithin(reach, room, await md.saveParts(room, parts, writtenBy));
254
332
  },
255
- history: (room, path, query) => covers(reach, room, path)
256
- ? md.history(room, path, query)
257
- : Promise.resolve(failure({ kind: 'room-not-readable', locator: room })),
333
+ resolve(room, path, destination) {
334
+ const at = runtime.located(room, path, destination);
335
+ return at !== null && !covers(reach, at.room, at.path)
336
+ ? Promise.resolve(UNREADABLE)
337
+ : md.resolve(room, path, destination);
338
+ },
339
+ history: (room, path, query) => !covers(reach, room, path)
340
+ ? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
341
+ : runtime.locked(room)
342
+ ? Promise.resolve(lockedRoom(room))
343
+ : md.history(room, path, query),
258
344
  binaryFile: {
259
- read: (room, path, revision) => covers(reach, room, path)
260
- ? md.binaryFile.read(room, path, revision)
261
- : Promise.resolve(failure({ kind: 'room-not-readable', locator: room })),
262
- link: (room, path, revision) => covers(reach, room, path)
263
- ? md.binaryFile.link(room, path, revision)
264
- : Promise.resolve(failure({ kind: 'room-not-readable', locator: room })),
265
- readReference: (reference) => refers(reach, runtime.referrerScope(reference.referrer))
266
- ? md.binaryFile.readReference(reference)
267
- : Promise.resolve(unreachedReference(reference.fileRef)),
345
+ read: (room, path, revision) => !covers(reach, room, path)
346
+ ? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
347
+ : runtime.locked(room)
348
+ ? Promise.resolve(lockedRoom(room))
349
+ : hand(md.binaryFile.read(room, path, revision)),
350
+ link: (room, path, revision) => !covers(reach, room, path)
351
+ ? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
352
+ : runtime.locked(room)
353
+ ? Promise.resolve(lockedRoom(room))
354
+ : md.binaryFile.link(room, path, revision),
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),
365
+ async part(file, part) {
366
+ const key = files.get(file);
367
+ if (key === undefined)
368
+ return null;
369
+ const bytes = await md.binaryFile.part(key, part);
370
+ if (bytes === null)
371
+ files.delete(file);
372
+ return bytes;
373
+ },
268
374
  },
269
- reached: (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
270
- md.reached(room, roomVersion, path),
375
+ reached: async (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
376
+ !runtime.locked(room) &&
377
+ (await md.reached(room, roomVersion, path)),
271
378
  log: () => (reach === null ? md.log() : ''),
379
+ cleanUp: () => (reach === null ? md.cleanUp() : Promise.reject(deviceUnreached())),
272
380
  roomDraft: {
273
- list: () => md.roomDraft.list().then((drafts) => draftsWithin(reach, drafts)),
274
- read: (room, path) => covers(reach, room, path) ? shownDraft(reach, md.roomDraft.read(room, path)) : null,
275
- async write(room, path, revision, parts) {
276
- if (!covers(reach, room, path) || !moves(reach, room, readParts(parts).move)) {
277
- throw unreached(room);
381
+ list: () => md.roomDraft.list().then((drafts) => unlocked(draftsWithin(reach, drafts))),
382
+ async read(room, path) {
383
+ if (!covers(reach, room, path))
384
+ return null;
385
+ if (runtime.locked(room))
386
+ throw lockedError(room);
387
+ return shownDraft(reach, await md.roomDraft.read(room, path));
388
+ },
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);
278
403
  }
279
- return writeWithin(reach, await md.roomDraft.write(room, path, revision, parts));
404
+ return md.roomDraft
405
+ .write(room, path, revision, parts, next)
406
+ .then((written) => writeWithin(reach, written));
280
407
  },
281
408
  async discard(room, path, revision) {
282
409
  if (!covers(reach, room, path))
283
410
  return staleWrite(null);
411
+ if (runtime.locked(room))
412
+ throw lockedError(room);
284
413
  return writeWithin(reach, await md.roomDraft.discard(room, path, revision));
285
414
  },
286
415
  },
@@ -1,11 +1,11 @@
1
1
  import type { Open } from './open.js';
2
2
  export type CodeAvailability = Open<'stored' | 'absent'>;
3
- export type RoomPreparation = Open<'complete' | 'acquiring' | 'preparing' | 'indexing' | 'refused' | 'unadmitted'>;
3
+ export type RoomPreparation = Open<'complete' | 'acquiring' | 'preparing' | 'refused' | 'unadmitted'>;
4
4
  export type RoomCoverage = {
5
5
  readonly room: string;
6
6
  readonly state: RoomPreparation;
7
7
  };
8
- export type ConversationCoverage = Open<'complete' | 'acquiring' | 'indexing' | 'undeclared'>;
8
+ export type ConversationCoverage = Open<'complete' | 'acquiring' | 'undeclared'>;
9
9
  export type SearchObligation = Open<'required' | 'unused'>;
10
10
  export type TargetCoverage = {
11
11
  readonly complete: boolean;
@@ -18,17 +18,28 @@ 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' | 'quota-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<'listing' | '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
+ readonly received: InstallationAmount;
42
+ };
32
43
  export type ReadinessStatus = Open<'preparing' | 'paused' | 'refused' | 'ready' | 'lost'>;
33
44
  export type Readiness = {
34
45
  readonly status: ReadinessStatus;
@@ -40,7 +51,8 @@ export type Readiness = {
40
51
  readonly persistence: Persistence;
41
52
  readonly connection: ConnectionAvailability;
42
53
  readonly house: HouseOutcome;
43
- readonly capacity: CapacityCause | null;
54
+ readonly space: Space | null;
55
+ readonly installation: Installation;
44
56
  readonly refused: readonly RefusedRoom[];
45
57
  readonly lost: boolean;
46
58
  };
@@ -48,6 +60,5 @@ export type ReadinessFacts = Omit<Readiness, 'status' | 'ready' | 'usable' | 'du
48
60
  readonly coverage: Omit<TargetCoverage, 'complete'>;
49
61
  readonly established: boolean;
50
62
  };
51
- export declare const SETTLED_ROOMS: ReadonlySet<string>;
52
63
  export declare function readinessOf(facts: ReadinessFacts): Readiness;
53
64
  //# 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,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;AAkCF,wBAAgB,SAAS,CACvB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,EACzC,UAAU,EAAE,MAAM,MAAM,GACvB,SAAS,CA4FX"}
package/dist/reads.js CHANGED
@@ -5,7 +5,7 @@ function declaredAs(declaration) {
5
5
  return declared;
6
6
  }
7
7
  function sameHeld(one, other) {
8
- return one?.documents === other?.documents && one?.revisions === other?.revisions;
8
+ return one === other;
9
9
  }
10
10
  function failed(answer) {
11
11
  return answer?.kind === 'transport-uncertainty';
@@ -20,7 +20,7 @@ export function doorReads(adapter, declaration, generation) {
20
20
  let carrying = false;
21
21
  function joined(read, authorization, request, ask) {
22
22
  const key = `${read} ${request.locator} ${request.pageToken ?? ''}`;
23
- const { held, ...named } = request;
23
+ const { held, received, ...named } = request;
24
24
  const asked = JSON.stringify([declaredAs(declaration(request.locator)), named]);
25
25
  const asking = generation();
26
26
  const current = reading.get(key);
@@ -28,6 +28,7 @@ export function doorReads(adapter, declaration, generation) {
28
28
  current.authorization === authorization &&
29
29
  current.asked === asked &&
30
30
  sameHeld(current.held, held) &&
31
+ current.received === received &&
31
32
  (!current.settled || current.holder < asking)) {
32
33
  if (current.settled && !current.continued)
33
34
  reading.delete(key);
@@ -49,6 +50,7 @@ export function doorReads(adapter, declaration, generation) {
49
50
  authorization,
50
51
  asked,
51
52
  held,
53
+ received,
52
54
  answer,
53
55
  from: asking,
54
56
  holder: asking,
@@ -8,7 +8,7 @@ export type AttemptOptions = {
8
8
  };
9
9
  export type RecoveryOptions = {
10
10
  readonly firstMs?: number;
11
- readonly ceilingMs?: number;
11
+ readonly maxMs?: number;
12
12
  readonly attempts?: number;
13
13
  readonly inFlight?: number;
14
14
  };
@@ -20,6 +20,6 @@ export type Recovery = {
20
20
  scope(inFlight?: number): Recovery;
21
21
  retire(): Promise<void>;
22
22
  };
23
- export declare function retryDelay(tries: number, firstMs?: number, ceilingMs?: number): number;
23
+ export declare function retryDelay(tries: number, firstMs?: number, maxMs?: number): number;
24
24
  export declare function createRecovery(options?: RecoveryOptions): Recovery;
25
25
  //# 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,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,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,SAAS,SAAa,GAAG,MAAM,CAG5F;AAuKD,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;AAwKD,wBAAgB,cAAc,CAAC,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAStE"}
package/dist/recovery.js CHANGED
@@ -1,11 +1,11 @@
1
1
  // A first retry waits about a second, so a passing failure clears before the next attempt.
2
2
  const FIRST_MS = 1_000;
3
3
  // Waits stop doubling at half a minute, so work resumes soon after a long failure ends.
4
- const CEILING_MS = 30_000;
4
+ const MAX_MS = 30_000;
5
5
  const ATTEMPTS = 8;
6
- export function retryDelay(tries, firstMs = FIRST_MS, ceilingMs = CEILING_MS) {
7
- const ceiling = Math.min(ceilingMs, firstMs * 2 ** tries);
8
- return ceiling / 2 + (Math.random() * ceiling) / 2;
6
+ export function retryDelay(tries, firstMs = FIRST_MS, maxMs = MAX_MS) {
7
+ const longest = Math.min(maxMs, firstMs * 2 ** tries);
8
+ return longest / 2 + (Math.random() * longest) / 2;
9
9
  }
10
10
  function owner(backoff, inFlight, release = () => { }) {
11
11
  const intents = new Map();
@@ -84,7 +84,8 @@ function owner(backoff, inFlight, release = () => { }) {
84
84
  return;
85
85
  }
86
86
  if (result === 'again') {
87
- const delay = retryDelay(intent.tries - 1, backoff.firstMs, backoff.ceilingMs);
87
+ // The next attempt waits the doubling backoff, up to its maximum.
88
+ const delay = retryDelay(intent.tries - 1, backoff.firstMs, backoff.maxMs);
88
89
  wait(key, intent, Date.now() + delay, false);
89
90
  }
90
91
  else
@@ -135,7 +136,7 @@ function owner(backoff, inFlight, release = () => { }) {
135
136
  wait(key, intent, options.at, true);
136
137
  else if (options.again === true) {
137
138
  intent.tries = 1;
138
- wait(key, intent, Date.now() + retryDelay(0, backoff.firstMs, backoff.ceilingMs), false);
139
+ wait(key, intent, Date.now() + retryDelay(0, backoff.firstMs, backoff.maxMs), false);
139
140
  }
140
141
  else
141
142
  launch(key, intent);
@@ -191,7 +192,7 @@ function owner(backoff, inFlight, release = () => { }) {
191
192
  export function createRecovery(options = {}) {
192
193
  return owner({
193
194
  firstMs: options.firstMs ?? FIRST_MS,
194
- ceilingMs: options.ceilingMs ?? CEILING_MS,
195
+ maxMs: options.maxMs ?? MAX_MS,
195
196
  attempts: options.attempts ?? ATTEMPTS,
196
197
  }, options.inFlight ?? Infinity);
197
198
  }