@agentshouse/mdruntime 0.1.0-c0105dbd22806 → 0.1.0-c0136de3edfbe

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 (356) hide show
  1. package/README.md +19 -16
  2. package/dist/acceptance.d.ts +6 -0
  3. package/dist/acceptance.d.ts.map +1 -0
  4. package/dist/acceptance.js +389 -0
  5. package/dist/actions.d.ts +20 -0
  6. package/dist/actions.d.ts.map +1 -0
  7. package/dist/actions.js +248 -0
  8. package/dist/adapter.d.ts +153 -58
  9. package/dist/adapter.d.ts.map +1 -1
  10. package/dist/attached-model.d.ts +7 -10
  11. package/dist/attached-model.d.ts.map +1 -1
  12. package/dist/attached-model.js +40 -41
  13. package/dist/binary.d.ts +0 -5
  14. package/dist/binary.d.ts.map +1 -1
  15. package/dist/binary.js +1 -1
  16. package/dist/bootstrap.d.ts +31 -11
  17. package/dist/bootstrap.d.ts.map +1 -1
  18. package/dist/bootstrap.js +323 -93
  19. package/dist/cell.d.ts +6 -0
  20. package/dist/cell.d.ts.map +1 -0
  21. package/dist/cell.js +9 -0
  22. package/dist/chain.d.ts +12 -0
  23. package/dist/chain.d.ts.map +1 -0
  24. package/dist/chain.js +64 -0
  25. package/dist/change-set.d.ts +9 -14
  26. package/dist/change-set.d.ts.map +1 -1
  27. package/dist/change-set.js +11 -63
  28. package/dist/change.d.ts +32 -1
  29. package/dist/change.d.ts.map +1 -1
  30. package/dist/change.js +10 -1
  31. package/dist/chat-types.d.ts +3 -0
  32. package/dist/chat-types.d.ts.map +1 -0
  33. package/dist/chat-types.js +2 -0
  34. package/dist/client.d.ts +41 -16
  35. package/dist/client.d.ts.map +1 -1
  36. package/dist/client.js +101 -12
  37. package/dist/collection.d.ts +11 -7
  38. package/dist/collection.d.ts.map +1 -1
  39. package/dist/collection.js +38 -79
  40. package/dist/compile.d.ts +16 -0
  41. package/dist/compile.d.ts.map +1 -0
  42. package/dist/compile.js +717 -0
  43. package/dist/connection.d.ts +8 -117
  44. package/dist/connection.d.ts.map +1 -1
  45. package/dist/connection.js +101 -2483
  46. package/dist/context.d.ts +2 -0
  47. package/dist/context.d.ts.map +1 -0
  48. package/dist/{chat/context.js → context.js} +1 -4
  49. package/dist/conversation-row.d.ts +33 -0
  50. package/dist/conversation-row.d.ts.map +1 -0
  51. package/dist/conversation-row.js +47 -0
  52. package/dist/conversation.d.ts +50 -20
  53. package/dist/conversation.d.ts.map +1 -1
  54. package/dist/conversation.js +897 -303
  55. package/dist/digest.d.ts +7 -0
  56. package/dist/digest.d.ts.map +1 -0
  57. package/dist/digest.js +113 -0
  58. package/dist/discovery.d.ts +10 -0
  59. package/dist/discovery.d.ts.map +1 -0
  60. package/dist/discovery.js +175 -0
  61. package/dist/durability.d.ts +10 -1
  62. package/dist/durability.d.ts.map +1 -1
  63. package/dist/durability.js +5 -0
  64. package/dist/entry.d.ts +7 -4
  65. package/dist/entry.d.ts.map +1 -1
  66. package/dist/entry.js +33 -28
  67. package/dist/figures.d.ts +48 -0
  68. package/dist/figures.d.ts.map +1 -0
  69. package/dist/figures.js +197 -0
  70. package/dist/file.d.ts +2 -19
  71. package/dist/file.d.ts.map +1 -1
  72. package/dist/file.js +7 -122
  73. package/dist/host.d.ts +11 -3
  74. package/dist/host.d.ts.map +1 -1
  75. package/dist/host.js +128 -21
  76. package/dist/index.d.ts +31 -11
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +10 -0
  79. package/dist/install.d.ts +56 -0
  80. package/dist/install.d.ts.map +1 -0
  81. package/dist/install.js +560 -0
  82. package/dist/job.d.ts +33 -0
  83. package/dist/job.d.ts.map +1 -0
  84. package/dist/job.js +54 -0
  85. package/dist/lifecycle.d.ts +7 -0
  86. package/dist/lifecycle.d.ts.map +1 -0
  87. package/dist/lifecycle.js +267 -0
  88. package/dist/listing.d.ts +53 -0
  89. package/dist/listing.d.ts.map +1 -0
  90. package/dist/listing.js +175 -0
  91. package/dist/live.d.ts +23 -0
  92. package/dist/live.d.ts.map +1 -0
  93. package/dist/live.js +165 -0
  94. package/dist/locks.d.ts +9 -0
  95. package/dist/locks.d.ts.map +1 -0
  96. package/dist/locks.js +61 -0
  97. package/dist/log.d.ts +1 -0
  98. package/dist/log.d.ts.map +1 -1
  99. package/dist/lost.d.ts +5 -0
  100. package/dist/lost.d.ts.map +1 -0
  101. package/dist/lost.js +61 -0
  102. package/dist/media.d.ts +8 -0
  103. package/dist/media.d.ts.map +1 -0
  104. package/dist/media.js +218 -0
  105. package/dist/memory.d.ts +19 -6
  106. package/dist/memory.d.ts.map +1 -1
  107. package/dist/memory.js +253 -95
  108. package/dist/messages.d.ts +52 -0
  109. package/dist/messages.d.ts.map +1 -0
  110. package/dist/messages.js +168 -0
  111. package/dist/model.d.ts +11 -11
  112. package/dist/model.d.ts.map +1 -1
  113. package/dist/model.js +7 -10
  114. package/dist/models.d.ts +14 -0
  115. package/dist/models.d.ts.map +1 -0
  116. package/dist/models.js +193 -0
  117. package/dist/name.d.ts +4 -0
  118. package/dist/name.d.ts.map +1 -0
  119. package/dist/name.js +122 -0
  120. package/dist/observation.d.ts +22 -4
  121. package/dist/observation.d.ts.map +1 -1
  122. package/dist/observation.js +120 -14
  123. package/dist/opened.d.ts +22 -0
  124. package/dist/opened.d.ts.map +1 -0
  125. package/dist/opened.js +107 -0
  126. package/dist/opening.d.ts +4 -0
  127. package/dist/opening.d.ts.map +1 -0
  128. package/dist/opening.js +56 -0
  129. package/dist/outcome.d.ts +50 -7
  130. package/dist/outcome.d.ts.map +1 -1
  131. package/dist/outcome.js +43 -0
  132. package/dist/overlay.d.ts +4 -4
  133. package/dist/overlay.d.ts.map +1 -1
  134. package/dist/overlay.js +111 -182
  135. package/dist/{chat/parts.d.ts → parts.d.ts} +11 -9
  136. package/dist/parts.d.ts.map +1 -0
  137. package/dist/{chat/parts.js → parts.js} +45 -46
  138. package/dist/paths.d.ts +1 -0
  139. package/dist/paths.d.ts.map +1 -1
  140. package/dist/paths.js +4 -0
  141. package/dist/preparation.d.ts +20 -0
  142. package/dist/preparation.d.ts.map +1 -0
  143. package/dist/preparation.js +226 -0
  144. package/dist/queries.d.ts +16 -0
  145. package/dist/queries.d.ts.map +1 -0
  146. package/dist/queries.js +272 -0
  147. package/dist/query.d.ts +50 -183
  148. package/dist/query.d.ts.map +1 -1
  149. package/dist/query.js +3 -464
  150. package/dist/{chat/questions.d.ts → questions.d.ts} +3 -2
  151. package/dist/questions.d.ts.map +1 -0
  152. package/dist/{chat/questions.js → questions.js} +8 -1
  153. package/dist/reach.d.ts +21 -7
  154. package/dist/reach.d.ts.map +1 -1
  155. package/dist/reach.js +289 -89
  156. package/dist/react.d.ts +12 -6
  157. package/dist/react.d.ts.map +1 -1
  158. package/dist/react.js +7 -17
  159. package/dist/{chat/read.d.ts → read.d.ts} +2 -0
  160. package/dist/read.d.ts.map +1 -0
  161. package/dist/{chat/read.js → read.js} +4 -0
  162. package/dist/readiness.d.ts +50 -0
  163. package/dist/readiness.d.ts.map +1 -0
  164. package/dist/readiness.js +27 -0
  165. package/dist/reads.d.ts +36 -0
  166. package/dist/reads.d.ts.map +1 -0
  167. package/dist/reads.js +136 -0
  168. package/dist/recovery.d.ts +26 -0
  169. package/dist/recovery.d.ts.map +1 -0
  170. package/dist/recovery.js +232 -0
  171. package/dist/refresh.d.ts +17 -14
  172. package/dist/refresh.d.ts.map +1 -1
  173. package/dist/refresh.js +143 -51
  174. package/dist/refusal.d.ts +5 -0
  175. package/dist/refusal.d.ts.map +1 -0
  176. package/dist/refusal.js +56 -0
  177. package/dist/replica.d.ts +55 -33
  178. package/dist/replica.d.ts.map +1 -1
  179. package/dist/replica.js +332 -154
  180. package/dist/room-draft.d.ts +37 -6
  181. package/dist/room-draft.d.ts.map +1 -1
  182. package/dist/room-draft.js +161 -74
  183. package/dist/room-drafts.d.ts +24 -0
  184. package/dist/room-drafts.d.ts.map +1 -0
  185. package/dist/room-drafts.js +216 -0
  186. package/dist/rows.d.ts +30 -37
  187. package/dist/rows.d.ts.map +1 -1
  188. package/dist/rows.js +59 -126
  189. package/dist/runtime.d.ts +42 -0
  190. package/dist/runtime.d.ts.map +1 -0
  191. package/dist/runtime.js +1 -0
  192. package/dist/save.d.ts +53 -9
  193. package/dist/save.d.ts.map +1 -1
  194. package/dist/save.js +542 -172
  195. package/dist/saves.d.ts +70 -0
  196. package/dist/saves.d.ts.map +1 -0
  197. package/dist/saves.js +1004 -0
  198. package/dist/search.d.ts +15 -55
  199. package/dist/search.d.ts.map +1 -1
  200. package/dist/search.js +10 -121
  201. package/dist/seed.d.ts +25 -0
  202. package/dist/seed.d.ts.map +1 -0
  203. package/dist/seed.js +146 -0
  204. package/dist/shared.d.ts +15 -0
  205. package/dist/shared.d.ts.map +1 -0
  206. package/dist/shared.js +421 -0
  207. package/dist/shown.d.ts +31 -0
  208. package/dist/shown.d.ts.map +1 -0
  209. package/dist/shown.js +294 -0
  210. package/dist/socket/admission.d.ts +7 -0
  211. package/dist/socket/admission.d.ts.map +1 -0
  212. package/dist/socket/admission.js +39 -0
  213. package/dist/socket/answers.d.ts +6 -0
  214. package/dist/socket/answers.d.ts.map +1 -0
  215. package/dist/socket/answers.js +20 -0
  216. package/dist/socket/lanes.d.ts +20 -0
  217. package/dist/socket/lanes.d.ts.map +1 -0
  218. package/dist/socket/lanes.js +77 -0
  219. package/dist/socket/reads.d.ts +10 -0
  220. package/dist/socket/reads.d.ts.map +1 -0
  221. package/dist/socket/reads.js +31 -0
  222. package/dist/socket/rooms.d.ts +43 -0
  223. package/dist/socket/rooms.d.ts.map +1 -0
  224. package/dist/socket/rooms.js +90 -0
  225. package/dist/socket/session.d.ts +39 -0
  226. package/dist/socket/session.d.ts.map +1 -0
  227. package/dist/socket/session.js +23 -0
  228. package/dist/socket.d.ts +70 -0
  229. package/dist/socket.d.ts.map +1 -0
  230. package/dist/socket.js +175 -0
  231. package/dist/source.d.ts +61 -0
  232. package/dist/source.d.ts.map +1 -0
  233. package/dist/source.js +81 -0
  234. package/dist/status.d.ts +5 -2
  235. package/dist/status.d.ts.map +1 -1
  236. package/dist/status.js +3 -7
  237. package/dist/store/fences.d.ts +16 -0
  238. package/dist/store/fences.d.ts.map +1 -0
  239. package/dist/store/fences.js +26 -0
  240. package/dist/store/installs.d.ts +30 -0
  241. package/dist/store/installs.d.ts.map +1 -0
  242. package/dist/store/installs.js +34 -0
  243. package/dist/store/readiness.d.ts +10 -0
  244. package/dist/store/readiness.d.ts.map +1 -0
  245. package/dist/store/readiness.js +52 -0
  246. package/dist/store/records.d.ts +212 -0
  247. package/dist/store/records.d.ts.map +1 -0
  248. package/dist/store/records.js +408 -0
  249. package/dist/store/room-held.d.ts +8 -0
  250. package/dist/store/room-held.d.ts.map +1 -0
  251. package/dist/store/room-held.js +17 -0
  252. package/dist/store/space.d.ts +11 -0
  253. package/dist/store/space.d.ts.map +1 -0
  254. package/dist/store/space.js +43 -0
  255. package/dist/store/watchers.d.ts +17 -0
  256. package/dist/store/watchers.d.ts.map +1 -0
  257. package/dist/store/watchers.js +57 -0
  258. package/dist/store/writes.d.ts +24 -0
  259. package/dist/store/writes.d.ts.map +1 -0
  260. package/dist/store/writes.js +125 -0
  261. package/dist/store.d.ts +106 -120
  262. package/dist/store.d.ts.map +1 -1
  263. package/dist/store.js +136 -556
  264. package/dist/stored.d.ts +156 -0
  265. package/dist/stored.d.ts.map +1 -0
  266. package/dist/stored.js +637 -0
  267. package/dist/surface.d.ts +86 -0
  268. package/dist/surface.d.ts.map +1 -0
  269. package/dist/surface.js +217 -0
  270. package/dist/sync.d.ts +20 -0
  271. package/dist/sync.d.ts.map +1 -0
  272. package/dist/sync.js +531 -0
  273. package/dist/tables.d.ts +407 -0
  274. package/dist/tables.d.ts.map +1 -0
  275. package/dist/tables.js +724 -0
  276. package/dist/tallies.d.ts +18 -0
  277. package/dist/tallies.d.ts.map +1 -0
  278. package/dist/tallies.js +129 -0
  279. package/dist/transfer.d.ts +0 -5
  280. package/dist/transfer.d.ts.map +1 -1
  281. package/dist/turn.d.ts +9 -0
  282. package/dist/turn.d.ts.map +1 -0
  283. package/dist/turn.js +75 -0
  284. package/dist/validation.d.ts +29 -0
  285. package/dist/validation.d.ts.map +1 -0
  286. package/dist/validation.js +104 -0
  287. package/dist/windows.d.ts +11 -0
  288. package/dist/windows.d.ts.map +1 -0
  289. package/dist/windows.js +16 -0
  290. package/dist/wire.d.ts +180 -33
  291. package/dist/wire.d.ts.map +1 -1
  292. package/dist/wire.js +61 -31
  293. package/package.json +18 -19
  294. package/AGENTS.md +0 -299
  295. package/dist/chat/acts.d.ts +0 -34
  296. package/dist/chat/acts.d.ts.map +0 -1
  297. package/dist/chat/acts.js +0 -36
  298. package/dist/chat/context.d.ts +0 -3
  299. package/dist/chat/context.d.ts.map +0 -1
  300. package/dist/chat/input.d.ts +0 -9
  301. package/dist/chat/input.d.ts.map +0 -1
  302. package/dist/chat/input.js +0 -99
  303. package/dist/chat/kit.d.ts +0 -60
  304. package/dist/chat/kit.d.ts.map +0 -1
  305. package/dist/chat/kit.js +0 -123
  306. package/dist/chat/lasting.d.ts +0 -6
  307. package/dist/chat/lasting.d.ts.map +0 -1
  308. package/dist/chat/lasting.js +0 -19
  309. package/dist/chat/list.d.ts +0 -26
  310. package/dist/chat/list.d.ts.map +0 -1
  311. package/dist/chat/list.js +0 -62
  312. package/dist/chat/markdown.d.ts +0 -20
  313. package/dist/chat/markdown.d.ts.map +0 -1
  314. package/dist/chat/markdown.js +0 -188
  315. package/dist/chat/message.d.ts +0 -6
  316. package/dist/chat/message.d.ts.map +0 -1
  317. package/dist/chat/message.js +0 -192
  318. package/dist/chat/messages.d.ts +0 -21
  319. package/dist/chat/messages.d.ts.map +0 -1
  320. package/dist/chat/messages.js +0 -151
  321. package/dist/chat/name.d.ts +0 -6
  322. package/dist/chat/name.d.ts.map +0 -1
  323. package/dist/chat/name.js +0 -37
  324. package/dist/chat/opened.d.ts +0 -11
  325. package/dist/chat/opened.d.ts.map +0 -1
  326. package/dist/chat/opened.js +0 -17
  327. package/dist/chat/overlay.d.ts +0 -31
  328. package/dist/chat/overlay.d.ts.map +0 -1
  329. package/dist/chat/overlay.js +0 -97
  330. package/dist/chat/parts.d.ts.map +0 -1
  331. package/dist/chat/process.d.ts +0 -20
  332. package/dist/chat/process.d.ts.map +0 -1
  333. package/dist/chat/process.js +0 -32
  334. package/dist/chat/provider.d.ts +0 -63
  335. package/dist/chat/provider.d.ts.map +0 -1
  336. package/dist/chat/provider.js +0 -645
  337. package/dist/chat/question.d.ts +0 -9
  338. package/dist/chat/question.d.ts.map +0 -1
  339. package/dist/chat/question.js +0 -80
  340. package/dist/chat/questions.d.ts.map +0 -1
  341. package/dist/chat/read.d.ts.map +0 -1
  342. package/dist/chat/ready.d.ts +0 -33
  343. package/dist/chat/ready.d.ts.map +0 -1
  344. package/dist/chat/ready.js +0 -91
  345. package/dist/chat/style.d.ts +0 -4
  346. package/dist/chat/style.d.ts.map +0 -1
  347. package/dist/chat/style.js +0 -302
  348. package/dist/chat.d.ts +0 -14
  349. package/dist/chat.d.ts.map +0 -1
  350. package/dist/chat.js +0 -8
  351. package/dist/fence.d.ts +0 -6
  352. package/dist/fence.d.ts.map +0 -1
  353. package/dist/fence.js +0 -10
  354. package/dist/read-side.d.ts +0 -18
  355. package/dist/read-side.d.ts.map +0 -1
  356. package/dist/read-side.js +0 -440
