@mostra/protocol 0.0.0-stage → 0.1.0

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 (439) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +38 -2
  3. package/dist/actions.d.ts +273 -0
  4. package/dist/actions.d.ts.map +1 -0
  5. package/dist/actions.js +154 -0
  6. package/dist/actions.js.map +1 -0
  7. package/dist/artifact.d.ts +113 -0
  8. package/dist/artifact.d.ts.map +1 -0
  9. package/dist/artifact.js +79 -0
  10. package/dist/artifact.js.map +1 -0
  11. package/dist/bridge.d.ts +295 -0
  12. package/dist/bridge.d.ts.map +1 -0
  13. package/dist/bridge.js +343 -0
  14. package/dist/bridge.js.map +1 -0
  15. package/dist/browser.d.ts +195 -0
  16. package/dist/browser.d.ts.map +1 -0
  17. package/dist/browser.js +156 -0
  18. package/dist/browser.js.map +1 -0
  19. package/dist/bundle.d.ts +155 -0
  20. package/dist/bundle.d.ts.map +1 -0
  21. package/dist/bundle.js +130 -0
  22. package/dist/bundle.js.map +1 -0
  23. package/dist/canonical.d.ts +23 -0
  24. package/dist/canonical.d.ts.map +1 -0
  25. package/dist/canonical.js +45 -0
  26. package/dist/canonical.js.map +1 -0
  27. package/dist/capability.d.ts +38 -0
  28. package/dist/capability.d.ts.map +1 -0
  29. package/dist/capability.js +61 -0
  30. package/dist/capability.js.map +1 -0
  31. package/dist/diagnostics/codes/a11y.d.ts +8 -0
  32. package/dist/diagnostics/codes/a11y.d.ts.map +1 -0
  33. package/dist/diagnostics/codes/a11y.js +30 -0
  34. package/dist/diagnostics/codes/a11y.js.map +1 -0
  35. package/dist/diagnostics/codes/action.d.ts +8 -0
  36. package/dist/diagnostics/codes/action.d.ts.map +1 -0
  37. package/dist/diagnostics/codes/action.js +110 -0
  38. package/dist/diagnostics/codes/action.js.map +1 -0
  39. package/dist/diagnostics/codes/artifact.d.ts +8 -0
  40. package/dist/diagnostics/codes/artifact.d.ts.map +1 -0
  41. package/dist/diagnostics/codes/artifact.js +121 -0
  42. package/dist/diagnostics/codes/artifact.js.map +1 -0
  43. package/dist/diagnostics/codes/build.d.ts +8 -0
  44. package/dist/diagnostics/codes/build.d.ts.map +1 -0
  45. package/dist/diagnostics/codes/build.js +55 -0
  46. package/dist/diagnostics/codes/build.js.map +1 -0
  47. package/dist/diagnostics/codes/cli.d.ts +8 -0
  48. package/dist/diagnostics/codes/cli.d.ts.map +1 -0
  49. package/dist/diagnostics/codes/cli.js +44 -0
  50. package/dist/diagnostics/codes/cli.js.map +1 -0
  51. package/dist/diagnostics/codes/console.d.ts +8 -0
  52. package/dist/diagnostics/codes/console.d.ts.map +1 -0
  53. package/dist/diagnostics/codes/console.js +30 -0
  54. package/dist/diagnostics/codes/console.js.map +1 -0
  55. package/dist/diagnostics/codes/dep.d.ts +8 -0
  56. package/dist/diagnostics/codes/dep.d.ts.map +1 -0
  57. package/dist/diagnostics/codes/dep.js +88 -0
  58. package/dist/diagnostics/codes/dep.js.map +1 -0
  59. package/dist/diagnostics/codes/env.d.ts +8 -0
  60. package/dist/diagnostics/codes/env.d.ts.map +1 -0
  61. package/dist/diagnostics/codes/env.js +132 -0
  62. package/dist/diagnostics/codes/env.js.map +1 -0
  63. package/dist/diagnostics/codes/field.d.ts +8 -0
  64. package/dist/diagnostics/codes/field.d.ts.map +1 -0
  65. package/dist/diagnostics/codes/field.js +99 -0
  66. package/dist/diagnostics/codes/field.js.map +1 -0
  67. package/dist/diagnostics/codes/home.d.ts +8 -0
  68. package/dist/diagnostics/codes/home.d.ts.map +1 -0
  69. package/dist/diagnostics/codes/home.js +132 -0
  70. package/dist/diagnostics/codes/home.js.map +1 -0
  71. package/dist/diagnostics/codes/host.d.ts +8 -0
  72. package/dist/diagnostics/codes/host.d.ts.map +1 -0
  73. package/dist/diagnostics/codes/host.js +176 -0
  74. package/dist/diagnostics/codes/host.js.map +1 -0
  75. package/dist/diagnostics/codes/hygiene.d.ts +8 -0
  76. package/dist/diagnostics/codes/hygiene.d.ts.map +1 -0
  77. package/dist/diagnostics/codes/hygiene.js +154 -0
  78. package/dist/diagnostics/codes/hygiene.js.map +1 -0
  79. package/dist/diagnostics/codes/index.d.ts +51 -0
  80. package/dist/diagnostics/codes/index.d.ts.map +1 -0
  81. package/dist/diagnostics/codes/index.js +72 -0
  82. package/dist/diagnostics/codes/index.js.map +1 -0
  83. package/dist/diagnostics/codes/live.d.ts +8 -0
  84. package/dist/diagnostics/codes/live.d.ts.map +1 -0
  85. package/dist/diagnostics/codes/live.js +30 -0
  86. package/dist/diagnostics/codes/live.js.map +1 -0
  87. package/dist/diagnostics/codes/manifest.d.ts +8 -0
  88. package/dist/diagnostics/codes/manifest.d.ts.map +1 -0
  89. package/dist/diagnostics/codes/manifest.js +44 -0
  90. package/dist/diagnostics/codes/manifest.js.map +1 -0
  91. package/dist/diagnostics/codes/network.d.ts +8 -0
  92. package/dist/diagnostics/codes/network.d.ts.map +1 -0
  93. package/dist/diagnostics/codes/network.js +30 -0
  94. package/dist/diagnostics/codes/network.js.map +1 -0
  95. package/dist/diagnostics/codes/platform.d.ts +8 -0
  96. package/dist/diagnostics/codes/platform.d.ts.map +1 -0
  97. package/dist/diagnostics/codes/platform.js +18 -0
  98. package/dist/diagnostics/codes/platform.js.map +1 -0
  99. package/dist/diagnostics/codes/publish.d.ts +8 -0
  100. package/dist/diagnostics/codes/publish.d.ts.map +1 -0
  101. package/dist/diagnostics/codes/publish.js +44 -0
  102. package/dist/diagnostics/codes/publish.js.map +1 -0
  103. package/dist/diagnostics/codes/regression.d.ts +8 -0
  104. package/dist/diagnostics/codes/regression.d.ts.map +1 -0
  105. package/dist/diagnostics/codes/regression.js +77 -0
  106. package/dist/diagnostics/codes/regression.js.map +1 -0
  107. package/dist/diagnostics/codes/runtime.d.ts +8 -0
  108. package/dist/diagnostics/codes/runtime.d.ts.map +1 -0
  109. package/dist/diagnostics/codes/runtime.js +66 -0
  110. package/dist/diagnostics/codes/runtime.js.map +1 -0
  111. package/dist/diagnostics/codes/secret.d.ts +8 -0
  112. package/dist/diagnostics/codes/secret.d.ts.map +1 -0
  113. package/dist/diagnostics/codes/secret.js +18 -0
  114. package/dist/diagnostics/codes/secret.js.map +1 -0
  115. package/dist/diagnostics/codes/smoke.d.ts +8 -0
  116. package/dist/diagnostics/codes/smoke.d.ts.map +1 -0
  117. package/dist/diagnostics/codes/smoke.js +30 -0
  118. package/dist/diagnostics/codes/smoke.js.map +1 -0
  119. package/dist/diagnostics/codes/submit.d.ts +8 -0
  120. package/dist/diagnostics/codes/submit.d.ts.map +1 -0
  121. package/dist/diagnostics/codes/submit.js +99 -0
  122. package/dist/diagnostics/codes/submit.js.map +1 -0
  123. package/dist/diagnostics/codes/target.d.ts +8 -0
  124. package/dist/diagnostics/codes/target.d.ts.map +1 -0
  125. package/dist/diagnostics/codes/target.js +18 -0
  126. package/dist/diagnostics/codes/target.js.map +1 -0
  127. package/dist/diagnostics/codes/type.d.ts +8 -0
  128. package/dist/diagnostics/codes/type.d.ts.map +1 -0
  129. package/dist/diagnostics/codes/type.js +30 -0
  130. package/dist/diagnostics/codes/type.js.map +1 -0
  131. package/dist/diagnostics/codes/verify.d.ts +8 -0
  132. package/dist/diagnostics/codes/verify.d.ts.map +1 -0
  133. package/dist/diagnostics/codes/verify.js +99 -0
  134. package/dist/diagnostics/codes/verify.js.map +1 -0
  135. package/dist/diagnostics/diagnostic.d.ts +79 -0
  136. package/dist/diagnostics/diagnostic.d.ts.map +1 -0
  137. package/dist/diagnostics/diagnostic.js +131 -0
  138. package/dist/diagnostics/diagnostic.js.map +1 -0
  139. package/dist/diagnostics/spec.d.ts +49 -0
  140. package/dist/diagnostics/spec.d.ts.map +1 -0
  141. package/dist/diagnostics/spec.js +31 -0
  142. package/dist/diagnostics/spec.js.map +1 -0
  143. package/dist/hygiene.d.ts +66 -0
  144. package/dist/hygiene.d.ts.map +1 -0
  145. package/dist/hygiene.js +134 -0
  146. package/dist/hygiene.js.map +1 -0
  147. package/dist/ids.d.ts +119 -0
  148. package/dist/ids.d.ts.map +1 -0
  149. package/dist/ids.js +135 -0
  150. package/dist/ids.js.map +1 -0
  151. package/dist/index.d.ts +86 -0
  152. package/dist/index.js +86 -0
  153. package/dist/interaction.d.ts +391 -0
  154. package/dist/interaction.d.ts.map +1 -0
  155. package/dist/interaction.js +306 -0
  156. package/dist/interaction.js.map +1 -0
  157. package/dist/manifest.d.ts +97 -0
  158. package/dist/manifest.d.ts.map +1 -0
  159. package/dist/manifest.js +101 -0
  160. package/dist/manifest.js.map +1 -0
  161. package/dist/method.d.ts +26 -0
  162. package/dist/method.d.ts.map +1 -0
  163. package/dist/method.js +10 -0
  164. package/dist/method.js.map +1 -0
  165. package/dist/methods/artifact/create.d.ts +29 -0
  166. package/dist/methods/artifact/create.d.ts.map +1 -0
  167. package/dist/methods/artifact/create.js +31 -0
  168. package/dist/methods/artifact/create.js.map +1 -0
  169. package/dist/methods/artifact/get.d.ts +17 -0
  170. package/dist/methods/artifact/get.d.ts.map +1 -0
  171. package/dist/methods/artifact/get.js +21 -0
  172. package/dist/methods/artifact/get.js.map +1 -0
  173. package/dist/methods/artifact/list.d.ts +22 -0
  174. package/dist/methods/artifact/list.d.ts.map +1 -0
  175. package/dist/methods/artifact/list.js +19 -0
  176. package/dist/methods/artifact/list.js.map +1 -0
  177. package/dist/methods/artifact/publish.d.ts +28 -0
  178. package/dist/methods/artifact/publish.d.ts.map +1 -0
  179. package/dist/methods/artifact/publish.js +28 -0
  180. package/dist/methods/artifact/publish.js.map +1 -0
  181. package/dist/methods/artifact/verify.d.ts +29 -0
  182. package/dist/methods/artifact/verify.d.ts.map +1 -0
  183. package/dist/methods/artifact/verify.js +27 -0
  184. package/dist/methods/artifact/verify.js.map +1 -0
  185. package/dist/methods/deps/add.d.ts +43 -0
  186. package/dist/methods/deps/add.d.ts.map +1 -0
  187. package/dist/methods/deps/add.js +40 -0
  188. package/dist/methods/deps/add.js.map +1 -0
  189. package/dist/methods/dev/start.d.ts +52 -0
  190. package/dist/methods/dev/start.d.ts.map +1 -0
  191. package/dist/methods/dev/start.js +56 -0
  192. package/dist/methods/dev/start.js.map +1 -0
  193. package/dist/methods/dev/stop.d.ts +16 -0
  194. package/dist/methods/dev/stop.d.ts.map +1 -0
  195. package/dist/methods/dev/stop.js +21 -0
  196. package/dist/methods/dev/stop.js.map +1 -0
  197. package/dist/methods/events/ack.d.ts +20 -0
  198. package/dist/methods/events/ack.d.ts.map +1 -0
  199. package/dist/methods/events/ack.js +26 -0
  200. package/dist/methods/events/ack.js.map +1 -0
  201. package/dist/methods/events/read.d.ts +40 -0
  202. package/dist/methods/events/read.d.ts.map +1 -0
  203. package/dist/methods/events/read.js +35 -0
  204. package/dist/methods/events/read.js.map +1 -0
  205. package/dist/methods/events/subscribe.d.ts +54 -0
  206. package/dist/methods/events/subscribe.d.ts.map +1 -0
  207. package/dist/methods/events/subscribe.js +44 -0
  208. package/dist/methods/events/subscribe.js.map +1 -0
  209. package/dist/methods/events/unsubscribe.d.ts +16 -0
  210. package/dist/methods/events/unsubscribe.d.ts.map +1 -0
  211. package/dist/methods/events/unsubscribe.js +21 -0
  212. package/dist/methods/events/unsubscribe.js.map +1 -0
  213. package/dist/methods/gc/run.d.ts +76 -0
  214. package/dist/methods/gc/run.d.ts.map +1 -0
  215. package/dist/methods/gc/run.js +56 -0
  216. package/dist/methods/gc/run.js.map +1 -0
  217. package/dist/methods/index.d.ts +6 -0
  218. package/dist/methods/index.d.ts.map +1 -0
  219. package/dist/methods/index.js +78 -0
  220. package/dist/methods/index.js.map +1 -0
  221. package/dist/methods/instance/check.d.ts +30 -0
  222. package/dist/methods/instance/check.d.ts.map +1 -0
  223. package/dist/methods/instance/check.js +34 -0
  224. package/dist/methods/instance/check.js.map +1 -0
  225. package/dist/methods/instance/status.d.ts +102 -0
  226. package/dist/methods/instance/status.d.ts.map +1 -0
  227. package/dist/methods/instance/status.js +83 -0
  228. package/dist/methods/instance/status.js.map +1 -0
  229. package/dist/methods/live/push.d.ts +28 -0
  230. package/dist/methods/live/push.d.ts.map +1 -0
  231. package/dist/methods/live/push.js +35 -0
  232. package/dist/methods/live/push.js.map +1 -0
  233. package/dist/methods/mostra/initialize.d.ts +143 -0
  234. package/dist/methods/mostra/initialize.d.ts.map +1 -0
  235. package/dist/methods/mostra/initialize.js +97 -0
  236. package/dist/methods/mostra/initialize.js.map +1 -0
  237. package/dist/methods/mostra/shutdown.d.ts +14 -0
  238. package/dist/methods/mostra/shutdown.d.ts.map +1 -0
  239. package/dist/methods/mostra/shutdown.js +22 -0
  240. package/dist/methods/mostra/shutdown.js.map +1 -0
  241. package/dist/methods/port/drafts-mirror.d.ts +30 -0
  242. package/dist/methods/port/drafts-mirror.d.ts.map +1 -0
  243. package/dist/methods/port/drafts-mirror.js +33 -0
  244. package/dist/methods/port/drafts-mirror.js.map +1 -0
  245. package/dist/methods/port/secrets-get.d.ts +19 -0
  246. package/dist/methods/port/secrets-get.d.ts.map +1 -0
  247. package/dist/methods/port/secrets-get.js +31 -0
  248. package/dist/methods/port/secrets-get.js.map +1 -0
  249. package/dist/methods/port/submissions-deliver.d.ts +38 -0
  250. package/dist/methods/port/submissions-deliver.d.ts.map +1 -0
  251. package/dist/methods/port/submissions-deliver.js +38 -0
  252. package/dist/methods/port/submissions-deliver.js.map +1 -0
  253. package/dist/methods/port/trusted-controls-activated.d.ts +27 -0
  254. package/dist/methods/port/trusted-controls-activated.d.ts.map +1 -0
  255. package/dist/methods/port/trusted-controls-activated.js +33 -0
  256. package/dist/methods/port/trusted-controls-activated.js.map +1 -0
  257. package/dist/methods/port/trusted-controls-policy.d.ts +21 -0
  258. package/dist/methods/port/trusted-controls-policy.d.ts.map +1 -0
  259. package/dist/methods/port/trusted-controls-policy.js +27 -0
  260. package/dist/methods/port/trusted-controls-policy.js.map +1 -0
  261. package/dist/methods/results/get.d.ts +32 -0
  262. package/dist/methods/results/get.d.ts.map +1 -0
  263. package/dist/methods/results/get.js +36 -0
  264. package/dist/methods/results/get.js.map +1 -0
  265. package/dist/methods/secret/delete.d.ts +22 -0
  266. package/dist/methods/secret/delete.d.ts.map +1 -0
  267. package/dist/methods/secret/delete.js +32 -0
  268. package/dist/methods/secret/delete.js.map +1 -0
  269. package/dist/methods/secret/list.d.ts +21 -0
  270. package/dist/methods/secret/list.d.ts.map +1 -0
  271. package/dist/methods/secret/list.js +29 -0
  272. package/dist/methods/secret/list.js.map +1 -0
  273. package/dist/methods/secret/set.d.ts +37 -0
  274. package/dist/methods/secret/set.d.ts.map +1 -0
  275. package/dist/methods/secret/set.js +41 -0
  276. package/dist/methods/secret/set.js.map +1 -0
  277. package/dist/methods/state/get.d.ts +25 -0
  278. package/dist/methods/state/get.d.ts.map +1 -0
  279. package/dist/methods/state/get.js +29 -0
  280. package/dist/methods/state/get.js.map +1 -0
  281. package/dist/methods/state/patch.d.ts +32 -0
  282. package/dist/methods/state/patch.d.ts.map +1 -0
  283. package/dist/methods/state/patch.js +29 -0
  284. package/dist/methods/state/patch.js.map +1 -0
  285. package/dist/methods/view/default.d.ts +19 -0
  286. package/dist/methods/view/default.d.ts.map +1 -0
  287. package/dist/methods/view/default.js +23 -0
  288. package/dist/methods/view/default.js.map +1 -0
  289. package/dist/methods/view/launch.d.ts +27 -0
  290. package/dist/methods/view/launch.d.ts.map +1 -0
  291. package/dist/methods/view/launch.js +30 -0
  292. package/dist/methods/view/launch.js.map +1 -0
  293. package/dist/methods/view/revoke.d.ts +19 -0
  294. package/dist/methods/view/revoke.d.ts.map +1 -0
  295. package/dist/methods/view/revoke.js +26 -0
  296. package/dist/methods/view/revoke.js.map +1 -0
  297. package/dist/methods/view/rotate.d.ts +21 -0
  298. package/dist/methods/view/rotate.d.ts.map +1 -0
  299. package/dist/methods/view/rotate.js +27 -0
  300. package/dist/methods/view/rotate.js.map +1 -0
  301. package/dist/methods/view/url.d.ts +52 -0
  302. package/dist/methods/view/url.d.ts.map +1 -0
  303. package/dist/methods/view/url.js +43 -0
  304. package/dist/methods/view/url.js.map +1 -0
  305. package/dist/methods/wait/wait.d.ts +37 -0
  306. package/dist/methods/wait/wait.d.ts.map +1 -0
  307. package/dist/methods/wait/wait.js +39 -0
  308. package/dist/methods/wait/wait.js.map +1 -0
  309. package/dist/revision.d.ts +43 -0
  310. package/dist/revision.d.ts.map +1 -0
  311. package/dist/revision.js +69 -0
  312. package/dist/revision.js.map +1 -0
  313. package/dist/rpc/error.d.ts +47 -0
  314. package/dist/rpc/error.d.ts.map +1 -0
  315. package/dist/rpc/error.js +77 -0
  316. package/dist/rpc/error.js.map +1 -0
  317. package/dist/rpc/lines.d.ts +30 -0
  318. package/dist/rpc/lines.d.ts.map +1 -0
  319. package/dist/rpc/lines.js +63 -0
  320. package/dist/rpc/lines.js.map +1 -0
  321. package/dist/rpc/messages.d.ts +92 -0
  322. package/dist/rpc/messages.d.ts.map +1 -0
  323. package/dist/rpc/messages.js +133 -0
  324. package/dist/rpc/messages.js.map +1 -0
  325. package/dist/rpc/peer.d.ts +81 -0
  326. package/dist/rpc/peer.d.ts.map +1 -0
  327. package/dist/rpc/peer.js +208 -0
  328. package/dist/rpc/peer.js.map +1 -0
  329. package/dist/serializer.d.ts +178 -0
  330. package/dist/serializer.d.ts.map +1 -0
  331. package/dist/serializer.js +929 -0
  332. package/dist/serializer.js.map +1 -0
  333. package/dist/verify.d.ts +254 -0
  334. package/dist/verify.d.ts.map +1 -0
  335. package/dist/verify.js +243 -0
  336. package/dist/verify.js.map +1 -0
  337. package/dist/view.d.ts +103 -0
  338. package/dist/view.d.ts.map +1 -0
  339. package/dist/view.js +110 -0
  340. package/dist/view.js.map +1 -0
  341. package/dist/wire-registry.js +11 -0
  342. package/dist/wire-registry.js.map +1 -0
  343. package/dist/worker.d.ts +249 -0
  344. package/dist/worker.d.ts.map +1 -0
  345. package/dist/worker.js +158 -0
  346. package/dist/worker.js.map +1 -0
  347. package/package.json +114 -3
  348. package/schemas/protocol.draft-07.json +5120 -0
  349. package/schemas/protocol.schema.json +4964 -0
  350. package/src/actions.ts +418 -0
  351. package/src/artifact.ts +187 -0
  352. package/src/bridge.ts +618 -0
  353. package/src/browser.ts +374 -0
  354. package/src/bundle.ts +264 -0
  355. package/src/canonical.ts +49 -0
  356. package/src/capability.ts +92 -0
  357. package/src/diagnostics/codes/a11y.ts +41 -0
  358. package/src/diagnostics/codes/action.ts +125 -0
  359. package/src/diagnostics/codes/artifact.ts +137 -0
  360. package/src/diagnostics/codes/build.ts +65 -0
  361. package/src/diagnostics/codes/cli.ts +53 -0
  362. package/src/diagnostics/codes/console.ts +41 -0
  363. package/src/diagnostics/codes/dep.ts +101 -0
  364. package/src/diagnostics/codes/env.ts +149 -0
  365. package/src/diagnostics/codes/field.ts +113 -0
  366. package/src/diagnostics/codes/home.ts +150 -0
  367. package/src/diagnostics/codes/host.ts +197 -0
  368. package/src/diagnostics/codes/hygiene.ts +175 -0
  369. package/src/diagnostics/codes/index.ts +142 -0
  370. package/src/diagnostics/codes/live.ts +41 -0
  371. package/src/diagnostics/codes/manifest.ts +53 -0
  372. package/src/diagnostics/codes/network.ts +41 -0
  373. package/src/diagnostics/codes/platform.ts +30 -0
  374. package/src/diagnostics/codes/publish.ts +53 -0
  375. package/src/diagnostics/codes/regression.ts +89 -0
  376. package/src/diagnostics/codes/runtime.ts +77 -0
  377. package/src/diagnostics/codes/secret.ts +29 -0
  378. package/src/diagnostics/codes/smoke.ts +41 -0
  379. package/src/diagnostics/codes/submit.ts +113 -0
  380. package/src/diagnostics/codes/target.ts +29 -0
  381. package/src/diagnostics/codes/type.ts +41 -0
  382. package/src/diagnostics/codes/verify.ts +113 -0
  383. package/src/diagnostics/diagnostic.ts +240 -0
  384. package/src/diagnostics/spec.ts +90 -0
  385. package/src/hygiene.ts +224 -0
  386. package/src/ids.ts +279 -0
  387. package/src/index.ts +576 -0
  388. package/src/interaction.ts +728 -0
  389. package/src/manifest.ts +206 -0
  390. package/src/method.ts +42 -0
  391. package/src/methods/artifact/create.ts +56 -0
  392. package/src/methods/artifact/get.ts +30 -0
  393. package/src/methods/artifact/list.ts +42 -0
  394. package/src/methods/artifact/publish.ts +46 -0
  395. package/src/methods/artifact/verify.ts +46 -0
  396. package/src/methods/deps/add.ts +72 -0
  397. package/src/methods/dev/start.ts +84 -0
  398. package/src/methods/dev/stop.ts +32 -0
  399. package/src/methods/events/ack.ts +41 -0
  400. package/src/methods/events/read.ts +67 -0
  401. package/src/methods/events/subscribe.ts +91 -0
  402. package/src/methods/events/unsubscribe.ts +35 -0
  403. package/src/methods/gc/run.ts +125 -0
  404. package/src/methods/index.ts +81 -0
  405. package/src/methods/instance/check.ts +61 -0
  406. package/src/methods/instance/status.ts +172 -0
  407. package/src/methods/live/push.ts +54 -0
  408. package/src/methods/mostra/initialize.ts +249 -0
  409. package/src/methods/mostra/shutdown.ts +31 -0
  410. package/src/methods/port/drafts-mirror.ts +52 -0
  411. package/src/methods/port/secrets-get.ts +40 -0
  412. package/src/methods/port/submissions-deliver.ts +70 -0
  413. package/src/methods/port/trusted-controls-activated.ts +51 -0
  414. package/src/methods/port/trusted-controls-policy.ts +38 -0
  415. package/src/methods/results/get.ts +59 -0
  416. package/src/methods/secret/delete.ts +43 -0
  417. package/src/methods/secret/list.ts +40 -0
  418. package/src/methods/secret/set.ts +69 -0
  419. package/src/methods/state/get.ts +44 -0
  420. package/src/methods/state/patch.ts +51 -0
  421. package/src/methods/view/default.ts +32 -0
  422. package/src/methods/view/launch.ts +47 -0
  423. package/src/methods/view/revoke.ts +39 -0
  424. package/src/methods/view/rotate.ts +37 -0
  425. package/src/methods/view/url.ts +84 -0
  426. package/src/methods/wait/wait.ts +58 -0
  427. package/src/revision.ts +101 -0
  428. package/src/rpc/error.ts +107 -0
  429. package/src/rpc/lines.ts +70 -0
  430. package/src/rpc/messages.ts +188 -0
  431. package/src/rpc/peer.ts +341 -0
  432. package/src/serializer.ts +1217 -0
  433. package/src/timers.d.ts +8 -0
  434. package/src/verify.ts +458 -0
  435. package/src/view.ts +200 -0
  436. package/src/web-crypto.d.ts +9 -0
  437. package/src/web-platform.d.ts +35 -0
  438. package/src/wire-registry.ts +14 -0
  439. package/src/worker.ts +374 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.d.ts","names":[],"sources":["../../src/diagnostics/spec.ts"],"mappings":";;;iBAeiB;;WAEN,UAAU;;WAEV,OAAO;;WAEP;;WAEA;;WAEA;;aAEE;;aAEA;;;;;;WAMF;;;YAIC,YAAY,oBAAoB,0CAChC,KAAK,IAAI;;;;;qBAOR;;wBAGG,QAAQ,cAAc;;iBAOrB;;WAEN;;WAEA;;WAEA,MAAM;;WAEN,WAAW;;WAEX"}
