@agentshouse/mdruntime 0.1.0-c5d3fa6fb67bc → 0.1.0-c63ad08fad0c3

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 (211) hide show
  1. package/AGENTS.md +240 -220
  2. package/README.md +9 -8
  3. package/dist/adapter.d.ts +72 -24
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/attached-model.d.ts +4 -1
  6. package/dist/attached-model.d.ts.map +1 -1
  7. package/dist/attached-model.js +13 -3
  8. package/dist/bootstrap.d.ts +26 -7
  9. package/dist/bootstrap.d.ts.map +1 -1
  10. package/dist/bootstrap.js +167 -82
  11. package/dist/chain.d.ts +11 -0
  12. package/dist/chain.d.ts.map +1 -0
  13. package/dist/chain.js +64 -0
  14. package/dist/change-set.d.ts +9 -16
  15. package/dist/change-set.d.ts.map +1 -1
  16. package/dist/change-set.js +11 -89
  17. package/dist/change.d.ts +31 -1
  18. package/dist/change.d.ts.map +1 -1
  19. package/dist/change.js +10 -1
  20. package/dist/chat/earlier.d.ts +10 -0
  21. package/dist/chat/earlier.d.ts.map +1 -0
  22. package/dist/chat/earlier.js +54 -0
  23. package/dist/chat/house.d.ts +25 -0
  24. package/dist/chat/house.d.ts.map +1 -0
  25. package/dist/chat/house.js +38 -0
  26. package/dist/chat/input.d.ts +3 -1
  27. package/dist/chat/input.d.ts.map +1 -1
  28. package/dist/chat/input.js +11 -18
  29. package/dist/chat/kit.js +1 -1
  30. package/dist/chat/list.d.ts +2 -1
  31. package/dist/chat/list.d.ts.map +1 -1
  32. package/dist/chat/list.js +45 -5
  33. package/dist/chat/markdown.d.ts +1 -0
  34. package/dist/chat/markdown.d.ts.map +1 -1
  35. package/dist/chat/markdown.js +78 -20
  36. package/dist/chat/message.d.ts +1 -0
  37. package/dist/chat/message.d.ts.map +1 -1
  38. package/dist/chat/message.js +73 -11
  39. package/dist/chat/messages.d.ts +14 -1
  40. package/dist/chat/messages.d.ts.map +1 -1
  41. package/dist/chat/messages.js +79 -24
  42. package/dist/chat/name.d.ts +1 -0
  43. package/dist/chat/name.d.ts.map +1 -1
  44. package/dist/chat/name.js +1 -1
  45. package/dist/chat/opened.d.ts +1 -0
  46. package/dist/chat/opened.d.ts.map +1 -1
  47. package/dist/chat/opened.js +2 -0
  48. package/dist/chat/overlay.d.ts +1 -0
  49. package/dist/chat/overlay.d.ts.map +1 -1
  50. package/dist/chat/overlay.js +11 -5
  51. package/dist/chat/parts.d.ts +1 -0
  52. package/dist/chat/parts.d.ts.map +1 -1
  53. package/dist/chat/parts.js +3 -2
  54. package/dist/chat/pieces.d.ts +62 -0
  55. package/dist/chat/pieces.d.ts.map +1 -0
  56. package/dist/chat/pieces.js +1110 -0
  57. package/dist/chat/provider.d.ts +8 -1
  58. package/dist/chat/provider.d.ts.map +1 -1
  59. package/dist/chat/provider.js +98 -92
  60. package/dist/chat/question.d.ts +1 -1
  61. package/dist/chat/question.d.ts.map +1 -1
  62. package/dist/chat/question.js +7 -18
  63. package/dist/chat/ready.d.ts +5 -2
  64. package/dist/chat/ready.d.ts.map +1 -1
  65. package/dist/chat/ready.js +7 -5
  66. package/dist/chat/room-file.d.ts +8 -0
  67. package/dist/chat/room-file.d.ts.map +1 -0
  68. package/dist/chat/room-file.js +72 -0
  69. package/dist/chat/steady.d.ts +3 -0
  70. package/dist/chat/steady.d.ts.map +1 -0
  71. package/dist/chat/steady.js +26 -0
  72. package/dist/chat/style.d.ts.map +1 -1
  73. package/dist/chat/style.js +6 -1
  74. package/dist/chat.d.ts +3 -2
  75. package/dist/chat.d.ts.map +1 -1
  76. package/dist/chat.js +2 -2
  77. package/dist/client.d.ts +11 -2
  78. package/dist/client.d.ts.map +1 -1
  79. package/dist/client.js +45 -7
  80. package/dist/collection.d.ts +6 -19
  81. package/dist/collection.d.ts.map +1 -1
  82. package/dist/collection.js +30 -287
  83. package/dist/compile.d.ts +16 -0
  84. package/dist/compile.d.ts.map +1 -0
  85. package/dist/compile.js +721 -0
  86. package/dist/connection.d.ts +22 -8
  87. package/dist/connection.d.ts.map +1 -1
  88. package/dist/connection.js +2509 -830
  89. package/dist/conversation.d.ts +15 -3
  90. package/dist/conversation.d.ts.map +1 -1
  91. package/dist/conversation.js +238 -94
  92. package/dist/digest.d.ts +7 -0
  93. package/dist/digest.d.ts.map +1 -0
  94. package/dist/digest.js +113 -0
  95. package/dist/durability.d.ts +3 -1
  96. package/dist/durability.d.ts.map +1 -1
  97. package/dist/entry.d.ts +3 -1
  98. package/dist/entry.d.ts.map +1 -1
  99. package/dist/entry.js +18 -23
  100. package/dist/file.d.ts +2 -10
  101. package/dist/file.d.ts.map +1 -1
  102. package/dist/file.js +3 -120
  103. package/dist/fulltext.d.ts +27 -0
  104. package/dist/fulltext.d.ts.map +1 -0
  105. package/dist/fulltext.js +368 -0
  106. package/dist/host.d.ts +5 -4
  107. package/dist/host.d.ts.map +1 -1
  108. package/dist/host.js +57 -7
  109. package/dist/identity.d.ts +0 -1
  110. package/dist/identity.d.ts.map +1 -1
  111. package/dist/identity.js +0 -3
  112. package/dist/index.d.ts +12 -8
  113. package/dist/index.d.ts.map +1 -1
  114. package/dist/index.js +4 -0
  115. package/dist/live.d.ts +22 -0
  116. package/dist/live.d.ts.map +1 -0
  117. package/dist/live.js +123 -0
  118. package/dist/memory.d.ts +7 -3
  119. package/dist/memory.d.ts.map +1 -1
  120. package/dist/memory.js +39 -17
  121. package/dist/messages.d.ts +28 -0
  122. package/dist/messages.d.ts.map +1 -0
  123. package/dist/messages.js +90 -0
  124. package/dist/name.d.ts +4 -0
  125. package/dist/name.d.ts.map +1 -0
  126. package/dist/name.js +122 -0
  127. package/dist/observation.d.ts +14 -0
  128. package/dist/observation.d.ts.map +1 -1
  129. package/dist/observation.js +93 -3
  130. package/dist/opened.d.ts +22 -0
  131. package/dist/opened.d.ts.map +1 -0
  132. package/dist/opened.js +107 -0
  133. package/dist/outcome.d.ts +35 -4
  134. package/dist/outcome.d.ts.map +1 -1
  135. package/dist/outcome.js +28 -0
  136. package/dist/overlay.d.ts +2 -5
  137. package/dist/overlay.d.ts.map +1 -1
  138. package/dist/overlay.js +86 -171
  139. package/dist/query.d.ts +29 -2
  140. package/dist/query.d.ts.map +1 -1
  141. package/dist/query.js +46 -7
  142. package/dist/reach.d.ts +5 -1
  143. package/dist/reach.d.ts.map +1 -1
  144. package/dist/reach.js +167 -48
  145. package/dist/react.d.ts +3 -3
  146. package/dist/react.d.ts.map +1 -1
  147. package/dist/react.js +7 -17
  148. package/dist/readiness.d.ts +18 -3
  149. package/dist/readiness.d.ts.map +1 -1
  150. package/dist/readiness.js +1 -1
  151. package/dist/reads.d.ts +11 -0
  152. package/dist/reads.d.ts.map +1 -0
  153. package/dist/reads.js +100 -0
  154. package/dist/recovery.d.ts +2 -2
  155. package/dist/recovery.d.ts.map +1 -1
  156. package/dist/recovery.js +8 -7
  157. package/dist/refresh.d.ts +13 -15
  158. package/dist/refresh.d.ts.map +1 -1
  159. package/dist/refresh.js +78 -51
  160. package/dist/replica.d.ts +57 -33
  161. package/dist/replica.d.ts.map +1 -1
  162. package/dist/replica.js +295 -186
  163. package/dist/room-draft.d.ts +15 -1
  164. package/dist/room-draft.d.ts.map +1 -1
  165. package/dist/room-draft.js +32 -25
  166. package/dist/rows.d.ts +29 -30
  167. package/dist/rows.d.ts.map +1 -1
  168. package/dist/rows.js +113 -64
  169. package/dist/save.d.ts +51 -14
  170. package/dist/save.d.ts.map +1 -1
  171. package/dist/save.js +518 -180
  172. package/dist/search.d.ts +25 -42
  173. package/dist/search.d.ts.map +1 -1
  174. package/dist/search.js +30 -169
  175. package/dist/seed.d.ts +16 -0
  176. package/dist/seed.d.ts.map +1 -0
  177. package/dist/seed.js +75 -0
  178. package/dist/shared.d.ts +8 -3
  179. package/dist/shared.d.ts.map +1 -1
  180. package/dist/shared.js +129 -66
  181. package/dist/store.d.ts +97 -88
  182. package/dist/store.d.ts.map +1 -1
  183. package/dist/store.js +335 -659
  184. package/dist/stored.d.ts +145 -0
  185. package/dist/stored.d.ts.map +1 -0
  186. package/dist/stored.js +567 -0
  187. package/dist/tables.d.ts +342 -0
  188. package/dist/tables.d.ts.map +1 -0
  189. package/dist/tables.js +576 -0
  190. package/dist/turn.d.ts +5 -3
  191. package/dist/turn.d.ts.map +1 -1
  192. package/dist/turn.js +51 -21
  193. package/dist/validation.d.ts +30 -0
  194. package/dist/validation.d.ts.map +1 -0
  195. package/dist/validation.js +162 -0
  196. package/dist/windows.d.ts +22 -0
  197. package/dist/windows.d.ts.map +1 -0
  198. package/dist/windows.js +89 -0
  199. package/dist/wire.d.ts +32 -0
  200. package/dist/wire.d.ts.map +1 -1
  201. package/dist/wire.js +8 -0
  202. package/dist/words.d.ts +19 -0
  203. package/dist/words.d.ts.map +1 -0
  204. package/dist/words.js +150 -0
  205. package/package.json +10 -4
  206. package/dist/acquisition.d.ts +0 -14
  207. package/dist/acquisition.d.ts.map +0 -1
  208. package/dist/acquisition.js +0 -24
  209. package/dist/read-side.d.ts +0 -25
  210. package/dist/read-side.d.ts.map +0 -1
  211. package/dist/read-side.js +0 -642
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 { absentReference, 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';
@@ -17,6 +16,7 @@ const NO_CONVERSATION = {
17
16
  read: (conversation) => Promise.resolve(unheldView(conversation)),
18
17
  create: unconversed('conversation.create'),
19
18
  send: unconversed('conversation.send'),
19
+ attach: unconversed('conversation.attach'),
20
20
  answer: unconversed('conversation.answer'),
21
21
  interrupt: unconversed('conversation.interrupt'),
22
22
  kill: unconversed('conversation.kill'),
@@ -25,6 +25,7 @@ const NO_CONVERSATION = {
25
25
  };
26
26
  const NO_CHAT_DRAFT = {
27
27
  write: () => Promise.resolve(),
28
+ prepend: () => Promise.resolve(),
28
29
  discard: () => Promise.resolve(),
29
30
  };
30
31
  export function holds(reach, room) {
@@ -58,15 +59,10 @@ function refers(reach, scope) {
58
59
  return true;
59
60
  if (scope === null)
60
61
  return false;
61
- if (scope.kind === 'conversations')
62
- return reach.conversations;
63
62
  return scope.path === undefined
64
63
  ? wholly(reach, scope.locator)
65
64
  : covers(reach, scope.locator, scope.path);
66
65
  }
67
- function unreachedReference(fileRef) {
68
- return { kind: 'absent', code: 'binary-file-absent', fields: { fileRef }, retryable: false };
69
- }
70
66
  export function planReach(reach) {
71
67
  return reach === null
72
68
  ? null
@@ -90,7 +86,7 @@ function typesWithin(reach, room, types) {
90
86
  };
91
87
  }
92
88
  function moves(reach, room, move) {
93
- return move === undefined || covers(reach, room, moveTarget(move));
89
+ return move === undefined || covers(reach, move.room ?? room, moveTarget(move));
94
90
  }
95
91
  function draftWithin(reach, draft) {
96
92
  return covers(reach, draft.room, draft.path) && moves(reach, draft.room, draft.parts.move);
@@ -127,29 +123,54 @@ function statusWithin(reach, status) {
127
123
  };
128
124
  }
129
125
  function queueWithin(reach, room, entries) {
130
- return entries.filter(({ batch }) => batch.changes.every((change) => covers(reach, room, change.path) &&
131
- (change.kind !== 'move' || covers(reach, room, change.to))));
126
+ return entries
127
+ .filter(({ batch }) => batch.changes.every((change) => covers(reach, room, change.path) &&
128
+ (change.kind !== 'move' || covers(reach, room, change.to))))
129
+ .map((entry) => {
130
+ const { between, ...batch } = entry.batch;
131
+ if (between === undefined)
132
+ return entry;
133
+ return wholly(reach, between.source.room) && wholly(reach, between.destination.room)
134
+ ? entry
135
+ : { ...entry, batch };
136
+ });
132
137
  }
133
138
  function unreached(room) {
134
139
  return runtimeError('room-not-held', `No Local Replica for ${room}`);
135
140
  }
141
+ function lockedError(room) {
142
+ return runtimeError(ROOM_LOCKED, `${room} is locked until House confirms its access`, true);
143
+ }
144
+ function deviceUnreached() {
145
+ return runtimeError('device-unreached', 'Only the panel cleans up this device');
146
+ }
136
147
  export function narrowed(runtime, given, told) {
137
148
  const { md, watch } = runtime;
138
149
  let reach = given;
139
150
  let port = told;
140
151
  const open = new Set();
141
- function following(begin) {
152
+ function following(begin, locking = false) {
142
153
  let stop = begin();
143
154
  const restart = () => {
144
155
  stop();
145
156
  stop = begin();
146
157
  };
147
158
  open.add(restart);
159
+ const unwatch = locking ? runtime.watchLocks(restart) : () => { };
148
160
  return () => {
149
161
  open.delete(restart);
162
+ unwatch();
150
163
  stop();
151
164
  };
152
165
  }
166
+ const unlocking = (rooms) => {
167
+ const locked = (rooms ?? []).filter((room) => runtime.locked(room));
168
+ return locked.length === 0
169
+ ? null
170
+ : { pending: locked.map((room) => ({ room, awaits: 'unlock' })) };
171
+ };
172
+ const unlocked = (entries) => entries.filter((entry) => !runtime.locked(entry.room));
173
+ const intoLocked = (held) => held.some((move) => move?.room !== undefined && runtime.locked(move.room));
153
174
  const within = (topic, input, deliver) => {
154
175
  if (topic === 'rooms') {
155
176
  return following(() => watch(topic, input, (rooms) => deliver(roomsWithin(reach, rooms))));
@@ -158,45 +179,60 @@ export function narrowed(runtime, given, told) {
158
179
  return following(() => runtime.watchReadiness(port, reach, deliver));
159
180
  }
160
181
  if (topic === 'sync-status') {
161
- return following(() => watch(topic, input, (status) => deliver(statusWithin(reach, status))));
182
+ return following(() => watch(topic, input, (status) => {
183
+ const within = statusWithin(reach, status);
184
+ deliver({ ...within, attentionRequired: unlocked(within.attentionRequired) });
185
+ }), true);
162
186
  }
163
187
  if (topic === 'room-drafts') {
164
- return following(() => watch(topic, input, (drafts) => deliver(draftsWithin(reach, drafts))));
188
+ return following(() => watch(topic, input, (drafts) => deliver(unlocked(draftsWithin(reach, drafts)))), true);
165
189
  }
166
190
  if (topic === 'queue') {
167
191
  const room = input[0];
168
192
  return following(() => {
169
- if (!holds(reach, room)) {
193
+ if (!holds(reach, room) || runtime.locked(room)) {
170
194
  deliver([]);
171
195
  return () => { };
172
196
  }
173
197
  return watch(topic, input, (entries) => deliver(queueWithin(reach, room, entries)));
174
- });
198
+ }, true);
175
199
  }
176
200
  if (topic === 'query') {
177
201
  const plan = runtime.plan(input[0], reach);
178
202
  let held = null;
179
203
  return following(() => {
204
+ const locked = unlocking(plan.rooms);
205
+ if (locked !== null) {
206
+ const answer = { result: locked, keys: [] };
207
+ if (held === null || changeOf(held, answer) !== null)
208
+ deliver(answer);
209
+ held = digestOf(answer);
210
+ return () => { };
211
+ }
180
212
  let first = true;
181
- return runtime.watchPlan({ ...plan, reach: planReach(reach) }, (message) => {
213
+ let open = true;
214
+ const heard = (message) => {
182
215
  if (!first) {
183
- held = applied(held, message);
216
+ held = digestApplied(held, message);
184
217
  deliver(message);
185
218
  return;
186
219
  }
187
220
  first = false;
188
- if (held === null) {
189
- held = message;
190
- deliver(message);
191
- return;
192
- }
193
- const next = reconciled(held, message);
194
- if (next === null)
195
- return;
196
- held = next.keyed;
197
- deliver(next.message);
221
+ const change = held === null ? message : changeOf(held, message);
222
+ held = digestOf(message);
223
+ if (change !== null)
224
+ deliver(change);
225
+ };
226
+ const current = { ...plan, reach: planReach(reach), locked: runtime.lockedRooms() };
227
+ const stop = runtime.watchPlan(current, (message) => {
228
+ if (open)
229
+ heard(message);
198
230
  });
199
- });
231
+ return () => {
232
+ open = false;
233
+ stop();
234
+ };
235
+ }, true);
200
236
  }
201
237
  if (topic === 'conversation') {
202
238
  return following(() => {
@@ -216,16 +252,32 @@ export function narrowed(runtime, given, told) {
216
252
  }
217
253
  return watch(topic, input, deliver);
218
254
  };
255
+ const files = new Map();
256
+ let handed = 0;
257
+ const hand = async (reading) => {
258
+ const answer = await reading;
259
+ if (answer.kind !== 'binary')
260
+ return answer;
261
+ handed += 1;
262
+ const file = String(handed);
263
+ files.set(file, answer.file);
264
+ return { ...answer, file };
265
+ };
219
266
  const conversation = () => (conversing(reach) ? md.conversation : NO_CONVERSATION);
220
267
  const chatDraft = () => (conversing(reach) ? md.chatDraft : NO_CHAT_DRAFT);
221
268
  const view = {
222
269
  ...md,
223
270
  rooms: () => roomsWithin(reach, md.rooms()),
224
- query: ((input) => runtime.query(runtime.plan(input, reach))),
271
+ query: ((input) => {
272
+ const plan = runtime.plan(input, reach);
273
+ return Promise.resolve(unlocking(plan.rooms) ?? runtime.query({ ...plan, locked: runtime.lockedRooms() }));
274
+ }),
225
275
  search: (input) => port.search === 'required'
226
- ? runtime.search(input, reach)
276
+ ? runtime.search(input, reach, runtime.lockedRooms())
227
277
  : Promise.resolve(undeclaredSearch()),
228
278
  types(room) {
279
+ if (holds(reach, room) && runtime.locked(room))
280
+ throw lockedError(room);
229
281
  if (wholly(reach, room))
230
282
  return md.types(room);
231
283
  if (!holds(reach, room))
@@ -236,39 +288,100 @@ export function narrowed(runtime, given, told) {
236
288
  async save(room, roomDrafts, writtenBy) {
237
289
  if (!holds(reach, room))
238
290
  throw unreached(room);
239
- const outside = roomDrafts.find(({ path }) => !covers(reach, room, path) ||
240
- !moves(reach, room, md.roomDraft.read(room, path)?.parts.move));
291
+ if (runtime.locked(room))
292
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
293
+ const held = (await Promise.all(roomDrafts.map(({ path }) => md.roomDraft.read(room, path)))).map((draft) => draft?.parts.move);
294
+ const outside = roomDrafts.find(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]));
241
295
  if (outside !== undefined) {
242
296
  return { outcome: 'refused', code: 'stale', retryable: false, file: outside.path };
243
297
  }
298
+ if (intoLocked(held))
299
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
244
300
  return savedWithin(reach, room, await md.save(room, roomDrafts, writtenBy));
245
301
  },
246
- history: (room, path, query) => covers(reach, room, path)
247
- ? md.history(room, path, query)
248
- : Promise.resolve(failure({ kind: 'room-not-readable', locator: room })),
302
+ async saveParts(room, parts, writtenBy) {
303
+ if (!holds(reach, room))
304
+ throw unreached(room);
305
+ if (runtime.locked(room))
306
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
307
+ const held = parts.map(({ parts: one }) => readParts(one).move);
308
+ if (parts.some(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]))) {
309
+ throw unreached(room);
310
+ }
311
+ if (intoLocked(held))
312
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
313
+ return savedWithin(reach, room, await md.saveParts(room, parts, writtenBy));
314
+ },
315
+ resolve(room, path, destination) {
316
+ const at = runtime.located(room, path, destination);
317
+ return at !== null && !covers(reach, at.room, at.path)
318
+ ? Promise.resolve(UNREADABLE)
319
+ : md.resolve(room, path, destination);
320
+ },
321
+ history: (room, path, query) => !covers(reach, room, path)
322
+ ? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
323
+ : runtime.locked(room)
324
+ ? Promise.resolve(lockedRoom(room))
325
+ : md.history(room, path, query),
249
326
  binaryFile: {
250
- read: (room, path, revision) => covers(reach, room, path)
251
- ? md.binaryFile.read(room, path, revision)
252
- : Promise.resolve(failure({ kind: 'room-not-readable', locator: room })),
253
- readReference: (reference) => refers(reach, runtime.referrerScope(reference.referrer))
254
- ? md.binaryFile.readReference(reference)
255
- : Promise.resolve(unreachedReference(reference.fileRef)),
327
+ read: (room, path, revision) => !covers(reach, room, path)
328
+ ? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
329
+ : runtime.locked(room)
330
+ ? Promise.resolve(lockedRoom(room))
331
+ : hand(md.binaryFile.read(room, path, revision)),
332
+ link: (room, path, revision) => !covers(reach, room, path)
333
+ ? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
334
+ : runtime.locked(room)
335
+ ? Promise.resolve(lockedRoom(room))
336
+ : 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
+ },
346
+ async part(file, part) {
347
+ const key = files.get(file);
348
+ if (key === undefined)
349
+ return null;
350
+ const bytes = await md.binaryFile.part(key, part);
351
+ if (bytes === null)
352
+ files.delete(file);
353
+ return bytes;
354
+ },
256
355
  },
257
- reached: (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
258
- md.reached(room, roomVersion, path),
356
+ reached: async (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
357
+ !runtime.locked(room) &&
358
+ (await md.reached(room, roomVersion, path)),
259
359
  log: () => (reach === null ? md.log() : ''),
360
+ cleanUp: () => (reach === null ? md.cleanUp() : Promise.reject(deviceUnreached())),
260
361
  roomDraft: {
261
- list: () => md.roomDraft.list().then((drafts) => draftsWithin(reach, drafts)),
262
- read: (room, path) => covers(reach, room, path) ? shownDraft(reach, md.roomDraft.read(room, path)) : null,
362
+ list: () => md.roomDraft.list().then((drafts) => unlocked(draftsWithin(reach, drafts))),
363
+ async read(room, path) {
364
+ if (!covers(reach, room, path))
365
+ return null;
366
+ if (runtime.locked(room))
367
+ throw lockedError(room);
368
+ return shownDraft(reach, await md.roomDraft.read(room, path));
369
+ },
263
370
  async write(room, path, revision, parts) {
264
- if (!covers(reach, room, path) || !moves(reach, room, readParts(parts).move)) {
371
+ const move = readParts(parts).move;
372
+ if (!covers(reach, room, path) || !moves(reach, room, move))
265
373
  throw unreached(room);
266
- }
374
+ if (runtime.locked(room))
375
+ throw lockedError(room);
376
+ if (intoLocked([move]))
377
+ throw lockedError(move.room);
267
378
  return writeWithin(reach, await md.roomDraft.write(room, path, revision, parts));
268
379
  },
269
380
  async discard(room, path, revision) {
270
381
  if (!covers(reach, room, path))
271
382
  return staleWrite(null);
383
+ if (runtime.locked(room))
384
+ throw lockedError(room);
272
385
  return writeWithin(reach, await md.roomDraft.discard(room, path, revision));
273
386
  },
274
387
  },
@@ -277,6 +390,11 @@ export function narrowed(runtime, given, told) {
277
390
  read: (id, options) => conversation().read(id, options),
278
391
  create: (input) => conversation().create(input),
279
392
  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),
280
398
  answer: (id, answer) => conversation().answer(id, answer),
281
399
  interrupt: (id) => conversation().interrupt(id),
282
400
  kill: (id) => conversation().kill(id),
@@ -285,6 +403,7 @@ export function narrowed(runtime, given, told) {
285
403
  },
286
404
  chatDraft: {
287
405
  write: (id, draft, revision) => chatDraft().write(id, draft, revision),
406
+ prepend: (id, draft) => chatDraft().prepend(id, draft),
288
407
  discard: (id) => chatDraft().discard(id),
289
408
  },
290
409
  observe: observing(within),
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { MdRuntimeClient } from './client.js';
2
- import type { AppRoom, ConnectionRefusal, SaveResult } from './connection.js';
2
+ import type { AppRoom, ConnectionRefusal, SavedRoomDraft, SaveResult } from './connection.js';
3
3
  import type { Member, ServiceMode } from './adapter.js';
4
4
  import type { ConversationAgent, ConversationEntry, ConversationOptions, ConversationView } from './conversation.js';
5
5
  import { type RuntimeError } from './failure.js';
@@ -35,9 +35,9 @@ export type Saving = {
35
35
  readonly busy: boolean;
36
36
  readonly outcome: SaveResult | null;
37
37
  readonly failure: RuntimeError | null;
38
- save(room: string, roomDrafts: ReadonlyMap<string, RoomDraftParts>): Promise<SaveResult>;
38
+ save(room: string, parts: ReadonlyMap<string, RoomDraftParts>): Promise<SaveResult>;
39
+ saveWritten(room: string, roomDrafts: readonly SavedRoomDraft[]): Promise<SaveResult>;
39
40
  };
40
- export declare function saveRoomDrafts(client: MdRuntimeClient, room: string, roomDrafts: ReadonlyMap<string, RoomDraftParts>): Promise<SaveResult>;
41
41
  export declare function useSave(client: MdRuntimeClient): Saving;
42
42
  export {};
43
43
  //# sourceMappingURL=react.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"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"}
package/dist/react.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { useCallback, useLayoutEffect, useRef, useState } from 'react';
2
- import { failed, runtimeError } from './failure.js';
2
+ import { failed } from './failure.js';
3
3
  const LOADING = { state: 'loading' };
4
4
  export function useObserve(client, topic, ...input) {
5
5
  const key = JSON.stringify([topic, ...input]);
@@ -33,24 +33,12 @@ export function useObserve(client, topic, ...input) {
33
33
  return held !== null && held.client === client && held.key === key ? held.observed : LOADING;
34
34
  }
35
35
  const IDLE = { busy: false, outcome: null, failure: null };
36
- export async function saveRoomDrafts(client, room, roomDrafts) {
37
- const kept = [];
38
- for (const [path, parts] of roomDrafts) {
39
- const prior = await client.roomDraft.read(room, path);
40
- const write = await client.roomDraft.write(room, path, prior?.revision ?? null, parts);
41
- if (write.outcome !== 'written' || write.roomDraft === null) {
42
- throw runtimeError(write.outcome === 'stale' ? write.code : 'room-draft-unwritten', `the Room Draft at ${path} was not written`);
43
- }
44
- kept.push({ path, revision: write.roomDraft.revision });
45
- }
46
- return client.save(room, kept);
47
- }
48
36
  export function useSave(client) {
49
37
  const [state, setState] = useState(IDLE);
50
- const save = useCallback(async (room, roomDrafts) => {
38
+ const settled = useCallback(async (saving) => {
51
39
  setState({ busy: true, outcome: null, failure: null });
52
40
  try {
53
- const outcome = await saveRoomDrafts(client, room, roomDrafts);
41
+ const outcome = await saving();
54
42
  setState({ busy: false, outcome, failure: null });
55
43
  return outcome;
56
44
  }
@@ -59,6 +47,8 @@ export function useSave(client) {
59
47
  setState({ busy: false, outcome: null, failure });
60
48
  throw failure;
61
49
  }
62
- }, [client]);
63
- return { ...state, save };
50
+ }, []);
51
+ const save = useCallback((room, parts) => settled(() => client.saveParts(room, [...parts].map(([path, one]) => ({ path, parts: one })))), [client, settled]);
52
+ const saveWritten = useCallback((room, roomDrafts) => settled(() => client.save(room, roomDrafts)), [client, settled]);
53
+ return { ...state, save, saveWritten };
64
54
  }
@@ -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;
@@ -19,7 +19,7 @@ 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
21
  export type CapacityCause = {
22
- readonly cause: Open<'insufficient-space' | 'quota-exceeded'>;
22
+ readonly cause: Open<'insufficient-space' | 'storage-exceeded'>;
23
23
  readonly needed: number | null;
24
24
  readonly available: number | null;
25
25
  };
@@ -29,6 +29,20 @@ export type RefusedRoom = {
29
29
  readonly rule: string;
30
30
  readonly location: string | null;
31
31
  };
32
+ export type InstallationStep = Open<'listing' | 'downloading' | 'writing' | 'replaying'>;
33
+ export type InstallationPause = Open<'hidden'>;
34
+ export type InstallationAmount = {
35
+ readonly done: number;
36
+ readonly total: number;
37
+ };
38
+ export type Installation = {
39
+ readonly step: InstallationStep | null;
40
+ readonly paused: InstallationPause | null;
41
+ readonly rooms: InstallationAmount;
42
+ readonly parts: InstallationAmount;
43
+ readonly bytes: InstallationAmount;
44
+ readonly received: InstallationAmount;
45
+ };
32
46
  export type ReadinessStatus = Open<'preparing' | 'paused' | 'refused' | 'ready' | 'lost'>;
33
47
  export type Readiness = {
34
48
  readonly status: ReadinessStatus;
@@ -41,6 +55,7 @@ export type Readiness = {
41
55
  readonly connection: ConnectionAvailability;
42
56
  readonly house: HouseOutcome;
43
57
  readonly capacity: CapacityCause | null;
58
+ readonly installation: Installation;
44
59
  readonly refused: readonly RefusedRoom[];
45
60
  readonly lost: boolean;
46
61
  };
@@ -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
@@ -15,7 +15,7 @@ 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.capacity !== null || facts.installation.paused !== null
19
19
  ? 'paused'
20
20
  : facts.lost && !established
21
21
  ? 'lost'
@@ -0,0 +1,11 @@
1
+ import type { Adapter } from './adapter.js';
2
+ import type { Reads } from './bootstrap.js';
3
+ export type DoorReads = Reads & {
4
+ carried(locator: string): number;
5
+ finished(locator: string, turn: number): void;
6
+ opened(): void;
7
+ applied(): void;
8
+ lost(): void;
9
+ };
10
+ export declare function doorReads(adapter: Adapter, declaration: (locator: string) => unknown, generation: () => number): DoorReads;
11
+ //# sourceMappingURL=reads.d.ts.map
@@ -0,0 +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;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 ADDED
@@ -0,0 +1,100 @@
1
+ function declaredAs(declaration) {
2
+ if (declaration === null || typeof declaration !== 'object')
3
+ return declaration;
4
+ const { roomVersion: _version, ...declared } = declaration;
5
+ return declared;
6
+ }
7
+ function sameHeld(one, other) {
8
+ return one === other;
9
+ }
10
+ function failed(answer) {
11
+ return answer?.kind === 'transport-uncertainty';
12
+ }
13
+ function continues(answer) {
14
+ const page = answer;
15
+ return page?.kind === 'net-advancement' && page.pageToken !== undefined;
16
+ }
17
+ export function doorReads(adapter, declaration, generation) {
18
+ const reading = new Map();
19
+ const taken = new Map();
20
+ let carrying = false;
21
+ function joined(read, authorization, request, ask) {
22
+ const key = `${read} ${request.locator} ${request.pageToken ?? ''}`;
23
+ const { held, received, ...named } = request;
24
+ const asked = JSON.stringify([declaredAs(declaration(request.locator)), named]);
25
+ const asking = generation();
26
+ const current = reading.get(key);
27
+ if (current !== undefined &&
28
+ current.authorization === authorization &&
29
+ current.asked === asked &&
30
+ sameHeld(current.held, held) &&
31
+ current.received === received &&
32
+ (!current.settled || current.holder < asking)) {
33
+ if (current.settled && !current.continued)
34
+ reading.delete(key);
35
+ else
36
+ current.holder = Math.max(current.holder, asking);
37
+ if (current.from === asking)
38
+ return current.answer;
39
+ const again = () => joined(read, authorization, request, ask);
40
+ return current.answer.then((answer) => {
41
+ if (failed(answer))
42
+ return again();
43
+ taken.set(request.locator, (taken.get(request.locator) ?? 0) + 1);
44
+ return answer;
45
+ }, again);
46
+ }
47
+ const answer = ask();
48
+ const sent = {
49
+ locator: request.locator,
50
+ authorization,
51
+ asked,
52
+ held,
53
+ received,
54
+ answer,
55
+ from: asking,
56
+ holder: asking,
57
+ settled: false,
58
+ continued: false,
59
+ };
60
+ reading.set(key, sent);
61
+ const settled = (result, kept) => {
62
+ sent.settled = true;
63
+ sent.continued = kept && read === 'refresh' && continues(result);
64
+ if (reading.get(key) !== sent)
65
+ return;
66
+ const live = sent.holder === generation();
67
+ if (!kept || (live ? !sent.continued : !carrying))
68
+ reading.delete(key);
69
+ };
70
+ answer.then((result) => settled(result, !failed(result)), () => settled(null, false));
71
+ return answer;
72
+ }
73
+ return {
74
+ bootstrap: (authorization, request) => joined('bootstrap', authorization, request, () => adapter.bootstrap(authorization, request)),
75
+ refresh: (authorization, request) => joined('refresh', authorization, request, () => adapter.refresh(authorization, request)),
76
+ reached: (locator, roomVersion, target) => adapter.reached(locator, roomVersion, target),
77
+ carried: (locator) => taken.get(locator) ?? 0,
78
+ finished(locator, turn) {
79
+ for (const [key, held] of reading) {
80
+ if (held.locator !== locator || !held.settled || held.holder !== turn)
81
+ continue;
82
+ if (turn === generation() || !carrying)
83
+ reading.delete(key);
84
+ }
85
+ },
86
+ opened() {
87
+ carrying = true;
88
+ },
89
+ applied() {
90
+ carrying = false;
91
+ for (const [key, held] of reading) {
92
+ if (held.settled && held.holder !== generation())
93
+ reading.delete(key);
94
+ }
95
+ },
96
+ lost() {
97
+ reading.clear();
98
+ },
99
+ };
100
+ }
@@ -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