@@ -0,0 +1,197 @@
1
+ import { instantKey } from '@agentshouse/mdmodel';
2
+ export const HOUSE_DIRECTORY = 'house';
3
+ export const ROOM_TOTALS = {
4
+ outside: [HOUSE_DIRECTORY],
5
+ groupBy: ['room'],
6
+ select: { size: true },
7
+ };
8
+ // Today's Last 24 hours is the day that ends as the read answers.
9
+ const DAY_MS = 86_400_000;
10
+ // An install or a catch-up commits many times a second, so the figures answer again once changes rest this long, never per commit.
11
+ const SETTLED_MS = 1_000;
12
+ // Changes that never rest, such as an Agent writing all afternoon, still reach the figures this long after the first of them.
13
+ const LONGEST_UNSETTLED_MS = 5_000;
14
+ function dayOf(tally, since) {
15
+ const after = (at) => at !== null && at >= since;
16
+ return {
17
+ created: tally.documentTimes.filter(([created]) => after(created)).length,
18
+ changed: tally.documentTimes.filter(([created, changed]) => !after(created) && after(changed))
19
+ .length,
20
+ chats: tally.chatTimes.filter(after).length,
21
+ messages: tally.messageTimes.filter(after).length,
22
+ };
23
+ }
24
+ function figuresOf(rooms, held, since) {
25
+ return {
26
+ rooms: rooms.map(({ locator }) => {
27
+ const tally = held.rooms.get(locator);
28
+ return {
29
+ room: locator,
30
+ day: dayOf(tally, since),
31
+ total: { documents: tally.documents, files: tally.files },
32
+ };
33
+ }),
34
+ agentMessages: [...held.said.values()].reduce((sum, said) => sum + said.filter((at) => at >= since).length, 0),
35
+ };
36
+ }
37
+ function unheld() {
38
+ return {
39
+ rooms: new Map(),
40
+ said: new Map(),
41
+ staleRooms: new Set(),
42
+ staleConversations: new Set(),
43
+ everyConversation: true,
44
+ };
45
+ }
46
+ export function createFigures(sources) {
47
+ const listeners = new Map();
48
+ const answered = new Set();
49
+ let held = unheld();
50
+ let shown = null;
51
+ let running = false;
52
+ let again = false;
53
+ let quiet = null;
54
+ let longest = null;
55
+ let closed = false;
56
+ function unscheduled() {
57
+ if (quiet !== null)
58
+ clearTimeout(quiet);
59
+ if (longest !== null)
60
+ clearTimeout(longest);
61
+ quiet = null;
62
+ longest = null;
63
+ }
64
+ function deliver(answer) {
65
+ const text = JSON.stringify(answer);
66
+ const changed = text !== shown;
67
+ shown = text;
68
+ for (const listener of listeners.keys()) {
69
+ if (changed || !answered.has(listener))
70
+ listener(structuredClone(answer));
71
+ answered.add(listener);
72
+ }
73
+ }
74
+ async function tallied(rooms, since) {
75
+ for (const locator of held.rooms.keys()) {
76
+ if (!rooms.some((room) => room.locator === locator))
77
+ held.rooms.delete(locator);
78
+ }
79
+ const asked = rooms.filter(({ locator, key }) => held.staleRooms.has(locator) || held.rooms.get(locator)?.key !== key);
80
+ for (const { locator } of asked)
81
+ held.staleRooms.delete(locator);
82
+ const every = held.everyConversation;
83
+ const conversations = every ? null : [...held.staleConversations];
84
+ held.everyConversation = false;
85
+ held.staleConversations.clear();
86
+ const kept = held;
87
+ const [roomTallies, said] = await Promise.all([
88
+ asked.length === 0 ? [] : sources.rooms(asked, since),
89
+ conversations?.length === 0 ? [] : sources.conversations(conversations, since),
90
+ ]);
91
+ if (kept !== held)
92
+ return false;
93
+ for (const tally of roomTallies) {
94
+ const room = asked.find(({ key }) => key === tally.key);
95
+ if (room !== undefined)
96
+ held.rooms.set(room.locator, tally);
97
+ }
98
+ if (every)
99
+ held.said.clear();
100
+ for (const { conversation, said: times } of said) {
101
+ if (times.length === 0)
102
+ held.said.delete(conversation);
103
+ else
104
+ held.said.set(conversation, times);
105
+ }
106
+ return true;
107
+ }
108
+ async function answer() {
109
+ const window = new Date(Date.now() - DAY_MS).toISOString();
110
+ const cover = await sources.cover();
111
+ if ('pending' in cover)
112
+ return cover;
113
+ if (!(await tallied(cover.rooms, window)))
114
+ return null;
115
+ return figuresOf(cover.rooms, held, instantKey(window));
116
+ }
117
+ async function run() {
118
+ if (running) {
119
+ again = true;
120
+ return;
121
+ }
122
+ running = true;
123
+ try {
124
+ do {
125
+ again = false;
126
+ const result = await answer();
127
+ if (closed || listeners.size === 0)
128
+ return;
129
+ if (result === null)
130
+ again = true;
131
+ else
132
+ deliver(result);
133
+ } while (again && !closed && listeners.size > 0);
134
+ }
135
+ catch (error) {
136
+ for (const [listener, failed] of listeners) {
137
+ if (!answered.has(listener))
138
+ failed(error);
139
+ }
140
+ }
141
+ finally {
142
+ running = false;
143
+ }
144
+ }
145
+ function stop(listener) {
146
+ return () => {
147
+ listeners.delete(listener);
148
+ answered.delete(listener);
149
+ if (listeners.size > 0)
150
+ return;
151
+ unscheduled();
152
+ held = unheld();
153
+ shown = null;
154
+ };
155
+ }
156
+ function settle() {
157
+ if (closed || listeners.size === 0)
158
+ return;
159
+ const now = () => {
160
+ unscheduled();
161
+ void run();
162
+ };
163
+ if (quiet !== null)
164
+ clearTimeout(quiet);
165
+ quiet = setTimeout(now, SETTLED_MS);
166
+ longest ??= setTimeout(now, LONGEST_UNSETTLED_MS);
167
+ }
168
+ return {
169
+ watch(listener, failed) {
170
+ listeners.set(listener, failed);
171
+ void run();
172
+ return stop(listener);
173
+ },
174
+ touched(set) {
175
+ if (listeners.size === 0)
176
+ return;
177
+ for (const { locator } of set.documents)
178
+ held.staleRooms.add(locator);
179
+ for (const locator of set.rooms)
180
+ held.staleRooms.add(locator);
181
+ for (const conversation of set.conversations)
182
+ held.staleConversations.add(conversation);
183
+ if (set.documents.length + set.rooms.length + set.conversations.length > 0)
184
+ settle();
185
+ },
186
+ recover() {
187
+ if (listeners.size > 0)
188
+ settle();
189
+ },
190
+ close() {
191
+ closed = true;
192
+ unscheduled();
193
+ listeners.clear();
194
+ answered.clear();
195
+ },
196
+ };
197
+ }
package/dist/file.d.ts CHANGED
@@ -1,20 +1,3 @@
1
- export type ChatDraftFile = {
2
- name: string;
3
- blob: Blob;
4
- };
5
- export type FileDeclaration = {
6
- name: string;
7
- mediaType: string;
8
- byteLength: number;
9
- contentHash: string;
10
- width?: number;
11
- height?: number;
12
- };
13
- export type Extent = {
14
- width: number;
15
- height: number;
16
- };
17
- export declare function extentOf(bytes: Uint8Array): Extent | null;
18
- export declare function hexDigest(digest: ArrayBuffer): string;
19
- export declare function declaredFile(file: ChatDraftFile): Promise<FileDeclaration>;
1
+ import type { AttachRequest } from './adapter.js';
2
+ export declare function attachedFile(locator: string, file: File): Promise<AttachRequest>;
20
3
  //# sourceMappingURL=file.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AA2GvD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAQzD;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAErD;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,CAAC,CAUhF"}
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAGlD,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAStF"}
package/dist/file.js CHANGED
@@ -1,126 +1,11 @@
1
- const PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
2
- const WEBP_SYNC = [0x9d, 0x01, 0x2a];
3
- const SHAPELESS_JPEG_MARKERS = new Set([0xc4, 0xc8, 0xcc]);
4
- const BMFF_CONTAINERS = new Set(['meta', 'iprp', 'ipco']);
5
- function starts(bytes, signature, at = 0) {
6
- return signature.every((value, index) => bytes[at + index] === value);
7
- }
8
- function text(bytes, at, length) {
9
- return String.fromCharCode(...bytes.subarray(at, at + length));
10
- }
11
- function bigEndian(bytes, at, length) {
12
- let value = 0;
13
- for (let index = 0; index < length; index += 1)
14
- value = value * 256 + (bytes[at + index] ?? 0);
15
- return value;
16
- }
17
- function littleEndian(bytes, at, length) {
18
- let value = 0;
19
- for (let index = length - 1; index >= 0; index -= 1)
20
- value = value * 256 + (bytes[at + index] ?? 0);
21
- return value;
22
- }
23
- function pngExtent(bytes) {
24
- if (bytes.length < 24 || !starts(bytes, PNG_SIGNATURE))
25
- return null;
26
- if (text(bytes, 12, 4) !== 'IHDR')
27
- return null;
28
- return { width: bigEndian(bytes, 16, 4), height: bigEndian(bytes, 20, 4) };
29
- }
30
- function gifExtent(bytes) {
31
- if (bytes.length < 10 || text(bytes, 0, 3) !== 'GIF')
32
- return null;
33
- return { width: littleEndian(bytes, 6, 2), height: littleEndian(bytes, 8, 2) };
34
- }
35
- function jpegExtent(bytes) {
36
- if (bytes.length < 4 || bytes[0] !== 0xff || bytes[1] !== 0xd8)
37
- return null;
38
- let at = 2;
39
- while (at + 9 < bytes.length) {
40
- if (bytes[at] !== 0xff)
41
- return null;
42
- const marker = bytes[at + 1] ?? 0;
43
- if (marker === 0xd8 || marker === 0x01 || (marker >= 0xd0 && marker <= 0xd7)) {
44
- at += 2;
45
- continue;
46
- }
47
- const length = bigEndian(bytes, at + 2, 2);
48
- if (marker >= 0xc0 && marker <= 0xcf && !SHAPELESS_JPEG_MARKERS.has(marker)) {
49
- return { width: bigEndian(bytes, at + 7, 2), height: bigEndian(bytes, at + 5, 2) };
50
- }
51
- if (length < 2)
52
- return null;
53
- at += 2 + length;
54
- }
55
- return null;
56
- }
57
- function webpExtent(bytes) {
58
- if (bytes.length < 30 || text(bytes, 0, 4) !== 'RIFF' || text(bytes, 8, 4) !== 'WEBP')
59
- return null;
60
- const chunk = text(bytes, 12, 4);
61
- if (chunk === 'VP8X') {
62
- return {
63
- width: littleEndian(bytes, 24, 3) + 1,
64
- height: littleEndian(bytes, 27, 3) + 1,
65
- };
66
- }
67
- if (chunk === 'VP8 ' && starts(bytes, WEBP_SYNC, 23)) {
68
- return {
69
- width: littleEndian(bytes, 26, 2) & 0x3fff,
70
- height: littleEndian(bytes, 28, 2) & 0x3fff,
71
- };
72
- }
73
- if (chunk === 'VP8L' && bytes[20] === 0x2f) {
74
- const packed = littleEndian(bytes, 21, 4);
75
- return { width: (packed & 0x3fff) + 1, height: ((packed >>> 14) & 0x3fff) + 1 };
76
- }
77
- return null;
78
- }
79
- function spatialExtent(bytes, from, to) {
80
- let at = from;
81
- while (at + 8 <= to) {
82
- const size = bigEndian(bytes, at, 4);
83
- const name = text(bytes, at + 4, 4);
84
- const end = size === 0 ? to : at + size;
85
- if (size === 1 || end <= at || end > to)
86
- return null;
87
- if (name === 'ispe') {
88
- if (end < at + 20)
89
- return null;
90
- return { width: bigEndian(bytes, at + 12, 4), height: bigEndian(bytes, at + 16, 4) };
91
- }
92
- if (BMFF_CONTAINERS.has(name)) {
93
- const inner = spatialExtent(bytes, at + (name === 'meta' ? 12 : 8), end);
94
- if (inner !== null)
95
- return inner;
96
- }
97
- at = end;
98
- }
99
- return null;
100
- }
101
- function bmffExtent(bytes) {
102
- if (bytes.length < 16 || text(bytes, 4, 4) !== 'ftyp')
103
- return null;
104
- return spatialExtent(bytes, 0, bytes.length);
105
- }
106
- export function extentOf(bytes) {
107
- return (pngExtent(bytes) ??
108
- jpegExtent(bytes) ??
109
- gifExtent(bytes) ??
110
- webpExtent(bytes) ??
111
- bmffExtent(bytes));
112
- }
113
- export function hexDigest(digest) {
114
- return [...new Uint8Array(digest)].map((value) => value.toString(16).padStart(2, '0')).join('');
115
- }
116
- export async function declaredFile(file) {
117
- const bytes = new Uint8Array(await file.blob.arrayBuffer());
118
- const extent = file.blob.type.startsWith('image/') ? extentOf(bytes) : null;
1
+ import { sha256 } from './digest.js';
2
+ export async function attachedFile(locator, file) {
119
3
  return {
4
+ locator,
120
5
  name: file.name,
121
- mediaType: file.blob.type,
122
- byteLength: bytes.byteLength,
123
- contentHash: hexDigest(await crypto.subtle.digest('SHA-256', bytes)),
124
- ...(extent === null ? {} : extent),
6
+ mediaType: file.type,
7
+ byteLength: file.size,
8
+ sha256: await sha256(file),
9
+ blob: file,
125
10
  };
126
11
  }
package/dist/host.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { type MdRuntimeOptions } from './connection.js';
2
2
  import type { PortReach } from './reach.js';
3
+ import type { CodeAvailability, Persistence, Readiness } from './readiness.js';
4
+ import type { EntrySeed } from './seed.js';
3
5
  import { type RuntimePort } from './wire.js';
4
6
  export type MdRuntimeHostOptions = MdRuntimeOptions & {
5
7
  deploymentFacts?: unknown;
@@ -7,15 +9,21 @@ export type MdRuntimeHostOptions = MdRuntimeOptions & {
7
9
  export type AttachedPort = {
8
10
  detach(): void;
9
11
  narrow(reach: PortReach): void;
12
+ readiness(deliver: (readiness: Readiness) => void): () => void;
13
+ answered(queries: readonly unknown[], done: () => void): void;
10
14
  };
11
15
  export type MdRuntimeHost = {
12
- attach(port: RuntimePort, app: string, release?: string, reach?: PortReach): AttachedPort;
16
+ attach(port: RuntimePort, app: string, release?: string, reach?: PortReach, code?: CodeAvailability): AttachedPort;
17
+ present(app: string, members: Readonly<Record<string, unknown>>): Promise<void>;
18
+ seed(entry: EntrySeed): void;
19
+ persisted(answer: Persistence): void;
13
20
  endAuthorization(holder?: string): Promise<void>;
14
- lose(locators: readonly string[]): Promise<void>;
15
21
  stop(): Promise<void>;
16
22
  };
17
23
  export declare function serveMdRuntime(options: MdRuntimeHostOptions): MdRuntimeHost;
24
+ export { entrySeedOf, type EntrySeed } from './seed.js';
18
25
  export type { PortReach, ReachedDocument } from './reach.js';
19
- export { AUTHORED_SCHEMA, authoredBy, authoredHolder, STORE_SCHEMA } from './store.js';
26
+ export type { CodeAvailability, Persistence, Space } from './readiness.js';
27
+ export { createRecovery, retryDelay, type Attempt, type Attempted, type AttemptOptions, type Recovery, type RecoveryOptions, } from './recovery.js';
20
28
  export type { RuntimePort } from './wire.js';
21
29
  //# sourceMappingURL=host.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,gBAAgB,EAEtB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C,OAAO,EAGL,KAAK,WAAW,EAOjB,MAAM,WAAW,CAAC;AAInB,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;IAC1F,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB,CAAC;AAsFF,wBAAgB,cAAc,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAoH3E;AAED,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACvF,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAGA,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAIxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE/E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C,OAAO,EAGL,KAAK,WAAW,EAOjB,MAAM,WAAW,CAAC;AAInB,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IAC/B,SAAS,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC/D,QAAQ,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAC/D,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,CACJ,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,SAAS,EACjB,IAAI,CAAC,EAAE,gBAAgB,GACtB,YAAY,CAAC;IAChB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IACrC,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB,CAAC;AAsIF,wBAAgB,cAAc,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAuL3E;AAED,OAAO,EAAE,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AACxD,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7D,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EACL,cAAc,EACd,UAAU,EACV,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,eAAe,GACrB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
package/dist/host.js CHANGED
@@ -1,7 +1,9 @@
1
- import { composeRuntime, } from './connection.js';
1
+ import { queryKey } from '@agentshouse/mdmodel';
2
+ import { composeRuntime } from './connection.js';
3
+ import { untilAnswered } from './recovery.js';
2
4
  import { described } from './failure.js';
3
- import { removeRuntimeStore } from './store.js';
4
- import { AUTHORIZATION_ENDED, request, WIRE_REACH, } from './wire.js';
5
+ import { answeredResult } from './outcome.js';
6
+ import { AUTHORIZATION_ENDED, request, WIRE, } from './wire.js';
5
7
  const NARROWED = new Set(['within', 'whole']);
6
8
  function answered(md, app, writtenBy, member, input) {
7
9
  switch (member) {
@@ -15,20 +17,40 @@ function answered(md, app, writtenBy, member, input) {
15
17
  return md.types(input[0]);
16
18
  case 'save':
17
19
  return md.save(input[0], input[1], writtenBy);
20
+ case 'saveParts':
21
+ return md.saveParts(input[0], input[1], writtenBy);
18
22
  case 'history':
19
23
  return md.history(input[0], input[1], input[2]);
24
+ case 'resolve':
25
+ return md.resolve(input[0], input[1], input[2]);
20
26
  case 'binaryFile.read':
21
27
  return md.binaryFile.read(input[0], input[1], input[2]);
22
- case 'binaryFile.readReference':
23
- return md.binaryFile.readReference(input[0]);
28
+ case 'binaryFile.link':
29
+ return md.binaryFile.link(input[0], input[1], input[2]);
30
+ case 'binaryFile.show':
31
+ return md.binaryFile.show(input[0], input[1], input[2]);
32
+ case 'binaryFile.attach':
33
+ return md.binaryFile.attach(input[0], input[1]);
34
+ case 'binaryFile.part':
35
+ return md.binaryFile.part(input[0], input[1]);
24
36
  case 'call':
25
37
  return md.call(input[0], input[1]);
26
38
  case 'reached':
27
39
  return md.reached(input[0], input[1], input[2]);
28
40
  case 'log':
29
41
  return md.log();
42
+ case 'cleanUp':
43
+ return md.cleanUp();
44
+ case 'unsent':
45
+ return md.unsent();
46
+ case 'reset':
47
+ return md.reset();
48
+ case 'readAgain':
49
+ return md.readAgain();
30
50
  case 'persistence':
31
51
  return md.persistence();
52
+ case 'retry':
53
+ return md.retry();
32
54
  case 'reauthorize':
33
55
  return md.reauthorize();
34
56
  case 'roomDraft.list':
@@ -36,13 +58,15 @@ function answered(md, app, writtenBy, member, input) {
36
58
  case 'roomDraft.read':
37
59
  return md.roomDraft.read(input[0], input[1]);
38
60
  case 'roomDraft.write':
39
- return md.roomDraft.write(input[0], input[1], input[2], input[3]);
61
+ return md.roomDraft.write(input[0], input[1], input[2], input[3], input[4]);
40
62
  case 'roomDraft.discard':
41
63
  return md.roomDraft.discard(input[0], input[1], input[2]);
42
64
  case 'presentation.read':
43
65
  return md.presentation.read(app);
44
66
  case 'presentation.write':
45
67
  return md.presentation.write(app, input[0]);
68
+ case 'presentation.edit':
69
+ return md.presentation.edit(app, input[0]);
46
70
  case 'conversation.list':
47
71
  return md.conversation.list();
48
72
  case 'conversation.read':
@@ -50,23 +74,36 @@ function answered(md, app, writtenBy, member, input) {
50
74
  case 'conversation.create':
51
75
  return md.conversation.create(input[0]);
52
76
  case 'conversation.send':
53
- return md.conversation.send(input[0]);
77
+ return md.conversation.send(input[0], input[1], input[2]);
54
78
  case 'conversation.answer':
55
79
  return md.conversation.answer(input[0], input[1]);
56
80
  case 'conversation.interrupt':
57
81
  return md.conversation.interrupt(input[0]);
58
82
  case 'conversation.kill':
59
83
  return md.conversation.kill(input[0]);
60
- case 'conversation.cancel':
61
- return md.conversation.cancel(input[0], input[1]);
62
84
  case 'conversation.delete':
63
85
  return md.conversation.delete(input[0]);
64
86
  case 'chatDraft.write':
65
87
  return md.chatDraft.write(input[0], input[1], input[2]);
88
+ case 'chatDraft.prepend':
89
+ return md.chatDraft.prepend(input[0], input[1]);
66
90
  case 'chatDraft.discard':
67
91
  return md.chatDraft.discard(input[0]);
68
92
  }
69
93
  }
94
+ function attempted(work) {
95
+ try {
96
+ return Promise.resolve(work());
97
+ }
98
+ catch (error) {
99
+ return Promise.reject(error);
100
+ }
101
+ }
102
+ function answeredMessage(value) {
103
+ if (typeof value !== 'object' || value === null)
104
+ return false;
105
+ return !('result' in value) || answeredResult(value.result);
106
+ }
70
107
  export function serveMdRuntime(options) {
71
108
  const deploymentFacts = structuredClone(options.deploymentFacts);
72
109
  const closing = new AbortController();
@@ -80,17 +117,30 @@ export function serveMdRuntime(options) {
80
117
  const { md } = runtime;
81
118
  const attachments = new Map();
82
119
  let authorized = true;
120
+ let opening = null;
121
+ const opened = () => (opening ??= untilAnswered(() => md.loaded(), closing.signal));
83
122
  const watchFacts = (deliver) => {
84
123
  deliver(structuredClone(deploymentFacts));
85
124
  return () => { };
86
125
  };
87
- function attach(port, app, release, reach) {
126
+ function attach(port, app, release, reach, code = 'stored') {
88
127
  if (!authorized)
89
128
  throw new Error(AUTHORIZATION_ENDED);
90
129
  const writtenBy = release === undefined ? undefined : { app, release };
91
- const view = runtime.within(reach ?? null);
130
+ const view = runtime.within(reach ?? null, { target: app, code });
92
131
  const observations = new Map();
132
+ const followed = new Set();
133
+ const answeredKeys = new Set();
134
+ let awaited = null;
93
135
  let serving = true;
136
+ const answeredQuery = (query) => {
137
+ answeredKeys.add(queryKey(query));
138
+ if (awaited === null || !awaited.keys.every((key) => answeredKeys.has(key)))
139
+ return;
140
+ const { done } = awaited;
141
+ awaited = null;
142
+ done();
143
+ };
94
144
  const send = (message) => {
95
145
  port.postMessage(message);
96
146
  };
@@ -101,6 +151,8 @@ export function serveMdRuntime(options) {
101
151
  for (const end of observations.values())
102
152
  end();
103
153
  observations.clear();
154
+ for (const end of [...followed])
155
+ end();
104
156
  attachments.delete(detach);
105
157
  };
106
158
  const observe = (id, topic, input) => {
@@ -110,10 +162,33 @@ export function serveMdRuntime(options) {
110
162
  return;
111
163
  send(resolved ? { kind: 'event', id, value } : { kind: 'result', id, value });
112
164
  resolved = true;
165
+ if (topic === 'query' && answeredMessage(value))
166
+ answeredQuery(input[0]);
167
+ };
168
+ const fail = (error) => {
169
+ if (!serving || resolved)
170
+ return;
171
+ observations.get(id)?.();
172
+ observations.delete(id);
173
+ send({ kind: 'failure', id, ...described(error) });
113
174
  };
114
175
  observations.set(id, topic === 'deployment-facts'
115
176
  ? watchFacts(deliver)
116
- : (NARROWED.has(WIRE_REACH.topics[topic]) ? view : runtime).watch(topic, topic === 'presentation' ? [app] : input, deliver));
177
+ : (NARROWED.has(WIRE.topics[topic]) ? view : runtime).watch(topic, topic === 'presentation' ? [app] : input, deliver, fail));
178
+ };
179
+ const reply = async (id, query, pending) => {
180
+ try {
181
+ const value = await pending;
182
+ if (!serving)
183
+ return;
184
+ send({ kind: 'result', id, value });
185
+ if (query !== undefined && answeredResult(value))
186
+ answeredQuery(query);
187
+ }
188
+ catch (error) {
189
+ if (serving)
190
+ send({ kind: 'failure', id, ...described(error) });
191
+ }
117
192
  };
118
193
  const serve = async (message) => {
119
194
  if (message.kind === 'hello')
@@ -124,21 +199,24 @@ export function serveMdRuntime(options) {
124
199
  return;
125
200
  }
126
201
  try {
127
- if (message.kind !== 'observe' || message.topic !== 'room-drafts')
202
+ if (message.kind !== 'observe')
128
203
  await md.loaded();
204
+ else if (message.topic !== 'room-drafts')
205
+ await opened();
129
206
  if (message.kind === 'observe') {
130
207
  if (serving)
131
208
  observe(message.id, message.topic, message.input);
132
209
  return;
133
210
  }
134
- const value = await answered(NARROWED.has(WIRE_REACH.members[message.member]) ? view.md : md, app, writtenBy, message.member, message.input);
135
- if (serving)
136
- send({ kind: 'result', id: message.id, value });
137
211
  }
138
212
  catch (error) {
139
213
  if (serving)
140
214
  send({ kind: 'failure', id: message.id, ...described(error) });
215
+ return;
141
216
  }
217
+ const { id, member, input } = message;
218
+ const pending = attempted(() => answered(NARROWED.has(WIRE.members[member].reach) ? view.md : md, app, writtenBy, member, input));
219
+ return reply(id, member === 'query' ? input[0] : undefined, pending);
142
220
  };
143
221
  port.addEventListener('message', (event) => {
144
222
  if (!serving)
@@ -157,10 +235,40 @@ export function serveMdRuntime(options) {
157
235
  if (serving)
158
236
  view.narrow(next);
159
237
  },
238
+ answered(queries, done) {
239
+ const keys = queries.map(queryKey);
240
+ if (keys.every((key) => answeredKeys.has(key)))
241
+ done();
242
+ else
243
+ awaited = { keys, done };
244
+ },
245
+ readiness(deliver) {
246
+ if (!serving)
247
+ return () => { };
248
+ const stop = view.watch('readiness', [], (value) => {
249
+ if (serving)
250
+ deliver(value);
251
+ }, () => { });
252
+ const end = () => {
253
+ followed.delete(end);
254
+ stop();
255
+ };
256
+ followed.add(end);
257
+ return end;
258
+ },
160
259
  };
161
260
  }
162
261
  return {
163
262
  attach,
263
+ present(app, members) {
264
+ return md.presentation.edit(app, members);
265
+ },
266
+ seed(entry) {
267
+ runtime.seed(entry);
268
+ },
269
+ persisted(answer) {
270
+ runtime.persisted(answer);
271
+ },
164
272
  async endAuthorization(holder) {
165
273
  authorized = false;
166
274
  for (const [detach, send] of [...attachments]) {
@@ -168,15 +276,14 @@ export function serveMdRuntime(options) {
168
276
  detach();
169
277
  }
170
278
  close();
171
- if (!(await removeRuntimeStore(holder)))
279
+ if (!(await options.database.ask({ kind: 'authored.end', holder: holder ?? null }))) {
172
280
  await options.shell.dropGeneration();
173
- },
174
- lose(locators) {
175
- return runtime.lose(locators);
281
+ }
176
282
  },
177
283
  stop() {
178
284
  return runtime.stop();
179
285
  },
180
286
  };
181
287
  }
182
- export { AUTHORED_SCHEMA, authoredBy, authoredHolder, STORE_SCHEMA } from './store.js';
288
+ export { entrySeedOf } from './seed.js';
289
+ export { createRecovery, retryDelay, } from './recovery.js';