@@ -0,0 +1,31 @@
1
+ //#region src/diagnostics/spec.ts
2
+ /**
3
+ * Where diagnostics link by default: the GitHub Pages docs site (D37). Hosts and the runtime pass
4
+ * their own base when the docs move.
5
+ */
6
+ const DEFAULT_DOCS_BASE = "https://mostra-dev.github.io/mostra";
7
+ /** The docs page for `code` under `docsBase`: `${docsBase}/errors/${code}`. */
8
+ function docsUrl(code, docsBase = DEFAULT_DOCS_BASE) {
9
+ let end = docsBase.length;
10
+ while (end > 0 && docsBase.charCodeAt(end - 1) === 47) end--;
11
+ return `${docsBase.slice(0, end)}/errors/${code}`;
12
+ }
13
+ /**
14
+ * Builds a diagnostic for a cataloged code: severity, phase, hint and docs link come from `spec`,
15
+ * the rest from `details`.
16
+ */
17
+ function buildDiagnostic(code, spec, details, docsBase = DEFAULT_DOCS_BASE) {
18
+ const { hint = spec.hint, ...rest } = details;
19
+ return {
20
+ code,
21
+ severity: spec.severity,
22
+ phase: spec.phase,
23
+ docs: docsUrl(code, docsBase),
24
+ hint,
25
+ ...rest
26
+ };
27
+ }
28
+ //#endregion
29
+ export { DEFAULT_DOCS_BASE, buildDiagnostic, docsUrl };
30
+
31
+ //# sourceMappingURL=spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.js","names":[],"sources":["../../src/diagnostics/spec.ts"],"sourcesContent":["/**\n * The diagnostic catalog: one entry per code, declared in one source file per area under\n * `codes/`. The catalog feeds `createDiagnostic`, the generated catalog JSON and one docs\n * page per code (AX-03).\n */\nimport type {\n Diagnostic,\n DiagnosticArea,\n DiagnosticFix,\n DiagnosticLocation,\n DiagnosticPhase,\n DiagnosticSeverity,\n} from \"./diagnostic.ts\";\n\n/** Everything Mostra knows about one code, besides the code itself. */\nexport interface DiagnosticSpec {\n /** The severity of every occurrence. */\n readonly severity: DiagnosticSeverity;\n /** The stage of work that reports it. */\n readonly phase: DiagnosticPhase;\n /** One line naming the condition. It is the docs page's title. */\n readonly title: string;\n /** The default hint: one imperative sentence. An occurrence may give a more specific one. */\n readonly hint: string;\n /** The docs page body. */\n readonly docs: {\n /** What the code means and when Mostra reports it. */\n readonly explanation: string;\n /** The minimal fix. */\n readonly fix: string;\n };\n /**\n * Set when Mostra no longer reports the code, saying what replaced it. Codes are never\n * removed (AX-03).\n */\n readonly deprecated?: string;\n}\n\n/** The catalog of one area: exactly the codes `C`, each with its spec. */\nexport type AreaCatalog<C extends `MOSTRA_${DiagnosticArea}_${string}`> = {\n readonly [K in C]: DiagnosticSpec;\n};\n\n/**\n * Where diagnostics link by default: the GitHub Pages docs site (D37). Hosts and the runtime pass\n * their own base when the docs move.\n */\nexport const DEFAULT_DOCS_BASE: string = \"https://mostra-dev.github.io/mostra\";\n\n/** The docs page for `code` under `docsBase`: `${docsBase}/errors/${code}`. */\nexport function docsUrl(code: string, docsBase: string = DEFAULT_DOCS_BASE): string {\n let end = docsBase.length;\n while (end > 0 && docsBase.charCodeAt(end - 1) === 47 /* \"/\" */) end--;\n return `${docsBase.slice(0, end)}/errors/${code}`;\n}\n\n/** The parts of a diagnostic that belong to one occurrence rather than to its code. */\nexport interface DiagnosticDetails {\n /** What is wrong, for this occurrence. Never include secrets or capability tokens. */\n readonly message: string;\n /** Replaces the catalog's default hint when the occurrence allows a more specific one. */\n readonly hint?: string;\n /** A machine-applicable fix. */\n readonly fix?: DiagnosticFix;\n /** Where the problem is. */\n readonly location?: DiagnosticLocation;\n /** How many identical occurrences this one stands for. */\n readonly count?: number;\n}\n\n/**\n * Builds a diagnostic for a cataloged code: severity, phase, hint and docs link come from `spec`,\n * the rest from `details`.\n */\nexport function buildDiagnostic(\n code: Diagnostic[\"code\"],\n spec: DiagnosticSpec,\n details: DiagnosticDetails,\n docsBase: string = DEFAULT_DOCS_BASE,\n): Diagnostic {\n const { hint = spec.hint, ...rest } = details;\n return {\n code,\n severity: spec.severity,\n phase: spec.phase,\n docs: docsUrl(code, docsBase),\n hint,\n ...rest,\n };\n}\n"],"mappings":";;;;;AA+CA,MAAa,oBAA4B;;AAGzC,SAAgB,QAAQ,MAAc,WAAmB,mBAA2B;CAClF,IAAI,MAAM,SAAS;CACnB,OAAO,MAAM,KAAK,SAAS,WAAW,MAAM,CAAC,MAAM,IAAc;CACjE,OAAO,GAAG,SAAS,MAAM,GAAG,GAAG,EAAE,UAAU;AAC7C;;;;;AAoBA,SAAgB,gBACd,MACA,MACA,SACA,WAAmB,mBACP;CACZ,MAAM,EAAE,OAAO,KAAK,MAAM,GAAG,SAAS;CACtC,OAAO;EACL;EACA,UAAU,KAAK;EACf,OAAO,KAAK;EACZ,MAAM,QAAQ,MAAM,QAAQ;EAC5B;EACA,GAAG;CACL;AACF"}
@@ -0,0 +1,66 @@
1
+ import { Diagnostic } from "./diagnostics/diagnostic.js";
2
+ import { HygieneDiagnosticCode } from "./diagnostics/codes/hygiene.js";
3
+ //#region src/hygiene.d.ts
4
+ /** What one listener serves: its own origin and the exact `Host` values it accepts. */
5
+ export interface RequestPolicy {
6
+ /** The listener's origin, such as `http://127.0.0.1:23456`; `Origin` headers must equal it. */
7
+ readonly origin: string;
8
+ /** Every `host:port` this listener answers to (lowercase): its URL host, plus registered tunnels. */
9
+ readonly hosts: readonly string[];
10
+ }
11
+ /**
12
+ * What a request is for, which decides the checks beyond the envelope:
13
+ * - `read`: a GET or HEAD of a page or file; a foreign `Origin` is refused, none is fine.
14
+ * - `stream`: an event stream (GET); same-origin only, by `Origin` or `Sec-Fetch-Site`.
15
+ * - `upgrade`: a WebSocket upgrade; `Origin` must be present and equal.
16
+ * - `exchange`: a mutation that starts a session (a capability token or ticket in the body):
17
+ * `Origin` and a JSON content type, but no CSRF token yet.
18
+ * - `mutation`: any other state change: `Origin`, a JSON content type and the session's CSRF
19
+ * token in `X-Mostra-CSRF`.
20
+ */
21
+ export type RequestIntent = "read" | "stream" | "upgrade" | "exchange" | "mutation";
22
+ /** One request as the transport received it. */
23
+ export interface RequestFacts {
24
+ /** The method, as sent. */
25
+ readonly method: string;
26
+ /** The request target exactly as sent: an origin-form path with its query. */
27
+ readonly target: string;
28
+ /** Every header as `[name, value]` in arrival order, so repeated headers are visible. */
29
+ readonly headers: readonly (readonly [string, string])[];
30
+ /** The intent the matched route declared; omit to check only the envelope. */
31
+ readonly intent?: RequestIntent;
32
+ /** The session's CSRF token, for `mutation` requests. */
33
+ readonly csrf?: string;
34
+ }
35
+ /** A refused request: the HTTP status to answer with and the diagnostic for its body. */
36
+ export interface Refusal {
37
+ /** The HTTP status: 400, 401, 403, 404, 410, 415, 421 or 429. */
38
+ readonly status: number;
39
+ /** What was refused and why, for the response body and the log. */
40
+ readonly diagnostic: Diagnostic;
41
+ }
42
+ /** The header that carries a session's CSRF token on every mutation (D98). */
43
+ export declare const CSRF_HEADER = "x-mostra-csrf";
44
+ /** Builds a refusal with the status the code's HTTP mapping gives (FAILURE_MODEL §8). */
45
+ export declare function refusal(code: HygieneDiagnosticCode, message: string, status?: number): Refusal;
46
+ /** Constant-time comparison of two strings, so timing reveals nothing about a secret. */
47
+ export declare function safeEqual(a: string, b: string): boolean;
48
+ /**
49
+ * The path a request target names, decoded, or `undefined` when it isn't a safe origin-form path:
50
+ * absolute and authority forms, `*`, encoded `/` or `\`, `.` or `..` segments (encoded or not),
51
+ * NUL and other controls, and invalid percent-encoding are all refused.
52
+ */
53
+ export declare function safePath(target: string): string | undefined;
54
+ /** The value of a header (case-insensitive name), or `undefined`. */
55
+ export declare function headerValue(headers: readonly (readonly [string, string])[], name: string): string | undefined;
56
+ /** Whether a `Content-Type` value is JSON (`application/json`, any parameters). */
57
+ export declare function isJsonContentType(value: string | undefined): boolean;
58
+ /**
59
+ * Checks a request's envelope (the `Host` allowlist, the request target, repeated and malformed
60
+ * headers) and, when `intent` is given, what that intent needs: `Origin`, the JSON content type
61
+ * and the CSRF token. Returns the first refusal, or `undefined` when the request may proceed.
62
+ * Session, token and scope checks follow in the endpoint, which knows its session.
63
+ */
64
+ export declare function checkRequest(policy: RequestPolicy, request: RequestFacts): Refusal | undefined;
65
+ //#endregion
66
+ //# sourceMappingURL=hygiene.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hygiene.d.ts","names":[],"sources":["../src/hygiene.ts"],"mappings":";;;;iBAoBiB;;WAEN;;WAEA;;;;;;;;;;;;YAaC;;iBAGK;;WAEN;;WAEA;;WAEA;;WAEA,SAAS;;WAET;;;iBAIM;;WAEN;;WAEA,YAAY;;;qBAIV;;wBAmBG,QAAQ,MAAM,uBAAuB,iBAAiB,kBAAkB;;wBAexE,UAAU,WAAW;;;;;;wBAcrB,SAAS;;wBAiBT,YACd,iDACA;;wBAOc,kBAAkB;;;;;;;wBAWlB,aAAa,QAAQ,eAAe,SAAS,eAAe"}
@@ -0,0 +1,134 @@
1
+ import { buildDiagnostic } from "./diagnostics/spec.js";
2
+ import { hygieneDiagnostics } from "./diagnostics/codes/hygiene.js";
3
+ //#region src/hygiene.ts
4
+ /**
5
+ * Request hygiene (D06, ARCHITECTURE §10, HY-01): the checks every Mostra HTTP endpoint applies
6
+ * before it acts on a request, as pure functions with no I/O. The gateway runs them on every
7
+ * request, and `mostra mcp --http` (WP-15) runs the same code (D96), so a request a stranger's
8
+ * page could send is refused the same way everywhere. None of them limits what an artifact, an
9
+ * agent or a viewer may do; they only make sure a request comes from the page it claims to.
10
+ *
11
+ * ```ts
12
+ * const refusal = checkRequest(
13
+ * { origin: "http://127.0.0.1:23456", hosts: ["127.0.0.1:23456"] },
14
+ * { method: "POST", target: "/a/art_…/_mostra/ticket", headers, intent: "mutation", csrf },
15
+ * );
16
+ * if (refusal) return respond(refusal.status, refusal.diagnostic);
17
+ * ```
18
+ */
19
+ /** The header that carries a session's CSRF token on every mutation (D98). */
20
+ const CSRF_HEADER = "x-mostra-csrf";
21
+ const STATUS = {
22
+ MOSTRA_HYGIENE_HOST_REFUSED: 421,
23
+ MOSTRA_HYGIENE_ORIGIN_REFUSED: 403,
24
+ MOSTRA_HYGIENE_CSRF_MISSING: 403,
25
+ MOSTRA_HYGIENE_CONTENT_TYPE: 415,
26
+ MOSTRA_HYGIENE_REQUEST_MALFORMED: 400,
27
+ MOSTRA_HYGIENE_SESSION_MISSING: 401,
28
+ MOSTRA_HYGIENE_TOKEN_INVALID: 401,
29
+ MOSTRA_HYGIENE_TOKEN_REVOKED: 410,
30
+ MOSTRA_HYGIENE_SCOPE_DENIED: 403,
31
+ MOSTRA_HYGIENE_RATE_LIMITED: 429,
32
+ MOSTRA_HYGIENE_NOT_SERVED: 404,
33
+ MOSTRA_HYGIENE_SESSION_CONFLICT: 409,
34
+ MOSTRA_HYGIENE_HEADERS_TOO_LARGE: 431
35
+ };
36
+ /** Builds a refusal with the status the code's HTTP mapping gives (FAILURE_MODEL §8). */
37
+ function refusal(code, message, status) {
38
+ return {
39
+ status: status ?? STATUS[code],
40
+ diagnostic: buildDiagnostic(code, hygieneDiagnostics[code], { message })
41
+ };
42
+ }
43
+ /** Headers that must appear at most once: a second copy could mean two different things. */
44
+ const SINGLE = /* @__PURE__ */ new Set([
45
+ "host",
46
+ "origin",
47
+ "content-type",
48
+ "content-length",
49
+ CSRF_HEADER,
50
+ "cookie"
51
+ ]);
52
+ /** Characters no header value or path may carry: controls other than tab, and DEL. */
53
+ const CONTROL = /[\u0000-\u0008\u000a-\u001f\u007f]/;
54
+ /** Constant-time comparison of two strings, so timing reveals nothing about a secret. */
55
+ function safeEqual(a, b) {
56
+ let difference = a.length ^ b.length;
57
+ const length = Math.max(a.length, b.length);
58
+ for (let index = 0; index < length; index++) difference |= (a.charCodeAt(index) | 0) ^ (b.charCodeAt(index) | 0);
59
+ return difference === 0;
60
+ }
61
+ /**
62
+ * The path a request target names, decoded, or `undefined` when it isn't a safe origin-form path:
63
+ * absolute and authority forms, `*`, encoded `/` or `\`, `.` or `..` segments (encoded or not),
64
+ * NUL and other controls, and invalid percent-encoding are all refused.
65
+ */
66
+ function safePath(target) {
67
+ if (!target.startsWith("/") || target.startsWith("//")) return void 0;
68
+ const end = target.search(/[?#]/);
69
+ const raw = end < 0 ? target : target.slice(0, end);
70
+ if (/%(2f|5c)/i.test(raw) || raw.includes("\\")) return void 0;
71
+ let path;
72
+ try {
73
+ path = decodeURIComponent(raw);
74
+ } catch {
75
+ return;
76
+ }
77
+ if (CONTROL.test(path) || path.includes("\0")) return void 0;
78
+ if (path.split("/").some((segment) => segment === "." || segment === "..")) return void 0;
79
+ return path;
80
+ }
81
+ /** The value of a header (case-insensitive name), or `undefined`. */
82
+ function headerValue(headers, name) {
83
+ const lower = name.toLowerCase();
84
+ return headers.find(([key]) => key.toLowerCase() === lower)?.[1];
85
+ }
86
+ /** Whether a `Content-Type` value is JSON (`application/json`, any parameters). */
87
+ function isJsonContentType(value) {
88
+ if (value === void 0) return false;
89
+ return value.split(";")[0]?.trim().toLowerCase() === "application/json";
90
+ }
91
+ /**
92
+ * Checks a request's envelope (the `Host` allowlist, the request target, repeated and malformed
93
+ * headers) and, when `intent` is given, what that intent needs: `Origin`, the JSON content type
94
+ * and the CSRF token. Returns the first refusal, or `undefined` when the request may proceed.
95
+ * Session, token and scope checks follow in the endpoint, which knows its session.
96
+ */
97
+ function checkRequest(policy, request) {
98
+ const counts = /* @__PURE__ */ new Map();
99
+ for (const [name, value] of request.headers) {
100
+ const lower = name.toLowerCase();
101
+ counts.set(lower, (counts.get(lower) ?? 0) + 1);
102
+ if (CONTROL.test(value)) return refusal("MOSTRA_HYGIENE_REQUEST_MALFORMED", `The ${lower} header has control characters.`);
103
+ }
104
+ for (const name of SINGLE) if ((counts.get(name) ?? 0) > 1) return refusal("MOSTRA_HYGIENE_REQUEST_MALFORMED", `The request repeats the ${name} header.`);
105
+ const host = headerValue(request.headers, "host")?.toLowerCase();
106
+ if (host === void 0 || !policy.hosts.includes(host)) return refusal("MOSTRA_HYGIENE_HOST_REFUSED", host === void 0 ? "The request has no Host header." : "The request's Host isn't one this listener serves.");
107
+ if (safePath(request.target) === void 0) return refusal("MOSTRA_HYGIENE_REQUEST_MALFORMED", "The request target isn't a plain path inside the served tree.");
108
+ if (request.intent === void 0) return void 0;
109
+ const origin = headerValue(request.headers, "origin");
110
+ switch (request.intent) {
111
+ case "read":
112
+ if (origin !== void 0 && origin !== policy.origin) return refusal("MOSTRA_HYGIENE_ORIGIN_REFUSED", "The request came from another origin.");
113
+ return;
114
+ case "stream": {
115
+ const site = headerValue(request.headers, "sec-fetch-site");
116
+ return (origin === void 0 ? site === "same-origin" : origin === policy.origin) ? void 0 : refusal("MOSTRA_HYGIENE_ORIGIN_REFUSED", "A stream must be opened by its own origin.");
117
+ }
118
+ case "upgrade":
119
+ case "exchange":
120
+ case "mutation": {
121
+ if (origin !== policy.origin) return refusal("MOSTRA_HYGIENE_ORIGIN_REFUSED", origin === void 0 ? "The request has no Origin header." : "The request came from another origin.");
122
+ if (request.intent === "upgrade") return void 0;
123
+ if (!isJsonContentType(headerValue(request.headers, "content-type"))) return refusal("MOSTRA_HYGIENE_CONTENT_TYPE", "The request's body isn't declared as JSON.");
124
+ if (request.intent === "exchange") return void 0;
125
+ const sent = headerValue(request.headers, CSRF_HEADER);
126
+ if (request.csrf === void 0 || sent === void 0 || !safeEqual(sent, request.csrf)) return refusal("MOSTRA_HYGIENE_CSRF_MISSING", sent === void 0 ? `The request has no ${CSRF_HEADER} header.` : `The request's ${CSRF_HEADER} header doesn't match its session.`);
127
+ return;
128
+ }
129
+ }
130
+ }
131
+ //#endregion
132
+ export { CSRF_HEADER, checkRequest, headerValue, isJsonContentType, refusal, safeEqual, safePath };
133
+
134
+ //# sourceMappingURL=hygiene.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hygiene.js","names":[],"sources":["../src/hygiene.ts"],"sourcesContent":["/**\n * Request hygiene (D06, ARCHITECTURE §10, HY-01): the checks every Mostra HTTP endpoint applies\n * before it acts on a request, as pure functions with no I/O. The gateway runs them on every\n * request, and `mostra mcp --http` (WP-15) runs the same code (D96), so a request a stranger's\n * page could send is refused the same way everywhere. None of them limits what an artifact, an\n * agent or a viewer may do; they only make sure a request comes from the page it claims to.\n *\n * ```ts\n * const refusal = checkRequest(\n * { origin: \"http://127.0.0.1:23456\", hosts: [\"127.0.0.1:23456\"] },\n * { method: \"POST\", target: \"/a/art_…/_mostra/ticket\", headers, intent: \"mutation\", csrf },\n * );\n * if (refusal) return respond(refusal.status, refusal.diagnostic);\n * ```\n */\nimport { type HygieneDiagnosticCode, hygieneDiagnostics } from \"./diagnostics/codes/hygiene.ts\";\nimport type { Diagnostic } from \"./diagnostics/diagnostic.ts\";\nimport { buildDiagnostic } from \"./diagnostics/spec.ts\";\n\n/** What one listener serves: its own origin and the exact `Host` values it accepts. */\nexport interface RequestPolicy {\n /** The listener's origin, such as `http://127.0.0.1:23456`; `Origin` headers must equal it. */\n readonly origin: string;\n /** Every `host:port` this listener answers to (lowercase): its URL host, plus registered tunnels. */\n readonly hosts: readonly string[];\n}\n\n/**\n * What a request is for, which decides the checks beyond the envelope:\n * - `read`: a GET or HEAD of a page or file; a foreign `Origin` is refused, none is fine.\n * - `stream`: an event stream (GET); same-origin only, by `Origin` or `Sec-Fetch-Site`.\n * - `upgrade`: a WebSocket upgrade; `Origin` must be present and equal.\n * - `exchange`: a mutation that starts a session (a capability token or ticket in the body):\n * `Origin` and a JSON content type, but no CSRF token yet.\n * - `mutation`: any other state change: `Origin`, a JSON content type and the session's CSRF\n * token in `X-Mostra-CSRF`.\n */\nexport type RequestIntent = \"read\" | \"stream\" | \"upgrade\" | \"exchange\" | \"mutation\";\n\n/** One request as the transport received it. */\nexport interface RequestFacts {\n /** The method, as sent. */\n readonly method: string;\n /** The request target exactly as sent: an origin-form path with its query. */\n readonly target: string;\n /** Every header as `[name, value]` in arrival order, so repeated headers are visible. */\n readonly headers: readonly (readonly [string, string])[];\n /** The intent the matched route declared; omit to check only the envelope. */\n readonly intent?: RequestIntent;\n /** The session's CSRF token, for `mutation` requests. */\n readonly csrf?: string;\n}\n\n/** A refused request: the HTTP status to answer with and the diagnostic for its body. */\nexport interface Refusal {\n /** The HTTP status: 400, 401, 403, 404, 410, 415, 421 or 429. */\n readonly status: number;\n /** What was refused and why, for the response body and the log. */\n readonly diagnostic: Diagnostic;\n}\n\n/** The header that carries a session's CSRF token on every mutation (D98). */\nexport const CSRF_HEADER = \"x-mostra-csrf\";\n\nconst STATUS: Readonly<Record<HygieneDiagnosticCode, number>> = {\n MOSTRA_HYGIENE_HOST_REFUSED: 421,\n MOSTRA_HYGIENE_ORIGIN_REFUSED: 403,\n MOSTRA_HYGIENE_CSRF_MISSING: 403,\n MOSTRA_HYGIENE_CONTENT_TYPE: 415,\n MOSTRA_HYGIENE_REQUEST_MALFORMED: 400,\n MOSTRA_HYGIENE_SESSION_MISSING: 401,\n MOSTRA_HYGIENE_TOKEN_INVALID: 401,\n MOSTRA_HYGIENE_TOKEN_REVOKED: 410,\n MOSTRA_HYGIENE_SCOPE_DENIED: 403,\n MOSTRA_HYGIENE_RATE_LIMITED: 429,\n MOSTRA_HYGIENE_NOT_SERVED: 404,\n MOSTRA_HYGIENE_SESSION_CONFLICT: 409,\n MOSTRA_HYGIENE_HEADERS_TOO_LARGE: 431,\n};\n\n/** Builds a refusal with the status the code's HTTP mapping gives (FAILURE_MODEL §8). */\nexport function refusal(code: HygieneDiagnosticCode, message: string, status?: number): Refusal {\n return {\n status: status ?? STATUS[code],\n diagnostic: buildDiagnostic(code, hygieneDiagnostics[code], { message }),\n };\n}\n\n/** Headers that must appear at most once: a second copy could mean two different things. */\nconst SINGLE = new Set([\"host\", \"origin\", \"content-type\", \"content-length\", CSRF_HEADER, \"cookie\"]);\n\n/** Characters no header value or path may carry: controls other than tab, and DEL. */\n// biome-ignore lint/suspicious/noControlCharactersInRegex: matching control characters is the point.\nconst CONTROL = /[\\u0000-\\u0008\\u000a-\\u001f\\u007f]/;\n\n/** Constant-time comparison of two strings, so timing reveals nothing about a secret. */\nexport function safeEqual(a: string, b: string): boolean {\n let difference = a.length ^ b.length;\n const length = Math.max(a.length, b.length);\n for (let index = 0; index < length; index++) {\n difference |= (a.charCodeAt(index) | 0) ^ (b.charCodeAt(index) | 0);\n }\n return difference === 0;\n}\n\n/**\n * The path a request target names, decoded, or `undefined` when it isn't a safe origin-form path:\n * absolute and authority forms, `*`, encoded `/` or `\\`, `.` or `..` segments (encoded or not),\n * NUL and other controls, and invalid percent-encoding are all refused.\n */\nexport function safePath(target: string): string | undefined {\n if (!target.startsWith(\"/\") || target.startsWith(\"//\")) return undefined;\n const end = target.search(/[?#]/);\n const raw = end < 0 ? target : target.slice(0, end);\n if (/%(2f|5c)/i.test(raw) || raw.includes(\"\\\\\")) return undefined;\n let path: string;\n try {\n path = decodeURIComponent(raw);\n } catch {\n return undefined;\n }\n if (CONTROL.test(path) || path.includes(\"\\u0000\")) return undefined;\n if (path.split(\"/\").some((segment) => segment === \".\" || segment === \"..\")) return undefined;\n return path;\n}\n\n/** The value of a header (case-insensitive name), or `undefined`. */\nexport function headerValue(\n headers: readonly (readonly [string, string])[],\n name: string,\n): string | undefined {\n const lower = name.toLowerCase();\n return headers.find(([key]) => key.toLowerCase() === lower)?.[1];\n}\n\n/** Whether a `Content-Type` value is JSON (`application/json`, any parameters). */\nexport function isJsonContentType(value: string | undefined): boolean {\n if (value === undefined) return false;\n return value.split(\";\")[0]?.trim().toLowerCase() === \"application/json\";\n}\n\n/**\n * Checks a request's envelope (the `Host` allowlist, the request target, repeated and malformed\n * headers) and, when `intent` is given, what that intent needs: `Origin`, the JSON content type\n * and the CSRF token. Returns the first refusal, or `undefined` when the request may proceed.\n * Session, token and scope checks follow in the endpoint, which knows its session.\n */\nexport function checkRequest(policy: RequestPolicy, request: RequestFacts): Refusal | undefined {\n const counts = new Map<string, number>();\n for (const [name, value] of request.headers) {\n const lower = name.toLowerCase();\n counts.set(lower, (counts.get(lower) ?? 0) + 1);\n if (CONTROL.test(value)) {\n return refusal(\n \"MOSTRA_HYGIENE_REQUEST_MALFORMED\",\n `The ${lower} header has control characters.`,\n );\n }\n }\n for (const name of SINGLE) {\n if ((counts.get(name) ?? 0) > 1) {\n return refusal(\"MOSTRA_HYGIENE_REQUEST_MALFORMED\", `The request repeats the ${name} header.`);\n }\n }\n const host = headerValue(request.headers, \"host\")?.toLowerCase();\n if (host === undefined || !policy.hosts.includes(host)) {\n return refusal(\n \"MOSTRA_HYGIENE_HOST_REFUSED\",\n host === undefined\n ? \"The request has no Host header.\"\n : \"The request's Host isn't one this listener serves.\",\n );\n }\n if (safePath(request.target) === undefined) {\n return refusal(\n \"MOSTRA_HYGIENE_REQUEST_MALFORMED\",\n \"The request target isn't a plain path inside the served tree.\",\n );\n }\n if (request.intent === undefined) return undefined;\n\n const origin = headerValue(request.headers, \"origin\");\n switch (request.intent) {\n case \"read\":\n if (origin !== undefined && origin !== policy.origin) {\n return refusal(\"MOSTRA_HYGIENE_ORIGIN_REFUSED\", \"The request came from another origin.\");\n }\n return undefined;\n case \"stream\": {\n const site = headerValue(request.headers, \"sec-fetch-site\");\n const sameOrigin = origin === undefined ? site === \"same-origin\" : origin === policy.origin;\n return sameOrigin\n ? undefined\n : refusal(\"MOSTRA_HYGIENE_ORIGIN_REFUSED\", \"A stream must be opened by its own origin.\");\n }\n case \"upgrade\":\n case \"exchange\":\n case \"mutation\": {\n if (origin !== policy.origin) {\n return refusal(\n \"MOSTRA_HYGIENE_ORIGIN_REFUSED\",\n origin === undefined\n ? \"The request has no Origin header.\"\n : \"The request came from another origin.\",\n );\n }\n if (request.intent === \"upgrade\") return undefined;\n if (!isJsonContentType(headerValue(request.headers, \"content-type\"))) {\n return refusal(\"MOSTRA_HYGIENE_CONTENT_TYPE\", \"The request's body isn't declared as JSON.\");\n }\n if (request.intent === \"exchange\") return undefined;\n const sent = headerValue(request.headers, CSRF_HEADER);\n if (request.csrf === undefined || sent === undefined || !safeEqual(sent, request.csrf)) {\n return refusal(\n \"MOSTRA_HYGIENE_CSRF_MISSING\",\n sent === undefined\n ? `The request has no ${CSRF_HEADER} header.`\n : `The request's ${CSRF_HEADER} header doesn't match its session.`,\n );\n }\n return undefined;\n }\n }\n}\n"],"mappings":"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"}
package/dist/ids.d.ts ADDED
@@ -0,0 +1,119 @@
1
+ import * as z from "zod";
2
+ //#region src/ids.d.ts
3
+ /** The prefixes INTERFACES §1 assigns, one per entity. */
4
+ export type IdPrefix = "art" | "ver" | "vw" | "vwr" | "sub" | "dlv" | "run" | "thr" | "cmt" | "tok" | "mut";
5
+ /**
6
+ * A branded ID string. The brand exists only at the type level, so an `Id<"art">` is a plain
7
+ * string at run time and on the wire.
8
+ */
9
+ export type Id<P extends IdPrefix> = `${P}_${string}` & {
10
+ readonly __mostraIdPrefix: P;
11
+ };
12
+ /** How an ID kind's body is formed. */
13
+ export type IdBody = "ulid" | "sha256-base32";
14
+ /** One ID kind: its prefix, validation and schema. */
15
+ export interface IdKind<P extends IdPrefix> {
16
+ /** The prefix, without the underscore. */
17
+ readonly prefix: P;
18
+ /** The entity the ID names, in the PRODUCT vocabulary. */
19
+ readonly entity: string;
20
+ /** How the body is formed. */
21
+ readonly body: IdBody;
22
+ /** The exact form, anchored at both ends. */
23
+ readonly pattern: RegExp;
24
+ /** The Zod schema for this ID, registered for JSON Schema output under the kind's type name. */
25
+ readonly schema: z.ZodType<Id<P>, string>;
26
+ /** Whether `value` is an ID of this kind. */
27
+ is(value: unknown): value is Id<P>;
28
+ /**
29
+ * Returns `value` as an ID of this kind.
30
+ *
31
+ * @throws TypeError when `value` is not of this kind's form. The message names the expected
32
+ * form and never echoes the input.
33
+ */
34
+ parse(value: string): Id<P>;
35
+ }
36
+ /** An ID kind whose body is a ULID that the creator generates. */
37
+ export interface GeneratedIdKind<P extends IdPrefix> extends IdKind<P> {
38
+ /** Generates a new ID from the current time and 80 bits of Web Crypto randomness. */
39
+ create(): Id<P>;
40
+ }
41
+ /** An artifact ID (`art_` + ULID). */
42
+ export type ArtifactId = Id<"art">;
43
+ /** Artifact IDs. */
44
+ export declare const ArtifactId: GeneratedIdKind<"art">;
45
+ /** A version ID (`ver_` + 26 characters of base32 SHA-256): content-addressed, never generated. */
46
+ export type VersionId = Id<"ver">;
47
+ /** The version ID kind, with the content-addressed constructor DATA_MODEL §2 defines. */
48
+ export interface VersionIdKind extends IdKind<"ver"> {
49
+ /**
50
+ * Returns the version ID for a SHA-256 digest: `ver_` plus the first 26 characters of the
51
+ * digest in Crockford base32 (130 bits). The caller computes the digest of the artifact ID's
52
+ * UTF-8 bytes, a `0x00` byte, and the 32-byte `sourceDigest` and `envDigest` (DATA_MODEL §2,
53
+ * D89).
54
+ *
55
+ * @throws RangeError when `digest` is not 32 bytes long.
56
+ */
57
+ fromSha256(digest: Uint8Array): VersionId;
58
+ }
59
+ /** Version IDs. */
60
+ export declare const VersionId: VersionIdKind;
61
+ /** A view ID (`vw_` + ULID). */
62
+ export type ViewId = Id<"vw">;
63
+ /** View IDs. */
64
+ export declare const ViewId: GeneratedIdKind<"vw">;
65
+ /** A viewer ID (`vwr_` + ULID). */
66
+ export type ViewerId = Id<"vwr">;
67
+ /** Viewer IDs. */
68
+ export declare const ViewerId: GeneratedIdKind<"vwr">;
69
+ /** A submission ID (`sub_` + ULID). */
70
+ export type SubmissionId = Id<"sub">;
71
+ /** Submission IDs. */
72
+ export declare const SubmissionId: GeneratedIdKind<"sub">;
73
+ /**
74
+ * A delivery ID (`dlv_` + ULID): one submission's delivery to one host (D105). A redelivery after a
75
+ * crash repeats it, so a host can treat deliveries idempotently.
76
+ */
77
+ export type DeliveryId = Id<"dlv">;
78
+ /** Delivery IDs. */
79
+ export declare const DeliveryId: GeneratedIdKind<"dlv">;
80
+ /** An action run ID (`run_` + ULID). */
81
+ export type RunId = Id<"run">;
82
+ /** Action run IDs. */
83
+ export declare const RunId: GeneratedIdKind<"run">;
84
+ /** A review thread ID (`thr_` + ULID). */
85
+ export type ThreadId = Id<"thr">;
86
+ /** Review thread IDs. */
87
+ export declare const ThreadId: GeneratedIdKind<"thr">;
88
+ /** A comment ID (`cmt_` + ULID). */
89
+ export type CommentId = Id<"cmt">;
90
+ /** Comment IDs. */
91
+ export declare const CommentId: GeneratedIdKind<"cmt">;
92
+ /** A capability token ID (`tok_` + ULID). The token's secret is separate and never an ID. */
93
+ export type TokenId = Id<"tok">;
94
+ /** Capability token IDs. */
95
+ export declare const TokenId: GeneratedIdKind<"tok">;
96
+ /** A mutation ID (`mut_` + ULID), generated by the client that sends the mutation. */
97
+ export type MutationId = Id<"mut">;
98
+ /** Mutation IDs. */
99
+ export declare const MutationId: GeneratedIdKind<"mut">;
100
+ /**
101
+ * An event cursor: the decimal string of a home-wide event position (INTERFACES §1). Decimal
102
+ * strings keep 64-bit positions exact in JavaScript.
103
+ */
104
+ export type Cursor = string & {
105
+ readonly __mostraCursor: true;
106
+ };
107
+ /** Event cursors. */
108
+ export declare const Cursor: {
109
+ /** The exact form: a non-negative decimal integer without leading zeros, at most 19 digits. */
110
+ readonly pattern: RegExp;
111
+ readonly schema: z.ZodType<Cursor, string>;
112
+ is(value: unknown): value is Cursor;
113
+ /** @throws TypeError when `value` is not a cursor. */
114
+ parse(value: string): Cursor;
115
+ /** Orders two cursors: negative when `a` comes first, zero when equal, positive otherwise. */
116
+ compare(a: Cursor, b: Cursor): number;
117
+ };
118
+ //#endregion
119
+ //# sourceMappingURL=ids.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.d.ts","names":[],"sources":["../src/ids.ts"],"mappings":";;;YAmBY;;;;;YAiBA,GAAG,UAAU,eAAe;WAA2B,kBAAkB;;;YAGzE;;iBAGK,OAAO,UAAU;;WAEvB,QAAQ;;WAER;;WAEA,MAAM;;WAEN,SAAS;;WAET,QAAQ,EAAE,QAAQ,GAAG;;EAE9B,GAAG,iBAAiB,SAAS,GAAG;;;;;;;EAOhC,MAAM,gBAAgB,GAAG;;;iBAIV,gBAAgB,UAAU,kBAAkB,OAAO;;EAElE,UAAU,GAAG;;;YAkFH,aAAa;;qBAEZ,YAAY;;YAKb,YAAY;;iBAEP,sBAAsB;;;;;;;;;EASrC,WAAW,QAAQ,aAAa;;;qBAGrB,WAAW;;YAWZ,SAAS;;qBAER,QAAQ;;YAGT,WAAW;;qBAEV,UAAU;;YAKX,eAAe;;qBAEd,cAAc;;;;;YAQf,aAAa;;qBAEZ,YAAY;;YAKb,QAAQ;;qBAEP,OAAO;;YAKR,WAAW;;qBAEV,UAAU;;YAKX,YAAY;;qBAEX,WAAW;;YAKZ,UAAU;;qBAET,SAAS;;YAKV,aAAa;;qBAEZ,YAAY;;;;;YAQb;WAA6B;;;qBAG5B;;WAEF,SAAS;WACT,QAAQ,EAAE,QAAQ;EAC3B,GAAG,iBAAiB,SAAS;;EAE7B,MAAM,gBAAgB;;EAEtB,QAAQ,GAAG,QAAQ,GAAG"}
package/dist/ids.js ADDED
@@ -0,0 +1,135 @@
1
+ import { wireRegistry } from "./wire-registry.js";
2
+ import * as z from "zod";
3
+ //#region src/ids.ts
4
+ /**
5
+ * Prefixed, opaque identifiers (INTERFACES §1, DATA_MODEL §2).
6
+ *
7
+ * Every Mostra entity is named by a string of the form `<prefix>_<body>`. Callers treat IDs as
8
+ * opaque: they validate the form at a boundary and never read meaning out of the body. Each ID
9
+ * kind below is both a type and a value with the same name:
10
+ *
11
+ * ```ts
12
+ * const artifact: ArtifactId = ArtifactId.parse(input);
13
+ * const mutation: MutationId = MutationId.create();
14
+ * const Params = z.object({ artifactId: ArtifactId.schema });
15
+ * ```
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ /** Crockford's base32 alphabet, used by ULIDs and by content-addressed version IDs. */
20
+ const CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
21
+ const BODY_LENGTH = 26;
22
+ /** A ULID's first character encodes at most 3 bits (48-bit time in 26 × 5 = 130 bits). */
23
+ const ULID_BODY = "[0-7][0-9A-HJKMNP-TV-Z]{25}";
24
+ const BASE32_BODY = "[0-9A-HJKMNP-TV-Z]{26}";
25
+ function defineKind(prefix, entity, body, typeName) {
26
+ const pattern = new RegExp(`^${prefix}_${body === "ulid" ? ULID_BODY : BASE32_BODY}$`);
27
+ const form = body === "ulid" ? "a 26-character ULID" : "26 characters of Crockford base32";
28
+ const is = (value) => typeof value === "string" && pattern.test(value);
29
+ return {
30
+ prefix,
31
+ entity,
32
+ body,
33
+ pattern,
34
+ schema: z.string().regex(pattern).register(wireRegistry, {
35
+ id: typeName,
36
+ description: `${entity[0]?.toUpperCase()}${entity.slice(1)} ID: "${prefix}_" followed by ${form}.`
37
+ }),
38
+ is,
39
+ parse(value) {
40
+ if (is(value)) return value;
41
+ throw new TypeError(`Expected ${entity} ID "${prefix}_" followed by ${form}.`);
42
+ }
43
+ };
44
+ }
45
+ function generated(kind) {
46
+ return {
47
+ ...kind,
48
+ create: () => kind.parse(`${kind.prefix}_${ulidBody(Date.now())}`)
49
+ };
50
+ }
51
+ /**
52
+ * Encodes a ULID body: 48 bits of milliseconds since the Unix epoch, then 80 random bits, as 26
53
+ * Crockford base32 characters.
54
+ */
55
+ function ulidBody(now) {
56
+ if (!Number.isSafeInteger(now) || now < 0 || now > 0xffffffffffff) throw new RangeError("ULID time must be a millisecond timestamp between 0 and 2^48 - 1.");
57
+ let time = "";
58
+ let rest = now;
59
+ for (let i = 0; i < 10; i++) {
60
+ time = CROCKFORD.charAt(rest % 32) + time;
61
+ rest = Math.floor(rest / 32);
62
+ }
63
+ const random = /* @__PURE__ */ new Uint8Array(10);
64
+ globalThis.crypto.getRandomValues(random);
65
+ return time + base32(random).slice(0, 16);
66
+ }
67
+ /** Encodes bytes as Crockford base32, most significant bit first, padding the last group with 0. */
68
+ function base32(bytes) {
69
+ let out = "";
70
+ let buffer = 0;
71
+ let bits = 0;
72
+ for (const byte of bytes) {
73
+ buffer = buffer << 8 | byte;
74
+ bits += 8;
75
+ while (bits >= 5) {
76
+ out += CROCKFORD.charAt(buffer >>> bits - 5 & 31);
77
+ bits -= 5;
78
+ }
79
+ buffer &= (1 << bits) - 1;
80
+ }
81
+ if (bits > 0) out += CROCKFORD.charAt(buffer << 5 - bits & 31);
82
+ return out;
83
+ }
84
+ /** Artifact IDs. */
85
+ const ArtifactId = generated(defineKind("art", "artifact", "ulid", "ArtifactId"));
86
+ /** Version IDs. */
87
+ const VersionId = {
88
+ ...defineKind("ver", "version", "sha256-base32", "VersionId"),
89
+ fromSha256(digest) {
90
+ if (digest.length !== 32) throw new RangeError(`A SHA-256 digest is 32 bytes, got ${digest.length}.`);
91
+ return VersionId.parse(`ver_${base32(digest).slice(0, BODY_LENGTH)}`);
92
+ }
93
+ };
94
+ /** View IDs. */
95
+ const ViewId = generated(defineKind("vw", "view", "ulid", "ViewId"));
96
+ /** Viewer IDs. */
97
+ const ViewerId = generated(defineKind("vwr", "viewer", "ulid", "ViewerId"));
98
+ /** Submission IDs. */
99
+ const SubmissionId = generated(defineKind("sub", "submission", "ulid", "SubmissionId"));
100
+ /** Delivery IDs. */
101
+ const DeliveryId = generated(defineKind("dlv", "delivery", "ulid", "DeliveryId"));
102
+ /** Action run IDs. */
103
+ const RunId = generated(defineKind("run", "action run", "ulid", "RunId"));
104
+ /** Review thread IDs. */
105
+ const ThreadId = generated(defineKind("thr", "thread", "ulid", "ThreadId"));
106
+ /** Comment IDs. */
107
+ const CommentId = generated(defineKind("cmt", "comment", "ulid", "CommentId"));
108
+ /** Capability token IDs. */
109
+ const TokenId = generated(defineKind("tok", "capability token", "ulid", "TokenId"));
110
+ /** Mutation IDs. */
111
+ const MutationId = generated(defineKind("mut", "mutation", "ulid", "MutationId"));
112
+ /** Event cursors. */
113
+ const Cursor = (() => {
114
+ const pattern = /^(0|[1-9][0-9]{0,18})$/;
115
+ const is = (value) => typeof value === "string" && pattern.test(value);
116
+ return {
117
+ pattern,
118
+ schema: z.string().regex(pattern).register(wireRegistry, {
119
+ id: "Cursor",
120
+ description: "Event cursor: the decimal string of a home-wide event position."
121
+ }),
122
+ is,
123
+ parse(value) {
124
+ if (is(value)) return value;
125
+ throw new TypeError("Expected an event cursor: a non-negative decimal integer string.");
126
+ },
127
+ compare(a, b) {
128
+ return a.length === b.length ? a < b ? -1 : a > b ? 1 : 0 : a.length - b.length;
129
+ }
130
+ };
131
+ })();
132
+ //#endregion
133
+ export { ArtifactId, CommentId, Cursor, DeliveryId, MutationId, RunId, SubmissionId, ThreadId, TokenId, VersionId, ViewId, ViewerId };
134
+
135
+ //# sourceMappingURL=ids.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.js","names":[],"sources":["../src/ids.ts"],"sourcesContent":["/**\n * Prefixed, opaque identifiers (INTERFACES §1, DATA_MODEL §2).\n *\n * Every Mostra entity is named by a string of the form `<prefix>_<body>`. Callers treat IDs as\n * opaque: they validate the form at a boundary and never read meaning out of the body. Each ID\n * kind below is both a type and a value with the same name:\n *\n * ```ts\n * const artifact: ArtifactId = ArtifactId.parse(input);\n * const mutation: MutationId = MutationId.create();\n * const Params = z.object({ artifactId: ArtifactId.schema });\n * ```\n *\n * @packageDocumentation\n */\nimport * as z from \"zod\";\nimport { wireRegistry } from \"./wire-registry.ts\";\n\n/** The prefixes INTERFACES §1 assigns, one per entity. */\nexport type IdPrefix =\n | \"art\"\n | \"ver\"\n | \"vw\"\n | \"vwr\"\n | \"sub\"\n | \"dlv\"\n | \"run\"\n | \"thr\"\n | \"cmt\"\n | \"tok\"\n | \"mut\";\n\n/**\n * A branded ID string. The brand exists only at the type level, so an `Id<\"art\">` is a plain\n * string at run time and on the wire.\n */\nexport type Id<P extends IdPrefix> = `${P}_${string}` & { readonly __mostraIdPrefix: P };\n\n/** How an ID kind's body is formed. */\nexport type IdBody = \"ulid\" | \"sha256-base32\";\n\n/** One ID kind: its prefix, validation and schema. */\nexport interface IdKind<P extends IdPrefix> {\n /** The prefix, without the underscore. */\n readonly prefix: P;\n /** The entity the ID names, in the PRODUCT vocabulary. */\n readonly entity: string;\n /** How the body is formed. */\n readonly body: IdBody;\n /** The exact form, anchored at both ends. */\n readonly pattern: RegExp;\n /** The Zod schema for this ID, registered for JSON Schema output under the kind's type name. */\n readonly schema: z.ZodType<Id<P>, string>;\n /** Whether `value` is an ID of this kind. */\n is(value: unknown): value is Id<P>;\n /**\n * Returns `value` as an ID of this kind.\n *\n * @throws TypeError when `value` is not of this kind's form. The message names the expected\n * form and never echoes the input.\n */\n parse(value: string): Id<P>;\n}\n\n/** An ID kind whose body is a ULID that the creator generates. */\nexport interface GeneratedIdKind<P extends IdPrefix> extends IdKind<P> {\n /** Generates a new ID from the current time and 80 bits of Web Crypto randomness. */\n create(): Id<P>;\n}\n\n/** Crockford's base32 alphabet, used by ULIDs and by content-addressed version IDs. */\nconst CROCKFORD = \"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";\nconst BODY_LENGTH = 26;\n/** A ULID's first character encodes at most 3 bits (48-bit time in 26 × 5 = 130 bits). */\nconst ULID_BODY = \"[0-7][0-9A-HJKMNP-TV-Z]{25}\";\nconst BASE32_BODY = \"[0-9A-HJKMNP-TV-Z]{26}\";\n\nfunction defineKind<P extends IdPrefix>(\n prefix: P,\n entity: string,\n body: IdBody,\n typeName: string,\n): IdKind<P> {\n const pattern = new RegExp(`^${prefix}_${body === \"ulid\" ? ULID_BODY : BASE32_BODY}$`);\n const form = body === \"ulid\" ? \"a 26-character ULID\" : \"26 characters of Crockford base32\";\n const is = (value: unknown): value is Id<P> => typeof value === \"string\" && pattern.test(value);\n const schema = z\n .string()\n .regex(pattern)\n .register(wireRegistry, {\n id: typeName,\n description: `${entity[0]?.toUpperCase()}${entity.slice(1)} ID: \"${prefix}_\" followed by ${form}.`,\n }) as unknown as z.ZodType<Id<P>, string>;\n return {\n prefix,\n entity,\n body,\n pattern,\n schema,\n is,\n parse(value: string): Id<P> {\n if (is(value)) return value;\n throw new TypeError(`Expected ${entity} ID \"${prefix}_\" followed by ${form}.`);\n },\n };\n}\n\nfunction generated<P extends IdPrefix>(kind: IdKind<P>): GeneratedIdKind<P> {\n return { ...kind, create: () => kind.parse(`${kind.prefix}_${ulidBody(Date.now())}`) };\n}\n\n/**\n * Encodes a ULID body: 48 bits of milliseconds since the Unix epoch, then 80 random bits, as 26\n * Crockford base32 characters.\n */\nfunction ulidBody(now: number): string {\n if (!Number.isSafeInteger(now) || now < 0 || now > 0xffff_ffff_ffff) {\n throw new RangeError(\"ULID time must be a millisecond timestamp between 0 and 2^48 - 1.\");\n }\n let time = \"\";\n let rest = now;\n for (let i = 0; i < 10; i++) {\n time = CROCKFORD.charAt(rest % 32) + time;\n rest = Math.floor(rest / 32);\n }\n const random = new Uint8Array(10);\n globalThis.crypto.getRandomValues(random);\n return time + base32(random).slice(0, 16);\n}\n\n/** Encodes bytes as Crockford base32, most significant bit first, padding the last group with 0. */\nfunction base32(bytes: Uint8Array): string {\n let out = \"\";\n let buffer = 0;\n let bits = 0;\n for (const byte of bytes) {\n buffer = (buffer << 8) | byte;\n bits += 8;\n while (bits >= 5) {\n out += CROCKFORD.charAt((buffer >>> (bits - 5)) & 31);\n bits -= 5;\n }\n buffer &= (1 << bits) - 1;\n }\n if (bits > 0) out += CROCKFORD.charAt((buffer << (5 - bits)) & 31);\n return out;\n}\n\n/** An artifact ID (`art_` + ULID). */\nexport type ArtifactId = Id<\"art\">;\n/** Artifact IDs. */\nexport const ArtifactId: GeneratedIdKind<\"art\"> = generated(\n defineKind(\"art\", \"artifact\", \"ulid\", \"ArtifactId\"),\n);\n\n/** A version ID (`ver_` + 26 characters of base32 SHA-256): content-addressed, never generated. */\nexport type VersionId = Id<\"ver\">;\n/** The version ID kind, with the content-addressed constructor DATA_MODEL §2 defines. */\nexport interface VersionIdKind extends IdKind<\"ver\"> {\n /**\n * Returns the version ID for a SHA-256 digest: `ver_` plus the first 26 characters of the\n * digest in Crockford base32 (130 bits). The caller computes the digest of the artifact ID's\n * UTF-8 bytes, a `0x00` byte, and the 32-byte `sourceDigest` and `envDigest` (DATA_MODEL §2,\n * D89).\n *\n * @throws RangeError when `digest` is not 32 bytes long.\n */\n fromSha256(digest: Uint8Array): VersionId;\n}\n/** Version IDs. */\nexport const VersionId: VersionIdKind = {\n ...defineKind(\"ver\", \"version\", \"sha256-base32\", \"VersionId\"),\n fromSha256(digest: Uint8Array): VersionId {\n if (digest.length !== 32) {\n throw new RangeError(`A SHA-256 digest is 32 bytes, got ${digest.length}.`);\n }\n return VersionId.parse(`ver_${base32(digest).slice(0, BODY_LENGTH)}`);\n },\n};\n\n/** A view ID (`vw_` + ULID). */\nexport type ViewId = Id<\"vw\">;\n/** View IDs. */\nexport const ViewId: GeneratedIdKind<\"vw\"> = generated(defineKind(\"vw\", \"view\", \"ulid\", \"ViewId\"));\n\n/** A viewer ID (`vwr_` + ULID). */\nexport type ViewerId = Id<\"vwr\">;\n/** Viewer IDs. */\nexport const ViewerId: GeneratedIdKind<\"vwr\"> = generated(\n defineKind(\"vwr\", \"viewer\", \"ulid\", \"ViewerId\"),\n);\n\n/** A submission ID (`sub_` + ULID). */\nexport type SubmissionId = Id<\"sub\">;\n/** Submission IDs. */\nexport const SubmissionId: GeneratedIdKind<\"sub\"> = generated(\n defineKind(\"sub\", \"submission\", \"ulid\", \"SubmissionId\"),\n);\n\n/**\n * A delivery ID (`dlv_` + ULID): one submission's delivery to one host (D105). A redelivery after a\n * crash repeats it, so a host can treat deliveries idempotently.\n */\nexport type DeliveryId = Id<\"dlv\">;\n/** Delivery IDs. */\nexport const DeliveryId: GeneratedIdKind<\"dlv\"> = generated(\n defineKind(\"dlv\", \"delivery\", \"ulid\", \"DeliveryId\"),\n);\n\n/** An action run ID (`run_` + ULID). */\nexport type RunId = Id<\"run\">;\n/** Action run IDs. */\nexport const RunId: GeneratedIdKind<\"run\"> = generated(\n defineKind(\"run\", \"action run\", \"ulid\", \"RunId\"),\n);\n\n/** A review thread ID (`thr_` + ULID). */\nexport type ThreadId = Id<\"thr\">;\n/** Review thread IDs. */\nexport const ThreadId: GeneratedIdKind<\"thr\"> = generated(\n defineKind(\"thr\", \"thread\", \"ulid\", \"ThreadId\"),\n);\n\n/** A comment ID (`cmt_` + ULID). */\nexport type CommentId = Id<\"cmt\">;\n/** Comment IDs. */\nexport const CommentId: GeneratedIdKind<\"cmt\"> = generated(\n defineKind(\"cmt\", \"comment\", \"ulid\", \"CommentId\"),\n);\n\n/** A capability token ID (`tok_` + ULID). The token's secret is separate and never an ID. */\nexport type TokenId = Id<\"tok\">;\n/** Capability token IDs. */\nexport const TokenId: GeneratedIdKind<\"tok\"> = generated(\n defineKind(\"tok\", \"capability token\", \"ulid\", \"TokenId\"),\n);\n\n/** A mutation ID (`mut_` + ULID), generated by the client that sends the mutation. */\nexport type MutationId = Id<\"mut\">;\n/** Mutation IDs. */\nexport const MutationId: GeneratedIdKind<\"mut\"> = generated(\n defineKind(\"mut\", \"mutation\", \"ulid\", \"MutationId\"),\n);\n\n/**\n * An event cursor: the decimal string of a home-wide event position (INTERFACES §1). Decimal\n * strings keep 64-bit positions exact in JavaScript.\n */\nexport type Cursor = string & { readonly __mostraCursor: true };\n\n/** Event cursors. */\nexport const Cursor: {\n /** The exact form: a non-negative decimal integer without leading zeros, at most 19 digits. */\n readonly pattern: RegExp;\n readonly schema: z.ZodType<Cursor, string>;\n is(value: unknown): value is Cursor;\n /** @throws TypeError when `value` is not a cursor. */\n parse(value: string): Cursor;\n /** Orders two cursors: negative when `a` comes first, zero when equal, positive otherwise. */\n compare(a: Cursor, b: Cursor): number;\n} = (() => {\n const pattern = /^(0|[1-9][0-9]{0,18})$/;\n const is = (value: unknown): value is Cursor => typeof value === \"string\" && pattern.test(value);\n return {\n pattern,\n schema: z.string().regex(pattern).register(wireRegistry, {\n id: \"Cursor\",\n description: \"Event cursor: the decimal string of a home-wide event position.\",\n }) as unknown as z.ZodType<Cursor, string>,\n is,\n parse(value: string): Cursor {\n if (is(value)) return value;\n throw new TypeError(\"Expected an event cursor: a non-negative decimal integer string.\");\n },\n compare(a: Cursor, b: Cursor): number {\n return a.length === b.length ? (a < b ? -1 : a > b ? 1 : 0) : a.length - b.length;\n },\n };\n})();\n"],"mappings":"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"}