@agentshouse/mdruntime 0.1.0-cedb03eaa48b6 → 0.1.0-cedd665dffa4c

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 (395) hide show
  1. package/README.md +24 -19
  2. package/dist/acceptance.d.ts +3 -0
  3. package/dist/acceptance.d.ts.map +1 -0
  4. package/dist/acceptance.js +299 -0
  5. package/dist/act-lanes.d.ts +30 -0
  6. package/dist/act-lanes.d.ts.map +1 -0
  7. package/dist/act-lanes.js +225 -0
  8. package/dist/actions.d.ts +26 -0
  9. package/dist/actions.d.ts.map +1 -0
  10. package/dist/actions.js +302 -0
  11. package/dist/adapter.d.ts +173 -125
  12. package/dist/adapter.d.ts.map +1 -1
  13. package/dist/attached-model.d.ts +6 -10
  14. package/dist/attached-model.d.ts.map +1 -1
  15. package/dist/attached-model.js +35 -41
  16. package/dist/binary.d.ts +0 -5
  17. package/dist/binary.d.ts.map +1 -1
  18. package/dist/binary.js +1 -1
  19. package/dist/bootstrap.d.ts +30 -11
  20. package/dist/bootstrap.d.ts.map +1 -1
  21. package/dist/bootstrap.js +309 -113
  22. package/dist/cell.d.ts +6 -0
  23. package/dist/cell.d.ts.map +1 -0
  24. package/dist/cell.js +9 -0
  25. package/dist/chain.d.ts +12 -0
  26. package/dist/chain.d.ts.map +1 -0
  27. package/dist/chain.js +64 -0
  28. package/dist/change-set.d.ts +13 -16
  29. package/dist/change-set.d.ts.map +1 -1
  30. package/dist/change-set.js +17 -89
  31. package/dist/change.d.ts +36 -1
  32. package/dist/change.d.ts.map +1 -1
  33. package/dist/change.js +17 -3
  34. package/dist/chat-types.d.ts +3 -0
  35. package/dist/chat-types.d.ts.map +1 -0
  36. package/dist/chat-types.js +11 -0
  37. package/dist/client.d.ts +37 -26
  38. package/dist/client.d.ts.map +1 -1
  39. package/dist/client.js +113 -23
  40. package/dist/collection.d.ts +32 -21
  41. package/dist/collection.d.ts.map +1 -1
  42. package/dist/collection.js +53 -318
  43. package/dist/compile.d.ts +18 -0
  44. package/dist/compile.d.ts.map +1 -0
  45. package/dist/compile.js +723 -0
  46. package/dist/connection.d.ts +7 -137
  47. package/dist/connection.d.ts.map +1 -1
  48. package/dist/connection.js +110 -3602
  49. package/dist/context.d.ts +2 -0
  50. package/dist/context.d.ts.map +1 -0
  51. package/dist/{chat/context.js → context.js} +2 -5
  52. package/dist/conversation-live.d.ts +150 -0
  53. package/dist/conversation-live.d.ts.map +1 -0
  54. package/dist/conversation-live.js +259 -0
  55. package/dist/conversation-row.d.ts +40 -0
  56. package/dist/conversation-row.d.ts.map +1 -0
  57. package/dist/conversation-row.js +66 -0
  58. package/dist/conversation.d.ts +75 -49
  59. package/dist/conversation.d.ts.map +1 -1
  60. package/dist/conversation.js +1029 -806
  61. package/dist/declaration.d.ts +10 -0
  62. package/dist/declaration.d.ts.map +1 -0
  63. package/dist/declaration.js +24 -0
  64. package/dist/digest.d.ts +7 -0
  65. package/dist/digest.d.ts.map +1 -0
  66. package/dist/digest.js +113 -0
  67. package/dist/discovery.d.ts +10 -0
  68. package/dist/discovery.d.ts.map +1 -0
  69. package/dist/discovery.js +150 -0
  70. package/dist/durability.d.ts +20 -4
  71. package/dist/durability.d.ts.map +1 -1
  72. package/dist/durability.js +9 -0
  73. package/dist/entry.d.ts +5 -2
  74. package/dist/entry.d.ts.map +1 -1
  75. package/dist/entry.js +33 -29
  76. package/dist/expectation.d.ts +26 -13
  77. package/dist/expectation.d.ts.map +1 -1
  78. package/dist/expectation.js +72 -19
  79. package/dist/failure.d.ts +3 -0
  80. package/dist/failure.d.ts.map +1 -1
  81. package/dist/failure.js +6 -0
  82. package/dist/figures.d.ts +49 -0
  83. package/dist/figures.d.ts.map +1 -0
  84. package/dist/figures.js +199 -0
  85. package/dist/file.d.ts +2 -19
  86. package/dist/file.d.ts.map +1 -1
  87. package/dist/file.js +8 -122
  88. package/dist/holdings.d.ts +29 -0
  89. package/dist/holdings.d.ts.map +1 -0
  90. package/dist/holdings.js +95 -0
  91. package/dist/host.d.ts +21 -8
  92. package/dist/host.d.ts.map +1 -1
  93. package/dist/host.js +119 -51
  94. package/dist/identity.d.ts +0 -2
  95. package/dist/identity.d.ts.map +1 -1
  96. package/dist/identity.js +0 -6
  97. package/dist/index.d.ts +41 -16
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +19 -4
  100. package/dist/install.d.ts +60 -0
  101. package/dist/install.d.ts.map +1 -0
  102. package/dist/install.js +537 -0
  103. package/dist/lifecycle.d.ts +7 -0
  104. package/dist/lifecycle.d.ts.map +1 -0
  105. package/dist/lifecycle.js +278 -0
  106. package/dist/listing.d.ts +52 -0
  107. package/dist/listing.d.ts.map +1 -0
  108. package/dist/listing.js +152 -0
  109. package/dist/live.d.ts +25 -0
  110. package/dist/live.d.ts.map +1 -0
  111. package/dist/live.js +206 -0
  112. package/dist/loaded.d.ts +5 -0
  113. package/dist/loaded.d.ts.map +1 -0
  114. package/dist/loaded.js +40 -0
  115. package/dist/locks.d.ts +7 -0
  116. package/dist/locks.d.ts.map +1 -0
  117. package/dist/locks.js +32 -0
  118. package/dist/lost.d.ts +5 -0
  119. package/dist/lost.d.ts.map +1 -0
  120. package/dist/lost.js +49 -0
  121. package/dist/media.d.ts +13 -0
  122. package/dist/media.d.ts.map +1 -0
  123. package/dist/media.js +269 -0
  124. package/dist/memory.d.ts +19 -7
  125. package/dist/memory.d.ts.map +1 -1
  126. package/dist/memory.js +281 -118
  127. package/dist/messages.d.ts +58 -0
  128. package/dist/messages.d.ts.map +1 -0
  129. package/dist/messages.js +162 -0
  130. package/dist/model.d.ts +8 -11
  131. package/dist/model.d.ts.map +1 -1
  132. package/dist/model.js +6 -23
  133. package/dist/models.d.ts +10 -0
  134. package/dist/models.d.ts.map +1 -0
  135. package/dist/models.js +153 -0
  136. package/dist/name.d.ts +4 -0
  137. package/dist/name.d.ts.map +1 -0
  138. package/dist/name.js +122 -0
  139. package/dist/observation.d.ts +38 -10
  140. package/dist/observation.d.ts.map +1 -1
  141. package/dist/observation.js +232 -44
  142. package/dist/opened.d.ts +22 -0
  143. package/dist/opened.d.ts.map +1 -0
  144. package/dist/opened.js +107 -0
  145. package/dist/opening.d.ts +4 -0
  146. package/dist/opening.d.ts.map +1 -0
  147. package/dist/opening.js +53 -0
  148. package/dist/outcome.d.ts +51 -9
  149. package/dist/outcome.d.ts.map +1 -1
  150. package/dist/outcome.js +62 -2
  151. package/dist/overlay.d.ts +8 -6
  152. package/dist/overlay.d.ts.map +1 -1
  153. package/dist/overlay.js +121 -182
  154. package/dist/page-metadata.d.ts +8 -0
  155. package/dist/page-metadata.d.ts.map +1 -0
  156. package/dist/page-metadata.js +19 -0
  157. package/dist/parts.d.ts +4 -0
  158. package/dist/parts.d.ts.map +1 -0
  159. package/dist/parts.js +13 -0
  160. package/dist/paths.d.ts +2 -0
  161. package/dist/paths.d.ts.map +1 -1
  162. package/dist/paths.js +26 -0
  163. package/dist/preparation.d.ts +41 -0
  164. package/dist/preparation.d.ts.map +1 -0
  165. package/dist/preparation.js +314 -0
  166. package/dist/presence.d.ts +58 -0
  167. package/dist/presence.d.ts.map +1 -0
  168. package/dist/presence.js +231 -0
  169. package/dist/queries.d.ts +16 -0
  170. package/dist/queries.d.ts.map +1 -0
  171. package/dist/queries.js +308 -0
  172. package/dist/query.d.ts +21 -207
  173. package/dist/query.d.ts.map +1 -1
  174. package/dist/query.js +3 -493
  175. package/dist/{chat/questions.d.ts → questions.d.ts} +5 -7
  176. package/dist/questions.d.ts.map +1 -0
  177. package/dist/{chat/questions.js → questions.js} +11 -7
  178. package/dist/queue.d.ts +40 -0
  179. package/dist/queue.d.ts.map +1 -0
  180. package/dist/queue.js +480 -0
  181. package/dist/reach.d.ts +21 -11
  182. package/dist/reach.d.ts.map +1 -1
  183. package/dist/reach.js +342 -112
  184. package/dist/react.d.ts +17 -3
  185. package/dist/react.d.ts.map +1 -1
  186. package/dist/react.js +33 -1
  187. package/dist/{chat/read.d.ts → read.d.ts} +2 -0
  188. package/dist/read.d.ts.map +1 -0
  189. package/dist/{chat/read.js → read.js} +4 -0
  190. package/dist/readiness.d.ts +22 -20
  191. package/dist/readiness.d.ts.map +1 -1
  192. package/dist/readiness.js +5 -13
  193. package/dist/reads.d.ts +38 -10
  194. package/dist/reads.d.ts.map +1 -1
  195. package/dist/reads.js +163 -83
  196. package/dist/recovery.d.ts +5 -2
  197. package/dist/recovery.d.ts.map +1 -1
  198. package/dist/recovery.js +65 -8
  199. package/dist/refresh.d.ts +18 -15
  200. package/dist/refresh.d.ts.map +1 -1
  201. package/dist/refresh.js +145 -60
  202. package/dist/refusal.d.ts +5 -0
  203. package/dist/refusal.d.ts.map +1 -0
  204. package/dist/refusal.js +55 -0
  205. package/dist/replica.d.ts +49 -36
  206. package/dist/replica.d.ts.map +1 -1
  207. package/dist/replica.js +322 -198
  208. package/dist/retried.d.ts +30 -0
  209. package/dist/retried.d.ts.map +1 -0
  210. package/dist/retried.js +72 -0
  211. package/dist/room-draft.d.ts +55 -13
  212. package/dist/room-draft.d.ts.map +1 -1
  213. package/dist/room-draft.js +416 -122
  214. package/dist/room-drafts.d.ts +24 -0
  215. package/dist/room-drafts.d.ts.map +1 -0
  216. package/dist/room-drafts.js +220 -0
  217. package/dist/rows.d.ts +32 -31
  218. package/dist/rows.d.ts.map +1 -1
  219. package/dist/rows.js +59 -124
  220. package/dist/runtime.d.ts +34 -0
  221. package/dist/runtime.d.ts.map +1 -0
  222. package/dist/runtime.js +1 -0
  223. package/dist/save.d.ts +43 -49
  224. package/dist/save.d.ts.map +1 -1
  225. package/dist/save.js +736 -302
  226. package/dist/saves.d.ts +32 -0
  227. package/dist/saves.d.ts.map +1 -0
  228. package/dist/saves.js +426 -0
  229. package/dist/search.d.ts +12 -95
  230. package/dist/search.d.ts.map +1 -1
  231. package/dist/search.js +10 -266
  232. package/dist/seed.d.ts +11 -2
  233. package/dist/seed.d.ts.map +1 -1
  234. package/dist/seed.js +71 -1
  235. package/dist/shared.d.ts +6 -7
  236. package/dist/shared.d.ts.map +1 -1
  237. package/dist/shared.js +75 -104
  238. package/dist/shown.d.ts +33 -0
  239. package/dist/shown.d.ts.map +1 -0
  240. package/dist/shown.js +309 -0
  241. package/dist/socket/admission.d.ts +7 -0
  242. package/dist/socket/admission.d.ts.map +1 -0
  243. package/dist/socket/admission.js +39 -0
  244. package/dist/socket/answers.d.ts +6 -0
  245. package/dist/socket/answers.d.ts.map +1 -0
  246. package/dist/socket/answers.js +20 -0
  247. package/dist/socket/lanes.d.ts +28 -0
  248. package/dist/socket/lanes.d.ts.map +1 -0
  249. package/dist/socket/lanes.js +103 -0
  250. package/dist/socket/reads.d.ts +10 -0
  251. package/dist/socket/reads.d.ts.map +1 -0
  252. package/dist/socket/reads.js +31 -0
  253. package/dist/socket/session.d.ts +38 -0
  254. package/dist/socket/session.d.ts.map +1 -0
  255. package/dist/socket/session.js +23 -0
  256. package/dist/socket.d.ts +67 -0
  257. package/dist/socket.d.ts.map +1 -0
  258. package/dist/socket.js +164 -0
  259. package/dist/source.d.ts +59 -0
  260. package/dist/source.d.ts.map +1 -0
  261. package/dist/source.js +93 -0
  262. package/dist/status.d.ts +4 -5
  263. package/dist/status.d.ts.map +1 -1
  264. package/dist/status.js +3 -7
  265. package/dist/store/installs.d.ts +30 -0
  266. package/dist/store/installs.d.ts.map +1 -0
  267. package/dist/store/installs.js +40 -0
  268. package/dist/store/readiness.d.ts +11 -0
  269. package/dist/store/readiness.d.ts.map +1 -0
  270. package/dist/store/readiness.js +68 -0
  271. package/dist/store/records.d.ts +217 -0
  272. package/dist/store/records.d.ts.map +1 -0
  273. package/dist/store/records.js +464 -0
  274. package/dist/store/room-held.d.ts +8 -0
  275. package/dist/store/room-held.d.ts.map +1 -0
  276. package/dist/store/room-held.js +17 -0
  277. package/dist/store/rooms-shown.d.ts +8 -0
  278. package/dist/store/rooms-shown.d.ts.map +1 -0
  279. package/dist/store/rooms-shown.js +13 -0
  280. package/dist/store/space.d.ts +11 -0
  281. package/dist/store/space.d.ts.map +1 -0
  282. package/dist/store/space.js +41 -0
  283. package/dist/store/watchers.d.ts +17 -0
  284. package/dist/store/watchers.d.ts.map +1 -0
  285. package/dist/store/watchers.js +56 -0
  286. package/dist/store/writes.d.ts +24 -0
  287. package/dist/store/writes.d.ts.map +1 -0
  288. package/dist/store/writes.js +125 -0
  289. package/dist/store.d.ts +114 -163
  290. package/dist/store.d.ts.map +1 -1
  291. package/dist/store.js +163 -750
  292. package/dist/stored.d.ts +167 -0
  293. package/dist/stored.d.ts.map +1 -0
  294. package/dist/stored.js +703 -0
  295. package/dist/surface.d.ts +89 -0
  296. package/dist/surface.d.ts.map +1 -0
  297. package/dist/surface.js +222 -0
  298. package/dist/sync.d.ts +19 -0
  299. package/dist/sync.d.ts.map +1 -0
  300. package/dist/sync.js +535 -0
  301. package/dist/tables.d.ts +419 -0
  302. package/dist/tables.d.ts.map +1 -0
  303. package/dist/tables.js +758 -0
  304. package/dist/tallies.d.ts +18 -0
  305. package/dist/tallies.d.ts.map +1 -0
  306. package/dist/tallies.js +128 -0
  307. package/dist/transfer.d.ts +0 -5
  308. package/dist/transfer.d.ts.map +1 -1
  309. package/dist/turn.d.ts +4 -2
  310. package/dist/turn.d.ts.map +1 -1
  311. package/dist/turn.js +46 -22
  312. package/dist/validation.d.ts +29 -0
  313. package/dist/validation.d.ts.map +1 -0
  314. package/dist/validation.js +98 -0
  315. package/dist/windows.d.ts +1 -16
  316. package/dist/windows.d.ts.map +1 -1
  317. package/dist/windows.js +2 -79
  318. package/dist/wire.d.ts +74 -9
  319. package/dist/wire.d.ts.map +1 -1
  320. package/dist/wire.js +26 -6
  321. package/package.json +19 -19
  322. package/AGENTS.md +0 -305
  323. package/dist/attempt.d.ts +0 -16
  324. package/dist/attempt.d.ts.map +0 -1
  325. package/dist/attempt.js +0 -70
  326. package/dist/chat/acts.d.ts +0 -33
  327. package/dist/chat/acts.d.ts.map +0 -1
  328. package/dist/chat/acts.js +0 -36
  329. package/dist/chat/context.d.ts +0 -3
  330. package/dist/chat/context.d.ts.map +0 -1
  331. package/dist/chat/earlier.d.ts +0 -10
  332. package/dist/chat/earlier.d.ts.map +0 -1
  333. package/dist/chat/earlier.js +0 -54
  334. package/dist/chat/input.d.ts +0 -9
  335. package/dist/chat/input.d.ts.map +0 -1
  336. package/dist/chat/input.js +0 -99
  337. package/dist/chat/kit.d.ts +0 -61
  338. package/dist/chat/kit.d.ts.map +0 -1
  339. package/dist/chat/kit.js +0 -123
  340. package/dist/chat/lasting.d.ts +0 -6
  341. package/dist/chat/lasting.d.ts.map +0 -1
  342. package/dist/chat/lasting.js +0 -19
  343. package/dist/chat/list.d.ts +0 -27
  344. package/dist/chat/list.d.ts.map +0 -1
  345. package/dist/chat/list.js +0 -99
  346. package/dist/chat/markdown.d.ts +0 -20
  347. package/dist/chat/markdown.d.ts.map +0 -1
  348. package/dist/chat/markdown.js +0 -188
  349. package/dist/chat/message.d.ts +0 -6
  350. package/dist/chat/message.d.ts.map +0 -1
  351. package/dist/chat/message.js +0 -192
  352. package/dist/chat/messages.d.ts +0 -22
  353. package/dist/chat/messages.d.ts.map +0 -1
  354. package/dist/chat/messages.js +0 -155
  355. package/dist/chat/name.d.ts +0 -6
  356. package/dist/chat/name.d.ts.map +0 -1
  357. package/dist/chat/name.js +0 -37
  358. package/dist/chat/opened.d.ts +0 -11
  359. package/dist/chat/opened.d.ts.map +0 -1
  360. package/dist/chat/opened.js +0 -17
  361. package/dist/chat/overlay.d.ts +0 -31
  362. package/dist/chat/overlay.d.ts.map +0 -1
  363. package/dist/chat/overlay.js +0 -97
  364. package/dist/chat/parts.d.ts +0 -57
  365. package/dist/chat/parts.d.ts.map +0 -1
  366. package/dist/chat/parts.js +0 -119
  367. package/dist/chat/process.d.ts +0 -20
  368. package/dist/chat/process.d.ts.map +0 -1
  369. package/dist/chat/process.js +0 -32
  370. package/dist/chat/provider.d.ts +0 -63
  371. package/dist/chat/provider.d.ts.map +0 -1
  372. package/dist/chat/provider.js +0 -628
  373. package/dist/chat/question.d.ts +0 -9
  374. package/dist/chat/question.d.ts.map +0 -1
  375. package/dist/chat/question.js +0 -69
  376. package/dist/chat/questions.d.ts.map +0 -1
  377. package/dist/chat/read.d.ts.map +0 -1
  378. package/dist/chat/ready.d.ts +0 -34
  379. package/dist/chat/ready.d.ts.map +0 -1
  380. package/dist/chat/ready.js +0 -91
  381. package/dist/chat/style.d.ts +0 -4
  382. package/dist/chat/style.d.ts.map +0 -1
  383. package/dist/chat/style.js +0 -302
  384. package/dist/chat.d.ts +0 -14
  385. package/dist/chat.d.ts.map +0 -1
  386. package/dist/chat.js +0 -8
  387. package/dist/fence.d.ts +0 -6
  388. package/dist/fence.d.ts.map +0 -1
  389. package/dist/fence.js +0 -10
  390. package/dist/log.d.ts +0 -5
  391. package/dist/log.d.ts.map +0 -1
  392. package/dist/log.js +0 -14
  393. package/dist/read-side.d.ts +0 -27
  394. package/dist/read-side.d.ts.map +0 -1
  395. package/dist/read-side.js +0 -824
package/dist/live.js ADDED
@@ -0,0 +1,206 @@
1
+ import { changeOf, digestOf, keyedAt, keyedInto, samePending, unchanged, } from './observation.js';
2
+ import { uncaught } from './failure.js';
3
+ import { roomsOfReach } from './rows.js';
4
+ function narrowed(plan) {
5
+ return (plan.paths !== null &&
6
+ plan.hop === null &&
7
+ plan.backlinks === null &&
8
+ !(plan.shape.kind === 'documents' && plan.shape.backlinks));
9
+ }
10
+ export function readerOf(plan) {
11
+ const locked = new Set(plan.locked);
12
+ const named = plan.rooms === null ? null : new Set(plan.rooms);
13
+ const reached = plan.reach === null ? null : roomsOfReach(plan.reach);
14
+ return (locator) => !locked.has(locator) &&
15
+ (named === null || named.has(locator)) &&
16
+ (reached === null || reached.has(locator));
17
+ }
18
+ function affected({ plan, reads }, set) {
19
+ if (set.rooms.some(reads))
20
+ return true;
21
+ const paths = narrowed(plan) ? new Set(plan.paths) : null;
22
+ return set.documents.some(({ locator, path }) => reads(locator) && (paths === null || path === null || paths.has(path)));
23
+ }
24
+ function shown(entry, held) {
25
+ const cover = entry.cover(held);
26
+ return JSON.stringify('pending' in cover ? cover : cover.coverage);
27
+ }
28
+ export function createLiveQueries(run, holding) {
29
+ const entries = new Map();
30
+ let closed = false;
31
+ let recoveringNow = false;
32
+ let recoveringAll = false;
33
+ const recovering = new Set();
34
+ function deliver(entry, next) {
35
+ const previous = entry.digest;
36
+ entry.digest = digestOf(next);
37
+ entry.pending = 'pending' in entry.digest ? entry.digest.pending : null;
38
+ entry.covered = JSON.stringify('pending' in next.result ? next.result : next.result.coverage);
39
+ const change = previous === undefined ? null : changeOf(previous, next);
40
+ if (change !== null) {
41
+ for (const listener of entry.ready)
42
+ listener(change);
43
+ }
44
+ for (const listener of entry.fresh.keys()) {
45
+ entry.ready.add(listener);
46
+ listener(next);
47
+ }
48
+ entry.fresh.clear();
49
+ }
50
+ async function delivered(entry) {
51
+ const { current, ...next } = await run(entry.plan, async () => entry.cover(await holding()));
52
+ if (closed || entry.listeners.size === 0)
53
+ return null;
54
+ deliver(entry, next);
55
+ return current;
56
+ }
57
+ function schedule(entry) {
58
+ if (closed || entry.listeners.size === 0)
59
+ return;
60
+ if (entry.running) {
61
+ entry.dirty = true;
62
+ return;
63
+ }
64
+ entry.running = true;
65
+ void (async () => {
66
+ try {
67
+ for (;;) {
68
+ entry.dirty = false;
69
+ const current = await delivered(entry);
70
+ if (current === null)
71
+ return;
72
+ const held = await holding();
73
+ if (entry.fresh.size > 0 || (entry.dirty && !current()))
74
+ continue;
75
+ if (shown(entry, held) === entry.covered)
76
+ break;
77
+ }
78
+ }
79
+ catch (error) {
80
+ const unanswered = [...entry.fresh.values()];
81
+ entry.fresh.clear();
82
+ for (const failed of unanswered)
83
+ failed(error);
84
+ }
85
+ finally {
86
+ entry.running = false;
87
+ }
88
+ })();
89
+ }
90
+ function pendingMoved(entry, held, rooms) {
91
+ const { pending } = entry;
92
+ if (pending === null || pending.size === 0 || entry.running || entry.fresh.size > 0) {
93
+ return false;
94
+ }
95
+ const at = entry.pendingAt(held, rooms);
96
+ const change = at === null ? null : keyedAt(pending, at, samePending);
97
+ if (change === null || change.removed.length === pending.size)
98
+ return false;
99
+ keyedInto(pending, change);
100
+ entry.covered = '';
101
+ if (unchanged(change))
102
+ return true;
103
+ for (const listener of entry.ready)
104
+ listener({ pending: change });
105
+ return true;
106
+ }
107
+ function recovered(locators) {
108
+ if (locators === undefined)
109
+ recoveringAll = true;
110
+ else
111
+ for (const locator of locators)
112
+ recovering.add(locator);
113
+ if (recoveringNow)
114
+ return;
115
+ recoveringNow = true;
116
+ void (async () => {
117
+ try {
118
+ while ((recoveringAll || recovering.size > 0) && !closed) {
119
+ const all = recoveringAll;
120
+ const touched = [...recovering];
121
+ recoveringAll = false;
122
+ recovering.clear();
123
+ const reached = [...entries.values()].filter((entry) => all || touched.some(entry.reads));
124
+ for (const entry of reached) {
125
+ if (entry.running)
126
+ entry.dirty = true;
127
+ }
128
+ const waiting = reached.filter((entry) => !entry.running);
129
+ if (waiting.length === 0)
130
+ continue;
131
+ const held = await holding();
132
+ for (const entry of waiting) {
133
+ if (entry.running)
134
+ continue;
135
+ const read = all ? [] : touched.filter(entry.reads);
136
+ if (read.length > 0 && pendingMoved(entry, held, read))
137
+ continue;
138
+ if (entry.digest === undefined || shown(entry, held) !== entry.covered)
139
+ schedule(entry);
140
+ }
141
+ }
142
+ }
143
+ catch (error) {
144
+ uncaught(error);
145
+ }
146
+ finally {
147
+ recoveringNow = false;
148
+ }
149
+ })();
150
+ }
151
+ return {
152
+ touched(set) {
153
+ const pending = new Set();
154
+ for (const entry of entries.values()) {
155
+ if (!affected(entry, set))
156
+ continue;
157
+ if (entry.pending === null || entry.running) {
158
+ schedule(entry);
159
+ continue;
160
+ }
161
+ for (const locator of set.rooms)
162
+ pending.add(locator);
163
+ for (const { locator } of set.documents)
164
+ pending.add(locator);
165
+ }
166
+ if (pending.size > 0)
167
+ recovered([...pending]);
168
+ },
169
+ recover: recovered,
170
+ watch(plan, identity, cover, pendingAt, listener, failed) {
171
+ let entry = entries.get(identity);
172
+ if (entry === undefined) {
173
+ entry = {
174
+ plan,
175
+ reads: readerOf(plan),
176
+ cover,
177
+ pendingAt,
178
+ listeners: new Set(),
179
+ fresh: new Map(),
180
+ ready: new Set(),
181
+ digest: undefined,
182
+ pending: null,
183
+ covered: '',
184
+ dirty: false,
185
+ running: false,
186
+ };
187
+ entries.set(identity, entry);
188
+ }
189
+ const held = entry;
190
+ held.listeners.add(listener);
191
+ held.fresh.set(listener, failed);
192
+ schedule(held);
193
+ return () => {
194
+ held.listeners.delete(listener);
195
+ held.fresh.delete(listener);
196
+ held.ready.delete(listener);
197
+ if (held.listeners.size === 0 && entries.get(identity) === held)
198
+ entries.delete(identity);
199
+ };
200
+ },
201
+ close() {
202
+ closed = true;
203
+ entries.clear();
204
+ },
205
+ };
206
+ }
@@ -0,0 +1,5 @@
1
+ import type { BuildFile } from './client.js';
2
+ export declare function parsed(file: Blob | null): Promise<unknown>;
3
+ export declare function perBuild<T>(buildFile: BuildFile, key: string, make: () => Promise<T>): Promise<T>;
4
+ export declare function loaded<T>(buildFile: BuildFile, name: string, read?: (file: Blob | null) => Promise<unknown>): Promise<T | null>;
5
+ //# sourceMappingURL=loaded.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loaded.d.ts","sourceRoot":"","sources":["../src/loaded.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAc7C,wBAAsB,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAEhE;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAYjG;AAED,wBAAgB,MAAM,CAAC,CAAC,EACtB,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC,OAAO,CAAY,GACvD,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAEnB"}
package/dist/loaded.js ADDED
@@ -0,0 +1,40 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ const holdings = new WeakMap();
10
+ async function imported(file) {
11
+ if (file === null)
12
+ return null;
13
+ const address = URL.createObjectURL(file);
14
+ try {
15
+ return await import(__rewriteRelativeImportExtension(address));
16
+ }
17
+ finally {
18
+ URL.revokeObjectURL(address);
19
+ }
20
+ }
21
+ export async function parsed(file) {
22
+ return file === null ? null : JSON.parse(await file.text());
23
+ }
24
+ export function perBuild(buildFile, key, make) {
25
+ let named = holdings.get(buildFile);
26
+ if (named === undefined) {
27
+ named = new Map();
28
+ holdings.set(buildFile, named);
29
+ }
30
+ const holding = named.get(key);
31
+ if (holding !== undefined)
32
+ return holding;
33
+ const making = make();
34
+ named.set(key, making);
35
+ making.catch(() => named.delete(key));
36
+ return making;
37
+ }
38
+ export function loaded(buildFile, name, read = imported) {
39
+ return perBuild(buildFile, name, () => buildFile(name).then(read));
40
+ }
@@ -0,0 +1,7 @@
1
+ import type { Runtime } from './runtime.js';
2
+ export declare function locked({ store, presence }: Runtime, locator: string): Promise<boolean>;
3
+ export declare function lockedRooms({ store, presence }: Runtime): Promise<readonly string[]>;
4
+ export declare function relocked(runtime: Runtime, before: readonly string[]): Promise<void>;
5
+ export declare function connectionLost(runtime: Runtime): void;
6
+ export declare function watchLocks({ store }: Runtime, notify: () => void): () => void;
7
+ //# sourceMappingURL=locks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locks.d.ts","sourceRoot":"","sources":["../src/locks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5C,wBAAsB,MAAM,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE5F;AAED,wBAAsB,WAAW,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAG1F;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,iBAKzE;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,QAU9C;AAED,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAE7E"}
package/dist/locks.js ADDED
@@ -0,0 +1,32 @@
1
+ import { uncaught } from './failure.js';
2
+ import { emitRooms, LOCKS_TOPIC } from './shown.js';
3
+ export async function locked({ store, presence }, locator) {
4
+ return presence.locked(locator, async () => (await store.open()).offline(locator));
5
+ }
6
+ export async function lockedRooms({ store, presence }) {
7
+ const { rooms, locking } = await store.covering();
8
+ return presence.lockedAmong(rooms, locking);
9
+ }
10
+ export async function relocked(runtime, before) {
11
+ const after = await lockedRooms(runtime);
12
+ if (JSON.stringify(after) === JSON.stringify(before))
13
+ return;
14
+ emitRooms(runtime);
15
+ runtime.store.tell(LOCKS_TOPIC, undefined);
16
+ }
17
+ export function connectionLost(runtime) {
18
+ const { socket, presence } = runtime;
19
+ if (socket.closed())
20
+ return;
21
+ presence.connectionLost(() => {
22
+ if (socket.isOpen() || socket.closed())
23
+ return;
24
+ void lockedRooms(runtime).then((before) => {
25
+ presence.lapse();
26
+ return relocked(runtime, before);
27
+ }, uncaught);
28
+ });
29
+ }
30
+ export function watchLocks({ store }, notify) {
31
+ return store.watch(LOCKS_TOPIC, notify).stop;
32
+ }
package/dist/lost.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import type { Runtime } from './runtime.js';
2
+ export declare function eraseFenced({ store }: Runtime, locators: readonly string[]): Promise<void>;
3
+ export declare function fenceLive(runtime: Runtime, locators: readonly string[]): void;
4
+ export declare function loseRooms(runtime: Runtime, locators: readonly string[]): Promise<void>;
5
+ //# sourceMappingURL=lost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lost.d.ts","sourceRoot":"","sources":["../src/lost.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAK5C,wBAAsB,WAAW,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,iBAIhF;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,QAMtE;AAED,wBAAsB,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,iBA+B5E"}
package/dist/lost.js ADDED
@@ -0,0 +1,49 @@
1
+ import { changeSet, mergeChangeSets } from './change-set.js';
2
+ import { ERASE_BATCH } from './install.js';
3
+ import { unpair } from './queue.js';
4
+ import { recoverReads } from './shown.js';
5
+ import { yielded } from './turn.js';
6
+ export async function eraseFenced({ store }, locators) {
7
+ for (const locator of locators) {
8
+ while (await store.durably((local) => local.erase(locator, ERASE_BATCH)))
9
+ await yielded();
10
+ }
11
+ }
12
+ export function fenceLive(runtime, locators) {
13
+ const { store, socket, presence } = runtime;
14
+ for (const locator of new Set(locators)) {
15
+ if (!presence.lose(locator, socket.session.now().discoveries))
16
+ continue;
17
+ store.forget(locator);
18
+ }
19
+ }
20
+ export async function loseRooms(runtime, locators) {
21
+ const { store, presence } = runtime;
22
+ fenceLive(runtime, locators);
23
+ const fresh = [...new Set(locators)].filter((locator) => presence.writing(locator));
24
+ if (fresh.length === 0)
25
+ return;
26
+ let held = [];
27
+ try {
28
+ await store.durably(async (local) => {
29
+ held = await local.roomDrafts();
30
+ await local.fence(fresh);
31
+ });
32
+ }
33
+ catch (error) {
34
+ for (const locator of fresh)
35
+ presence.unwritten(locator);
36
+ throw error;
37
+ }
38
+ finally {
39
+ store.changed(mergeChangeSets(fresh.map((locator) => changeSet(locator, {
40
+ documents: null,
41
+ room: true,
42
+ queue: true,
43
+ drafts: held.filter((draft) => draft.locator === locator).map(({ path }) => path),
44
+ }))));
45
+ recoverReads(runtime, fresh);
46
+ }
47
+ await unpair(runtime);
48
+ await eraseFenced(runtime, fresh);
49
+ }
@@ -0,0 +1,13 @@
1
+ import type { MdRuntimeClient } from './client.js';
2
+ import { type ShownAnswer } from './outcome.js';
3
+ export declare const ROOM_MEDIA = "room-media";
4
+ export declare const DIAGRAM = "md-diagram";
5
+ export declare const VIEWING = "ahc-viewer";
6
+ type Show = (room: string, path: string, revision?: string) => Promise<ShownAnswer>;
7
+ export declare function shownBy(show: Show, client: MdRuntimeClient): MdRuntimeClient;
8
+ export declare function rendered(element: Element): boolean;
9
+ export declare function viewable(element: Element): boolean;
10
+ export declare function viewFile(client: MdRuntimeClient, media: Element): void;
11
+ export declare function defineRoomMedia(client: Promise<MdRuntimeClient> | MdRuntimeClient): void;
12
+ export {};
13
+ //# sourceMappingURL=media.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAEnE,eAAO,MAAM,UAAU,eAAe,CAAC;AAMvC,eAAO,MAAM,OAAO,eAAe,CAAC;AAEpC,eAAO,MAAM,OAAO,eAAe,CAAC;AA8BpC,KAAK,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;AAIpF,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,GAAG,eAAe,CAG5E;AAsBD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAElD;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAMlD;AA4BD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAEtE;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,GAAG,IAAI,CAkMxF"}
package/dist/media.js ADDED
@@ -0,0 +1,269 @@
1
+ import { isAudioType, isImageType, isVideoType } from '@agentshouse/mdmodel';
2
+ import { loaded } from './loaded.js';
3
+ import { blobOf, UNCERTAIN } from './outcome.js';
4
+ export const ROOM_MEDIA = 'room-media';
5
+ const VIEWER = 'viewer';
6
+ const RENDERED = '.ahc, .ahc-markdown';
7
+ export const DIAGRAM = 'md-diagram';
8
+ export const VIEWING = 'ahc-viewer';
9
+ const PRESSED_ELSEWHERE = 'a[href], button, input, select, textarea, summary, label, [role="button"], [role="link"]';
10
+ const ATTRIBUTES = ['room', 'path', 'revision', 'width', 'height', 'alt'];
11
+ const LOADING = new Set(['room', 'path', 'revision']);
12
+ const NEARING = '600px 0px';
13
+ const RELINKS = 2;
14
+ // The Room's stream brings a file seconds after the text that links it, minutes after on a first open, and a page's reach of its Rooms settles seconds after it opens, so a file not shown yet is asked for again every three seconds.
15
+ const UNSHOWN_MS = 3_000;
16
+ const SHAPE = '16 / 9';
17
+ const STYLE = `:host{display:block}
18
+ [part=box]{position:relative;overflow:hidden}
19
+ [part=box]>img,[part=box]>video,[part=box]>audio{display:block;width:100%;height:100%;object-fit:contain}
20
+ [part=box]>video:not([controls]){cursor:pointer}
21
+ [part=box]>slot{display:flex;align-items:center;justify-content:center;width:100%;height:100%;text-align:center}
22
+ [part=play]{position:absolute;top:50%;left:50%;width:56px;height:56px;margin:-28px 0 0 -28px;border-radius:50%;background:rgb(0 0 0/.6);pointer-events:none}
23
+ [part=play]::before{content:"";position:absolute;top:18px;left:22px;border-style:solid;border-width:10px 0 10px 16px;border-color:transparent transparent transparent #fff}`;
24
+ const shows = new WeakMap();
25
+ export function shownBy(show, client) {
26
+ shows.set(client, show);
27
+ return client;
28
+ }
29
+ function ratioOf(width, height) {
30
+ const across = Number(width);
31
+ const down = Number(height);
32
+ return Number.isFinite(across) && Number.isFinite(down) && across > 0 && down > 0
33
+ ? `${across} / ${down}`
34
+ : SHAPE;
35
+ }
36
+ function refusedForGood(shown) {
37
+ if (shown.kind === 'revoked-authorization')
38
+ return true;
39
+ return (shown.kind === 'rejected' || shown.kind === 'scoped-refusal') && !shown.retryable;
40
+ }
41
+ function drawnFor(mediaType) {
42
+ if (isImageType(mediaType))
43
+ return 'img';
44
+ if (isVideoType(mediaType))
45
+ return 'video';
46
+ if (isAudioType(mediaType))
47
+ return 'audio';
48
+ return null;
49
+ }
50
+ export function rendered(element) {
51
+ return element.closest(RENDERED) !== null;
52
+ }
53
+ export function viewable(element) {
54
+ if (element.localName === 'figure')
55
+ return element.classList.contains(DIAGRAM);
56
+ if (element.localName !== ROOM_MEDIA || element.closest(`.${VIEWING}`) !== null)
57
+ return false;
58
+ return (rendered(element) || (element.shadowRoot?.querySelector('[part=box] > video') ?? null) !== null);
59
+ }
60
+ function viewed(client, opener, alone) {
61
+ void loaded(client.buildFile, VIEWER).then((file) => file?.openViewer({
62
+ opener,
63
+ alone,
64
+ download: (room, path, revision) => void client.binaryFile.download(room, path, revision),
65
+ }));
66
+ }
67
+ function pressed(client) {
68
+ return (event) => {
69
+ if (event.defaultPrevented || event.detail > 1)
70
+ return;
71
+ for (const node of event.composedPath()) {
72
+ if (!(node instanceof Element))
73
+ continue;
74
+ if (viewable(node)) {
75
+ event.preventDefault();
76
+ void client.then((one) => viewed(one, node, !rendered(node)));
77
+ return;
78
+ }
79
+ if (node.matches(PRESSED_ELSEWHERE))
80
+ return;
81
+ }
82
+ };
83
+ }
84
+ export function viewFile(client, media) {
85
+ viewed(client, media, true);
86
+ }
87
+ export function defineRoomMedia(client) {
88
+ if (customElements.get(ROOM_MEDIA) !== undefined)
89
+ return;
90
+ const connected = Promise.resolve(client);
91
+ document.addEventListener('click', pressed(connected));
92
+ class RoomMedia extends HTMLElement {
93
+ static observedAttributes = ATTRIBUTES;
94
+ #root = this.attachShadow({ mode: 'open' });
95
+ #box = document.createElement('div');
96
+ #fallback = document.createElement('slot');
97
+ #play = document.createElement('span');
98
+ #watching = null;
99
+ #near = false;
100
+ #asked = 0;
101
+ #shown = null;
102
+ #drawn = null;
103
+ #loaded = false;
104
+ #relinked = 0;
105
+ constructor() {
106
+ super();
107
+ this.#box.setAttribute('part', 'box');
108
+ this.#play.setAttribute('part', 'play');
109
+ this.#root.append(Object.assign(document.createElement('style'), { textContent: STYLE }), this.#box);
110
+ this.#shape();
111
+ }
112
+ connectedCallback() {
113
+ this.#label();
114
+ this.#watching ??= new IntersectionObserver((seen) => {
115
+ if (!seen.some((entry) => entry.isIntersecting) || this.#near)
116
+ return;
117
+ this.#near = true;
118
+ void this.#load();
119
+ }, { rootMargin: NEARING });
120
+ this.#watching.observe(this);
121
+ }
122
+ disconnectedCallback() {
123
+ this.#watching?.disconnect();
124
+ this.#watching = null;
125
+ this.#near = false;
126
+ this.#asked += 1;
127
+ this.#show(null);
128
+ }
129
+ attributeChangedCallback(name, before, after) {
130
+ if (before === after)
131
+ return;
132
+ this.#shape();
133
+ if (this.isConnected)
134
+ this.#label();
135
+ if (!LOADING.has(name) || !this.#near)
136
+ return;
137
+ this.#relinked = 0;
138
+ void this.#load();
139
+ }
140
+ #shape() {
141
+ this.#box.style.aspectRatio = ratioOf(this.getAttribute('width'), this.getAttribute('height'));
142
+ }
143
+ #label() {
144
+ const alt = this.getAttribute('alt') ?? '';
145
+ const drawn = this.#drawn;
146
+ if (drawn instanceof HTMLMediaElement) {
147
+ this.removeAttribute('role');
148
+ this.removeAttribute('aria-label');
149
+ drawn.setAttribute('aria-label', alt);
150
+ return;
151
+ }
152
+ this.setAttribute('role', 'img');
153
+ this.setAttribute('aria-label', alt);
154
+ if (drawn !== null)
155
+ drawn.alt = '';
156
+ }
157
+ async #load() {
158
+ const asked = (this.#asked += 1);
159
+ this.#loaded = false;
160
+ const room = this.getAttribute('room');
161
+ const path = this.getAttribute('path');
162
+ const revision = this.getAttribute('revision') ?? undefined;
163
+ if (room === null || path === null) {
164
+ this.#unreadable();
165
+ return;
166
+ }
167
+ const show = shows.get(await connected);
168
+ const shown = show === undefined ? null : await show(room, path, revision).catch(() => UNCERTAIN);
169
+ if (asked !== this.#asked)
170
+ return;
171
+ if (shown?.kind === 'link') {
172
+ this.#draw({ url: shown.url, copy: false }, shown.mediaType);
173
+ return;
174
+ }
175
+ if (shown?.kind !== 'binary') {
176
+ if (shown === null || refusedForGood(shown))
177
+ this.#unreadable();
178
+ else
179
+ this.#unshown(asked);
180
+ return;
181
+ }
182
+ const copy = await blobOf(shown).catch(() => null);
183
+ if (asked !== this.#asked)
184
+ return;
185
+ if (copy === null)
186
+ this.#unshown(asked);
187
+ else
188
+ this.#draw({ url: URL.createObjectURL(copy), copy: true }, shown.mediaType);
189
+ }
190
+ #unshown(asked) {
191
+ this.#unreadable();
192
+ setTimeout(() => {
193
+ if (asked === this.#asked && this.#near)
194
+ void this.#load();
195
+ }, UNSHOWN_MS);
196
+ }
197
+ #show(shown, content = null) {
198
+ if (this.#shown?.copy === true)
199
+ URL.revokeObjectURL(this.#shown.url);
200
+ this.#shown = shown;
201
+ if (content !== this.#drawn)
202
+ this.#drawn = null;
203
+ if (content === null)
204
+ this.#box.replaceChildren();
205
+ else if (content.parentNode !== this.#box)
206
+ this.#box.replaceChildren(...(content instanceof HTMLVideoElement && !content.controls
207
+ ? [content, this.#play]
208
+ : [content]));
209
+ this.#label();
210
+ }
211
+ #unreadable() {
212
+ this.#show(null, this.#fallback);
213
+ }
214
+ #draw(shown, mediaType) {
215
+ const tag = drawnFor(mediaType);
216
+ if (tag === null) {
217
+ if (shown.copy)
218
+ URL.revokeObjectURL(shown.url);
219
+ this.#unreadable();
220
+ return;
221
+ }
222
+ const kept = this.#drawn?.localName === tag ? this.#drawn : null;
223
+ const drawn = kept ?? document.createElement(tag);
224
+ if (kept === null) {
225
+ const plays = !(drawn instanceof HTMLVideoElement) || this.closest(`.${VIEWING}`) !== null;
226
+ if (drawn instanceof HTMLImageElement)
227
+ drawn.decoding = 'async';
228
+ if (drawn instanceof HTMLMediaElement) {
229
+ drawn.preload = 'metadata';
230
+ drawn.controls = plays;
231
+ }
232
+ if (drawn instanceof HTMLVideoElement && plays) {
233
+ drawn.autoplay = true;
234
+ drawn.setAttribute('playsinline', '');
235
+ }
236
+ drawn.addEventListener(drawn instanceof HTMLImageElement ? 'load' : 'loadedmetadata', () => {
237
+ if (drawn !== this.#drawn)
238
+ return;
239
+ this.#loaded = true;
240
+ this.#relinked = 0;
241
+ });
242
+ drawn.addEventListener('error', () => this.#failed(drawn));
243
+ }
244
+ this.#drawn = drawn;
245
+ this.#show(shown, drawn);
246
+ drawn.src = shown.url;
247
+ }
248
+ #failed(drawn) {
249
+ if (drawn !== this.#drawn)
250
+ return;
251
+ if (this.#shown?.copy !== false || !this.#loaded || this.#relinked >= RELINKS) {
252
+ this.#unreadable();
253
+ return;
254
+ }
255
+ this.#relinked += 1;
256
+ if (drawn instanceof HTMLMediaElement) {
257
+ const at = drawn.currentTime;
258
+ const playing = !drawn.paused;
259
+ drawn.addEventListener('loadedmetadata', () => {
260
+ drawn.currentTime = at;
261
+ if (playing)
262
+ void drawn.play().catch(() => undefined);
263
+ }, { once: true });
264
+ }
265
+ void this.#load();
266
+ }
267
+ }
268
+ customElements.define(ROOM_MEDIA, RoomMedia);
269
+ }