@pithy-sh/core 0.12.0 → 0.14.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 (362) hide show
  1. package/README.md +54 -0
  2. package/dist/audit/auditEvent.js +1 -1
  3. package/dist/audit/chain.d.ts +289 -0
  4. package/dist/audit/chain.d.ts.map +1 -0
  5. package/dist/audit/chain.js +400 -0
  6. package/dist/audit/citations.d.ts +52 -0
  7. package/dist/audit/citations.d.ts.map +1 -0
  8. package/dist/audit/citations.js +13 -0
  9. package/dist/audit/composed.d.ts +18 -0
  10. package/dist/audit/composed.d.ts.map +1 -0
  11. package/dist/audit/composed.js +28 -0
  12. package/dist/capability/bindings.d.ts +22 -0
  13. package/dist/capability/bindings.d.ts.map +1 -1
  14. package/dist/capability/bindings.js +32 -2
  15. package/dist/capability/capability.d.ts +133 -15
  16. package/dist/capability/capability.d.ts.map +1 -1
  17. package/dist/capability/capability.js +17 -2
  18. package/dist/capability/erasure.d.ts +75 -0
  19. package/dist/capability/erasure.d.ts.map +1 -0
  20. package/dist/capability/erasure.js +2 -0
  21. package/dist/capability/manifest.d.ts +5 -0
  22. package/dist/capability/manifest.d.ts.map +1 -1
  23. package/dist/capability/personColumns.d.ts +28 -0
  24. package/dist/capability/personColumns.d.ts.map +1 -0
  25. package/dist/capability/personColumns.js +66 -0
  26. package/dist/capability/personRows.d.ts +62 -0
  27. package/dist/capability/personRows.d.ts.map +1 -0
  28. package/dist/capability/personRows.js +59 -0
  29. package/dist/capability/purge.d.ts +113 -4
  30. package/dist/capability/purge.d.ts.map +1 -1
  31. package/dist/capability/purge.js +138 -5
  32. package/dist/capability/settings.d.ts +10 -0
  33. package/dist/capability/settings.d.ts.map +1 -1
  34. package/dist/capability/vectorIndex.d.ts +36 -0
  35. package/dist/capability/vectorIndex.d.ts.map +1 -0
  36. package/dist/capability/vectorIndex.js +25 -0
  37. package/dist/cli/commandCatalog.generated.d.ts +434 -4
  38. package/dist/cli/commandCatalog.generated.d.ts.map +1 -1
  39. package/dist/cli/commandCatalog.generated.js +455 -2
  40. package/dist/cli/commandFacts.d.ts +8 -5
  41. package/dist/cli/commandFacts.d.ts.map +1 -1
  42. package/dist/cli/commandFacts.js +12 -3
  43. package/dist/consent/purpose.d.ts +70 -0
  44. package/dist/consent/purpose.d.ts.map +1 -0
  45. package/dist/consent/purpose.js +97 -0
  46. package/dist/consent/reader.d.ts +99 -0
  47. package/dist/consent/reader.d.ts.map +1 -0
  48. package/dist/consent/reader.js +33 -0
  49. package/dist/controlPlane/audit/actions.d.ts +15 -4
  50. package/dist/controlPlane/audit/actions.d.ts.map +1 -1
  51. package/dist/controlPlane/audit/actions.js +16 -5
  52. package/dist/controlPlane/capability.d.ts +10 -0
  53. package/dist/controlPlane/capability.d.ts.map +1 -1
  54. package/dist/controlPlane/capability.js +56 -8
  55. package/dist/controlPlane/context.d.ts +4 -0
  56. package/dist/controlPlane/context.d.ts.map +1 -1
  57. package/dist/controlPlane/context.js +3 -2
  58. package/dist/controlPlane/data/connection.d.ts +21 -2
  59. package/dist/controlPlane/data/connection.d.ts.map +1 -1
  60. package/dist/controlPlane/data/connection.js +13 -4
  61. package/dist/controlPlane/data/connections.d.ts +94 -0
  62. package/dist/controlPlane/data/connections.d.ts.map +1 -0
  63. package/dist/controlPlane/data/connections.js +151 -0
  64. package/dist/controlPlane/data/hold.d.ts +46 -0
  65. package/dist/controlPlane/data/hold.d.ts.map +1 -0
  66. package/dist/controlPlane/data/hold.js +36 -0
  67. package/dist/controlPlane/data/oidcTrust.d.ts +122 -0
  68. package/dist/controlPlane/data/oidcTrust.d.ts.map +1 -0
  69. package/dist/controlPlane/data/oidcTrust.js +173 -0
  70. package/dist/controlPlane/data/tables.d.ts +4 -0
  71. package/dist/controlPlane/data/tables.d.ts.map +1 -1
  72. package/dist/controlPlane/data/tables.js +9 -4
  73. package/dist/controlPlane/data/trustFirstCall.d.ts +16 -0
  74. package/dist/controlPlane/data/trustFirstCall.d.ts.map +1 -0
  75. package/dist/controlPlane/data/trustFirstCall.js +25 -0
  76. package/dist/controlPlane/discovery/adminRoute.d.ts +165 -2
  77. package/dist/controlPlane/discovery/adminRoute.d.ts.map +1 -1
  78. package/dist/controlPlane/discovery/adminRoute.js +32 -8
  79. package/dist/controlPlane/discovery/routeInput.d.ts +23 -0
  80. package/dist/controlPlane/discovery/routeInput.d.ts.map +1 -0
  81. package/dist/controlPlane/discovery/routeInput.js +80 -0
  82. package/dist/controlPlane/discovery/toolName.d.ts +21 -0
  83. package/dist/controlPlane/discovery/toolName.d.ts.map +1 -0
  84. package/dist/controlPlane/discovery/toolName.js +25 -0
  85. package/dist/controlPlane/erasure/attest.d.ts +78 -0
  86. package/dist/controlPlane/erasure/attest.d.ts.map +1 -0
  87. package/dist/controlPlane/erasure/attest.js +164 -0
  88. package/dist/controlPlane/erasure/read.d.ts +39 -0
  89. package/dist/controlPlane/erasure/read.d.ts.map +1 -0
  90. package/dist/controlPlane/erasure/read.js +140 -0
  91. package/dist/controlPlane/error/errors.d.ts +61 -2
  92. package/dist/controlPlane/error/errors.d.ts.map +1 -1
  93. package/dist/controlPlane/error/errors.js +13 -0
  94. package/dist/controlPlane/evidence/derive.d.ts +124 -0
  95. package/dist/controlPlane/evidence/derive.d.ts.map +1 -0
  96. package/dist/controlPlane/evidence/derive.js +343 -0
  97. package/dist/controlPlane/evidence/mapping.d.ts +85 -0
  98. package/dist/controlPlane/evidence/mapping.d.ts.map +1 -0
  99. package/dist/controlPlane/evidence/mapping.js +114 -0
  100. package/dist/controlPlane/evidence/pack.d.ts +46 -0
  101. package/dist/controlPlane/evidence/pack.d.ts.map +1 -0
  102. package/dist/controlPlane/evidence/pack.js +124 -0
  103. package/dist/controlPlane/http/connections.d.ts +96 -0
  104. package/dist/controlPlane/http/connections.d.ts.map +1 -0
  105. package/dist/controlPlane/http/connections.js +109 -0
  106. package/dist/controlPlane/http/guard.d.ts +23 -2
  107. package/dist/controlPlane/http/guard.d.ts.map +1 -1
  108. package/dist/controlPlane/http/guard.js +103 -7
  109. package/dist/controlPlane/http/handlers.d.ts +212 -10
  110. package/dist/controlPlane/http/handlers.d.ts.map +1 -1
  111. package/dist/controlPlane/http/handlers.js +117 -26
  112. package/dist/controlPlane/http/holds.d.ts +57 -0
  113. package/dist/controlPlane/http/holds.d.ts.map +1 -0
  114. package/dist/controlPlane/http/holds.js +98 -0
  115. package/dist/controlPlane/http/presence.d.ts +27 -0
  116. package/dist/controlPlane/http/presence.d.ts.map +1 -0
  117. package/dist/controlPlane/http/presence.js +67 -0
  118. package/dist/controlPlane/http/processing.d.ts +73 -0
  119. package/dist/controlPlane/http/processing.d.ts.map +1 -0
  120. package/dist/controlPlane/http/processing.js +17 -0
  121. package/dist/controlPlane/http/responses.d.ts +927 -3
  122. package/dist/controlPlane/http/responses.d.ts.map +1 -1
  123. package/dist/controlPlane/http/responses.js +283 -7
  124. package/dist/controlPlane/http/routes.d.ts +12 -2
  125. package/dist/controlPlane/http/routes.d.ts.map +1 -1
  126. package/dist/controlPlane/http/routes.js +182 -5
  127. package/dist/controlPlane/http/schemas.d.ts +63 -0
  128. package/dist/controlPlane/http/schemas.d.ts.map +1 -1
  129. package/dist/controlPlane/http/schemas.js +39 -1
  130. package/dist/controlPlane/http/verify.d.ts.map +1 -1
  131. package/dist/controlPlane/http/verify.js +13 -1
  132. package/dist/controlPlane/http/verifyTrust.d.ts +76 -0
  133. package/dist/controlPlane/http/verifyTrust.d.ts.map +1 -0
  134. package/dist/controlPlane/http/verifyTrust.js +75 -0
  135. package/dist/controlPlane/migrations/0004_connection_trusts.d.ts +15 -0
  136. package/dist/controlPlane/migrations/0004_connection_trusts.d.ts.map +1 -0
  137. package/dist/controlPlane/migrations/0004_connection_trusts.js +23 -0
  138. package/dist/controlPlane/migrations/0005_holds.d.ts +12 -0
  139. package/dist/controlPlane/migrations/0005_holds.d.ts.map +1 -0
  140. package/dist/controlPlane/migrations/0005_holds.js +26 -0
  141. package/dist/controlPlane/processing/derive.d.ts +77 -0
  142. package/dist/controlPlane/processing/derive.d.ts.map +1 -0
  143. package/dist/controlPlane/processing/derive.js +206 -0
  144. package/dist/controlPlane/processing/read.d.ts +10 -0
  145. package/dist/controlPlane/processing/read.d.ts.map +1 -0
  146. package/dist/controlPlane/processing/read.js +89 -0
  147. package/dist/controlPlane/scope/kind.d.ts +46 -0
  148. package/dist/controlPlane/scope/kind.d.ts.map +1 -0
  149. package/dist/controlPlane/scope/kind.js +52 -0
  150. package/dist/controlPlane/scope/scope.d.ts +58 -3
  151. package/dist/controlPlane/scope/scope.d.ts.map +1 -1
  152. package/dist/controlPlane/scope/scope.js +59 -4
  153. package/dist/controlPlane/token/jws.js +1 -1
  154. package/dist/controlPlane/token/mint.js +1 -1
  155. package/dist/controlPlane/wire.d.ts +23 -0
  156. package/dist/controlPlane/wire.d.ts.map +1 -1
  157. package/dist/controlPlane/wire.js +24 -1
  158. package/dist/createBackend.d.ts +13 -0
  159. package/dist/createBackend.d.ts.map +1 -1
  160. package/dist/createBackend.js +11 -3
  161. package/dist/createEntrypoint.d.ts +14 -1
  162. package/dist/createEntrypoint.d.ts.map +1 -1
  163. package/dist/createEntrypoint.js +19 -5
  164. package/dist/error/http.d.ts +216 -0
  165. package/dist/error/http.d.ts.map +1 -1
  166. package/dist/error/payload.d.ts +432 -0
  167. package/dist/error/payload.d.ts.map +1 -1
  168. package/dist/error/payload.js +144 -0
  169. package/dist/error/pithyError.d.ts +22 -0
  170. package/dist/error/pithyError.d.ts.map +1 -1
  171. package/dist/error/pithyError.js +31 -1
  172. package/dist/http/routeSpec.d.ts +46 -1
  173. package/dist/http/routeSpec.d.ts.map +1 -1
  174. package/dist/http/routeSpec.js +39 -5
  175. package/dist/http/validation.d.ts +11 -2
  176. package/dist/http/validation.d.ts.map +1 -1
  177. package/dist/http/validation.js +20 -3
  178. package/dist/http/verification.d.ts.map +1 -1
  179. package/dist/http/verification.js +1 -1
  180. package/dist/i18n/translator.d.ts +2 -1
  181. package/dist/i18n/translator.d.ts.map +1 -1
  182. package/dist/index.d.ts +1 -1
  183. package/dist/index.d.ts.map +1 -1
  184. package/dist/index.js +3 -3
  185. package/dist/logger/record.d.ts +126 -0
  186. package/dist/logger/record.d.ts.map +1 -1
  187. package/dist/mcp/annotations.d.ts +20 -0
  188. package/dist/mcp/annotations.d.ts.map +1 -0
  189. package/dist/mcp/annotations.js +23 -0
  190. package/dist/mcp/tools.d.ts +75 -0
  191. package/dist/mcp/tools.d.ts.map +1 -0
  192. package/dist/mcp/tools.js +118 -0
  193. package/dist/openapi/document.d.ts.map +1 -1
  194. package/dist/openapi/document.js +8 -26
  195. package/dist/openapi/operations.d.ts +35 -0
  196. package/dist/openapi/operations.d.ts.map +1 -0
  197. package/dist/openapi/operations.js +37 -0
  198. package/dist/presence/channel.d.ts +11 -0
  199. package/dist/presence/channel.d.ts.map +1 -0
  200. package/dist/presence/channel.js +65 -0
  201. package/dist/presence/declaration.d.ts +154 -0
  202. package/dist/presence/declaration.d.ts.map +1 -0
  203. package/dist/presence/declaration.js +164 -0
  204. package/dist/presence/durableObject.d.ts +61 -0
  205. package/dist/presence/durableObject.d.ts.map +1 -0
  206. package/dist/presence/durableObject.js +257 -0
  207. package/dist/presence/frames.d.ts +166 -0
  208. package/dist/presence/frames.d.ts.map +1 -0
  209. package/dist/presence/frames.js +90 -0
  210. package/dist/presence/http/guard.d.ts +11 -0
  211. package/dist/presence/http/guard.d.ts.map +1 -0
  212. package/dist/presence/http/guard.js +20 -0
  213. package/dist/presence/http/responses.d.ts +31 -0
  214. package/dist/presence/http/responses.d.ts.map +1 -0
  215. package/dist/presence/http/responses.js +34 -0
  216. package/dist/presence/http/routes.d.ts +24 -0
  217. package/dist/presence/http/routes.d.ts.map +1 -0
  218. package/dist/presence/http/routes.js +127 -0
  219. package/dist/presence/http/schemas.d.ts +29 -0
  220. package/dist/presence/http/schemas.d.ts.map +1 -0
  221. package/dist/presence/http/schemas.js +28 -0
  222. package/dist/presence/names.d.ts +23 -0
  223. package/dist/presence/names.d.ts.map +1 -0
  224. package/dist/presence/names.js +22 -0
  225. package/dist/presence/room.d.ts +95 -0
  226. package/dist/presence/room.d.ts.map +1 -0
  227. package/dist/presence/room.js +105 -0
  228. package/dist/presence/ticket.d.ts +55 -0
  229. package/dist/presence/ticket.d.ts.map +1 -0
  230. package/dist/presence/ticket.js +109 -0
  231. package/dist/privacy/classify.js +1 -1
  232. package/dist/privacy/encrypted.js +1 -1
  233. package/dist/processing/activity.d.ts +134 -0
  234. package/dist/processing/activity.d.ts.map +1 -0
  235. package/dist/processing/activity.js +161 -0
  236. package/dist/processing/composed.d.ts +18 -0
  237. package/dist/processing/composed.d.ts.map +1 -0
  238. package/dist/processing/composed.js +28 -0
  239. package/dist/processing/vocabulary.d.ts +26 -0
  240. package/dist/processing/vocabulary.d.ts.map +1 -0
  241. package/dist/processing/vocabulary.js +35 -0
  242. package/dist/queue/consumer.d.ts +59 -0
  243. package/dist/queue/consumer.d.ts.map +1 -0
  244. package/dist/queue/consumer.js +46 -0
  245. package/dist/retention/composed.d.ts +37 -0
  246. package/dist/retention/composed.d.ts.map +1 -0
  247. package/dist/retention/composed.js +66 -0
  248. package/dist/retention/holds.d.ts +61 -0
  249. package/dist/retention/holds.d.ts.map +1 -0
  250. package/dist/retention/holds.js +107 -0
  251. package/dist/retention/holdsPurge.d.ts +22 -0
  252. package/dist/retention/holdsPurge.d.ts.map +1 -0
  253. package/dist/retention/holdsPurge.js +50 -0
  254. package/dist/retention/policy.d.ts +132 -0
  255. package/dist/retention/policy.d.ts.map +1 -0
  256. package/dist/retention/policy.js +197 -0
  257. package/dist/session/rotated.d.ts +34 -0
  258. package/dist/session/rotated.d.ts.map +1 -0
  259. package/dist/session/rotated.js +25 -0
  260. package/dist/test-utils/connectionFixtures.d.ts +13 -0
  261. package/dist/test-utils/connectionFixtures.d.ts.map +1 -0
  262. package/dist/test-utils/connectionFixtures.js +58 -0
  263. package/dist/test-utils/interleave.d.ts +12 -0
  264. package/dist/test-utils/interleave.d.ts.map +1 -0
  265. package/dist/test-utils/interleave.js +26 -0
  266. package/dist/testWorker.d.ts +8 -0
  267. package/dist/testWorker.d.ts.map +1 -0
  268. package/dist/testWorker.js +9 -0
  269. package/dist/version.generated.d.ts +1 -1
  270. package/dist/version.generated.js +1 -1
  271. package/dist/workflow/dispatchRoute.js +1 -1
  272. package/package.json +1 -1
  273. package/src/audit/auditEvent.ts +1 -1
  274. package/src/audit/chain.ts +551 -0
  275. package/src/audit/citations.ts +63 -0
  276. package/src/audit/composed.ts +30 -0
  277. package/src/capability/bindings.ts +61 -0
  278. package/src/capability/capability.ts +166 -18
  279. package/src/capability/erasure.ts +82 -0
  280. package/src/capability/personColumns.ts +83 -0
  281. package/src/capability/personRows.ts +125 -0
  282. package/src/capability/purge.ts +208 -8
  283. package/src/capability/settings.ts +7 -0
  284. package/src/capability/vectorIndex.ts +60 -0
  285. package/src/cli/commandCatalog.generated.ts +488 -2
  286. package/src/cli/commandFacts.ts +12 -3
  287. package/src/cloudflare-test.d.ts +3 -1
  288. package/src/consent/purpose.ts +160 -0
  289. package/src/consent/reader.ts +134 -0
  290. package/src/controlPlane/audit/actions.ts +15 -4
  291. package/src/controlPlane/capability.ts +99 -20
  292. package/src/controlPlane/context.ts +10 -2
  293. package/src/controlPlane/data/connection.ts +16 -2
  294. package/src/controlPlane/data/connections.ts +231 -0
  295. package/src/controlPlane/data/hold.ts +52 -0
  296. package/src/controlPlane/data/oidcTrust.ts +249 -0
  297. package/src/controlPlane/data/tables.ts +7 -0
  298. package/src/controlPlane/data/trustFirstCall.ts +37 -0
  299. package/src/controlPlane/discovery/adminRoute.ts +71 -9
  300. package/src/controlPlane/discovery/routeInput.ts +86 -0
  301. package/src/controlPlane/discovery/toolName.ts +23 -0
  302. package/src/controlPlane/erasure/attest.ts +205 -0
  303. package/src/controlPlane/erasure/read.ts +169 -0
  304. package/src/controlPlane/error/errors.ts +69 -2
  305. package/src/controlPlane/evidence/derive.ts +426 -0
  306. package/src/controlPlane/evidence/mapping.ts +118 -0
  307. package/src/controlPlane/evidence/pack.ts +190 -0
  308. package/src/controlPlane/http/connections.ts +129 -0
  309. package/src/controlPlane/http/guard.ts +178 -10
  310. package/src/controlPlane/http/handlers.ts +172 -40
  311. package/src/controlPlane/http/holds.ts +108 -0
  312. package/src/controlPlane/http/presence.ts +71 -0
  313. package/src/controlPlane/http/processing.ts +19 -0
  314. package/src/controlPlane/http/responses.ts +590 -7
  315. package/src/controlPlane/http/routes.ts +302 -3
  316. package/src/controlPlane/http/schemas.ts +126 -0
  317. package/src/controlPlane/http/verify.ts +19 -2
  318. package/src/controlPlane/http/verifyTrust.ts +176 -0
  319. package/src/controlPlane/migrations/0004_connection_trusts.ts +30 -0
  320. package/src/controlPlane/migrations/0005_holds.ts +40 -0
  321. package/src/controlPlane/processing/derive.ts +359 -0
  322. package/src/controlPlane/processing/read.ts +102 -0
  323. package/src/controlPlane/scope/kind.ts +63 -0
  324. package/src/controlPlane/scope/scope.ts +65 -3
  325. package/src/controlPlane/wire.ts +26 -0
  326. package/src/createBackend.ts +31 -6
  327. package/src/createEntrypoint.ts +34 -2
  328. package/src/error/payload.ts +302 -0
  329. package/src/error/pithyError.ts +42 -0
  330. package/src/http/routeSpec.ts +75 -5
  331. package/src/http/validation.ts +35 -3
  332. package/src/http/verification.ts +3 -1
  333. package/src/i18n/translator.ts +2 -1
  334. package/src/index.ts +2 -0
  335. package/src/mcp/annotations.ts +38 -0
  336. package/src/mcp/tools.ts +220 -0
  337. package/src/openapi/document.ts +8 -28
  338. package/src/openapi/operations.ts +62 -0
  339. package/src/presence/channel.ts +46 -0
  340. package/src/presence/declaration.ts +283 -0
  341. package/src/presence/durableObject.ts +287 -0
  342. package/src/presence/frames.ts +153 -0
  343. package/src/presence/http/guard.ts +23 -0
  344. package/src/presence/http/responses.ts +63 -0
  345. package/src/presence/http/routes.ts +165 -0
  346. package/src/presence/http/schemas.ts +39 -0
  347. package/src/presence/names.ts +45 -0
  348. package/src/presence/room.ts +145 -0
  349. package/src/presence/ticket.ts +145 -0
  350. package/src/processing/activity.ts +289 -0
  351. package/src/processing/composed.ts +33 -0
  352. package/src/processing/vocabulary.ts +43 -0
  353. package/src/queue/consumer.ts +104 -0
  354. package/src/retention/composed.ts +75 -0
  355. package/src/retention/holds.ts +175 -0
  356. package/src/retention/holdsPurge.ts +50 -0
  357. package/src/retention/policy.ts +305 -0
  358. package/src/session/rotated.ts +53 -0
  359. package/src/test-utils/connectionFixtures.ts +58 -0
  360. package/src/test-utils/interleave.ts +31 -0
  361. package/src/testWorker.ts +13 -0
  362. package/src/version.generated.ts +1 -1
@@ -41,14 +41,14 @@ const MANIFEST_READ_SCOPE = "manifest:read";
41
41
  const KEYS_ROTATE_SCOPE = "keys:rotate";
42
42
  /**
43
43
  * Read where each database this Worker binds stands: what is applied, what is pending, what is undeclared,
44
- * and which run put it there (#729). Read-only by construction — every route behind it is a `GET`, and
44
+ * and which run put it there. Read-only by construction — every route behind it is a `GET`, and
45
45
  * nothing over the seam runs, reverses or resets a migration. The two migration health keys on the seam's
46
46
  * manifest entry sit behind it too, so a connection without it gets no number rather than a zero.
47
47
  */
48
48
  const MIGRATIONS_READ_SCOPE = "migrations:read";
49
49
  /**
50
50
  * Read this Worker's full privacy inventory: every storage schema holding a marked field, each marked field's
51
- * path, its class, and where it is stored (#132). Read-only — the one route behind it is a `GET`.
51
+ * path, its class, and where it is stored. Read-only — the one route behind it is a `GET`.
52
52
  *
53
53
  * **Its own scope rather than `manifest:read`**, because field names are the kind of thing an adopter may
54
54
  * reasonably withhold from a client that has no business seeing them. The manifest's privacy block carries
@@ -56,10 +56,65 @@ const MIGRATIONS_READ_SCOPE = "migrations:read";
56
56
  */
57
57
  const PRIVACY_READ_SCOPE = "privacy:read";
58
58
  /**
59
+ * Read this Worker's evidence pack: the SOC 2 and ISO 27001 evidence it derives from its own declarations.
60
+ * Read-only — the one route behind it is a `GET`, and it performs nothing it reports on.
61
+ *
62
+ * **Its own scope**, because the pack reads across the seam: every connection's principal, kind, purpose and
63
+ * grant, and every route's verification. It never widens another scope. A fact a capability keeps behind its own
64
+ * read — migration counts behind {@link MIGRATIONS_READ_SCOPE}, a capability's health behind that capability's
65
+ * scope — stays behind it, and a connection without that scope gets `not-derivable` naming it.
66
+ */
67
+ const EVIDENCE_READ_SCOPE = "evidence:read";
68
+ /**
69
+ * Read the erasure attestation: one subject's purge, or every purge in a period, with the audit events that
70
+ * record each step. Read-only — both routes behind it are `GET`s — and kind `reads`.
71
+ *
72
+ * **Its own scope**, because it answers across subjects: which accounts and organizations were deleted, by which
73
+ * kind of actor and why. It carries nothing about a person beyond the id the lifecycle trail already keeps, and it
74
+ * never widens `audit:events:read`: it cites an event by id and chain position, never its contents.
75
+ */
76
+ const ERASURE_READ_SCOPE = "erasure:read";
77
+ /**
78
+ * Read the record of processing activities, GDPR Article 30: each activity's purpose, data classes, legal basis,
79
+ * recipients, retention and measures, and every gap. Read-only — the one route behind it is a `GET` — and kind
80
+ * `reads`.
81
+ *
82
+ * **Its own scope**, because it reads across the Worker: every activity, the consent counts behind each consent
83
+ * basis, and where each stored class sits. It never widens another: the measures carry the evidence pack's states
84
+ * only for a connection that also holds {@link EVIDENCE_READ_SCOPE}, and a gap names a stored table or field only for
85
+ * one that also holds {@link PRIVACY_READ_SCOPE}. Without it, a gap names the capability and the class.
86
+ */
87
+ const PROCESSING_READ_SCOPE = "processing:read";
88
+ /**
89
+ * Place and release a legal hold on a user, an organization or a tenant's audit trail. A write — both routes
90
+ * behind it are `POST`s — and kind `writes`, so `pithy dashboard connect` offers it and never grants it by default.
91
+ *
92
+ * **It can only preserve.** A hold suspends purges, prunes and inactivity deletions; releasing one returns the subject
93
+ * to the policy the Worker deploys with. No route behind it, or anywhere, shortens a retention.
94
+ */
95
+ const RETENTION_HOLD_SCOPE = "retention:hold";
96
+ /**
97
+ * Read the legal holds: every hold, standing or released, with who placed it and why. Read-only — the one
98
+ * route behind it is a `GET` — and kind `reads`. The manifest's count of standing holds sits behind it too:
99
+ * `activeHolds`, in the health of the `controlplane` entry.
100
+ */
101
+ const RETENTION_READ_SCOPE = "retention:read";
102
+ /**
103
+ * List every connection bound to this Worker's environment: who authorized it, what kind of client it is for, its purpose, its
104
+ * credential kinds, its grant and when it was registered or revoked. Kind `reads`. Never key material.
105
+ */
106
+ const CONNECTIONS_READ_SCOPE = "connections:read";
107
+ /**
108
+ * Revoke every key and trust another connection in this Worker's environment holds, with a reason. Kind
109
+ * `credentials`. Refused on the caller's own connection, which ends through `disconnect`.
110
+ */
111
+ const CONNECTIONS_REVOKE_SCOPE = "connections:revoke";
112
+ /**
59
113
  * The seam's base grant — what `pithy dashboard connect` grants whatever the Worker composes. Ping is absent
60
114
  * because it is not grantable; see {@link ANY_VERIFIED_CALLER}.
61
115
  *
62
- * **{@link MIGRATIONS_READ_SCOPE} and {@link PRIVACY_READ_SCOPE} are absent on purpose.** Each is a read —
116
+ * **The seam's reads are absent on purpose** — {@link MIGRATIONS_READ_SCOPE}, {@link PRIVACY_READ_SCOPE},
117
+ * {@link EVIDENCE_READ_SCOPE}, {@link ERASURE_READ_SCOPE}, {@link PROCESSING_READ_SCOPE}. Each is a read —
63
118
  * every route requiring it is a `GET` — so `connect` derives it from the seam's `adminRoutes` the way it
64
119
  * derives every capability's reads. The base exists for `keys:rotate`, which is not a read and would
65
120
  * otherwise drop out.
@@ -83,4 +138,4 @@ function scopeCovers(required, presented, granted) {
83
138
  return granted.includes(required);
84
139
  }
85
140
  //#endregion
86
- export { ANY_VERIFIED_CALLER, ControlPlaneScope, KEYS_ROTATE_SCOPE, MANIFEST_READ_SCOPE, MIGRATIONS_READ_SCOPE, PRIVACY_READ_SCOPE, SEAM_SCOPES, scopeCovers };
141
+ export { ANY_VERIFIED_CALLER, CONNECTIONS_READ_SCOPE, CONNECTIONS_REVOKE_SCOPE, ControlPlaneScope, ERASURE_READ_SCOPE, EVIDENCE_READ_SCOPE, KEYS_ROTATE_SCOPE, MANIFEST_READ_SCOPE, MIGRATIONS_READ_SCOPE, PRIVACY_READ_SCOPE, PROCESSING_READ_SCOPE, RETENTION_HOLD_SCOPE, RETENTION_READ_SCOPE, SEAM_SCOPES, scopeCovers };
@@ -1,8 +1,8 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
- import { ControlPlaneClaims, ControlPlaneJwsHeader } from "./claims.js";
4
3
  import { ControlPlaneInvalidCredentialError } from "../error/errors.js";
5
4
  import { base64UrlDecode } from "./base64url.js";
5
+ import { ControlPlaneClaims, ControlPlaneJwsHeader } from "./claims.js";
6
6
  //#region src/controlPlane/token/jws.ts
7
7
  /**
8
8
  * Split a compact JWS, decode it, and validate both segments through their schemas.
@@ -1,7 +1,7 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
- import { ControlPlaneClaims } from "./claims.js";
4
3
  import { base64UrlEncode } from "./base64url.js";
4
+ import { ControlPlaneClaims } from "./claims.js";
5
5
  import { sha256Base64Url } from "./digest.js";
6
6
  //#region src/controlPlane/token/mint.ts
7
7
  /** Base64url a UTF-8 JSON serialization — the encoding both JWS segments use. */
@@ -30,6 +30,29 @@
30
30
  * carrying that header, so a management call would drag the whole auth stack in. See `http/verify.ts`.
31
31
  */
32
32
  export declare const CONTROL_PLANE_HEADER = "pithy-control-plane";
33
+ /**
34
+ * The header a workload presents its OIDC token on, when it calls under a trust rather than a key (#722,
35
+ * `docs/AGENT-ACCESS.md` §6.2).
36
+ *
37
+ * Not `Authorization`, for the same reason as {@link CONTROL_PLANE_HEADER}, and not that header either: a call
38
+ * presents exactly one credential, and two names make "which one is this" a question the verifier never has
39
+ * to guess at. The token is the provider's own, verified per call; nothing is exchanged for it.
40
+ */
41
+ export declare const CONTROL_PLANE_OIDC_HEADER = "pithy-control-plane-oidc";
42
+ /**
43
+ * The header naming which of this environment's trusts an OIDC call claims, by its id — the way a token's
44
+ * `kid` names a key. Read before the token is verified, so it selects and grants nothing: the trust's issuer,
45
+ * audience and claims are what the token is then held to.
46
+ */
47
+ export declare const CONTROL_PLANE_TRUST_HEADER = "pithy-control-plane-trust";
48
+ /**
49
+ * The header naming the one scope an OIDC call exercises.
50
+ *
51
+ * A signed control-plane token names its scope inside the signature. A provider's identity token cannot — it
52
+ * proves **who**, never **what** — so the call names it out loud, and the seam checks it against the
53
+ * connection's grant exactly as it checks a token's. A call that names none is refused.
54
+ */
55
+ export declare const CONTROL_PLANE_SCOPE_HEADER = "pithy-control-plane-scope";
33
56
  /**
34
57
  * The response header carrying the build that answered a control-plane call.
35
58
  *
@@ -1 +1 @@
1
- {"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../../src/controlPlane/wire.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AAE1D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,4BAA4B,yBAAyB,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,oCAAoC,iCAAiC,CAAC;AAEnF;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,uFAAuF;IACvF,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,+FAA+F;IAC/F,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAEnF"}
1
+ {"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../../src/controlPlane/wire.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AAE1D;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,6BAA6B,CAAC;AAEpE;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,8BAA8B,CAAC;AAEtE;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,8BAA8B,CAAC;AAEtE;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,4BAA4B,yBAAyB,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,oCAAoC,iCAAiC,CAAC;AAEnF;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,uFAAuF;IACvF,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,+FAA+F;IAC/F,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAEnF"}
@@ -32,6 +32,29 @@
32
32
  */
33
33
  const CONTROL_PLANE_HEADER = "pithy-control-plane";
34
34
  /**
35
+ * The header a workload presents its OIDC token on, when it calls under a trust rather than a key (#722,
36
+ * `docs/AGENT-ACCESS.md` §6.2).
37
+ *
38
+ * Not `Authorization`, for the same reason as {@link CONTROL_PLANE_HEADER}, and not that header either: a call
39
+ * presents exactly one credential, and two names make "which one is this" a question the verifier never has
40
+ * to guess at. The token is the provider's own, verified per call; nothing is exchanged for it.
41
+ */
42
+ const CONTROL_PLANE_OIDC_HEADER = "pithy-control-plane-oidc";
43
+ /**
44
+ * The header naming which of this environment's trusts an OIDC call claims, by its id — the way a token's
45
+ * `kid` names a key. Read before the token is verified, so it selects and grants nothing: the trust's issuer,
46
+ * audience and claims are what the token is then held to.
47
+ */
48
+ const CONTROL_PLANE_TRUST_HEADER = "pithy-control-plane-trust";
49
+ /**
50
+ * The header naming the one scope an OIDC call exercises.
51
+ *
52
+ * A signed control-plane token names its scope inside the signature. A provider's identity token cannot — it
53
+ * proves **who**, never **what** — so the call names it out loud, and the seam checks it against the
54
+ * connection's grant exactly as it checks a token's. A call that names none is refused.
55
+ */
56
+ const CONTROL_PLANE_SCOPE_HEADER = "pithy-control-plane-scope";
57
+ /**
35
58
  * The response header carrying the build that answered a control-plane call.
36
59
  *
37
60
  * Set on every control-plane response — allowed and denied alike, and on every capability's admin
@@ -122,4 +145,4 @@ function differs(before, after) {
122
145
  return before !== after;
123
146
  }
124
147
  //#endregion
125
- export { CONTROL_PLANE_HEADER, CONTROL_PLANE_VERSION_CREATED_HEADER, CONTROL_PLANE_VERSION_HEADER, workerBuildChanged };
148
+ export { CONTROL_PLANE_HEADER, CONTROL_PLANE_OIDC_HEADER, CONTROL_PLANE_SCOPE_HEADER, CONTROL_PLANE_TRUST_HEADER, CONTROL_PLANE_VERSION_CREATED_HEADER, CONTROL_PLANE_VERSION_HEADER, workerBuildChanged };
@@ -30,6 +30,19 @@ export interface CreateBackendOptions<Caps extends readonly Capability[], App ex
30
30
  * absent — e.g. a non-provisioned local run. Falls through to `unknown` when neither is present.
31
31
  */
32
32
  env?: string;
33
+ /**
34
+ * How long this Worker keeps deleted accounts, the audit trail and each class of personal data — the
35
+ * `retention` block of the Worker's `pithy.config.ts`, which `createEntrypoint(config)` hands through. Parsed and
36
+ * resolved here, at assembly, so a block that does not parse, or keeps a floored audit action under the floor,
37
+ * refuses to deploy. See `retention/policy.ts`.
38
+ */
39
+ retention?: unknown;
40
+ /**
41
+ * The adopter's own processing activities, and the legal bases they state for a capability's — the `processing`
42
+ * block of the Worker's `pithy.config.ts`. Resolved here over what this Worker composes, so a block that does not
43
+ * parse, or overrides an activity nothing declares, refuses to deploy. See `processing/activity.ts`.
44
+ */
45
+ processing?: unknown;
33
46
  }
34
47
  /** The Hono env `createBackend` returns — `db`/`kv`/`workflows` typed precisely from the merged capabilities. */
35
48
  type BackendEnv<Caps extends readonly Capability[]> = {
@@ -1 +1 @@
1
- {"version":3,"file":"createBackend.d.ts","sourceRoot":"","sources":["../src/createBackend.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EACV,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EAEpB,SAAS,EACV,MAAM,yBAAyB,CAAC;AAOjC,OAAO,EAAqC,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAMtF,OAAO,EAA8B,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAQ9C,OAAO,EAA2B,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGvF,oGAAoG;AACpG,MAAM,WAAW,oBAAoB,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,EAAE,GAAG,SAAS,UAAU;IAC9F,2EAA2E;IAC3E,YAAY,EAAE,IAAI,CAAC;IACnB;;;OAGG;IACH,GAAG,CAAC,EAAE,GAAG,CAAC;IACV;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,iHAAiH;AACjH,KAAK,UAAU,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,IAAI;IACpD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,GAAG,IAAI,GAAG,WAAW,CAAC,GAAG;QACtD,EAAE,EAAE,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;QACtC,EAAE,EAAE,UAAU,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;QACzC,SAAS,EAAE,kBAAkB,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC;KAC3D,CAAC;CACH,CAAC;AAuCF,kCAAkC;AAClC,eAAO,MAAM,UAAU;;;iBAQ+B,CAAC;AACvD,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAC3B,KAAK,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,EACxC,KAAK,CAAC,GAAG,SAAS,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EACrF,OAAO,EAAE,oBAAoB,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CA6MrF"}
1
+ {"version":3,"file":"createBackend.d.ts","sourceRoot":"","sources":["../src/createBackend.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EACV,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EAEpB,SAAS,EACV,MAAM,yBAAyB,CAAC;AAOjC,OAAO,EAAqC,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAMtF,OAAO,EAA8B,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAY9C,OAAO,EAA2B,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGvF,oGAAoG;AACpG,MAAM,WAAW,oBAAoB,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,EAAE,GAAG,SAAS,UAAU;IAC9F,2EAA2E;IAC3E,YAAY,EAAE,IAAI,CAAC;IACnB;;;OAGG;IACH,GAAG,CAAC,EAAE,GAAG,CAAC;IACV;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,iHAAiH;AACjH,KAAK,UAAU,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,IAAI;IACpD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,GAAG,IAAI,GAAG,WAAW,CAAC,GAAG;QACtD,EAAE,EAAE,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;QACtC,EAAE,EAAE,UAAU,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;QACzC,SAAS,EAAE,kBAAkB,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC;KAC3D,CAAC;CACH,CAAC;AAuCF,kCAAkC;AAClC,eAAO,MAAM,UAAU;;;iBAQ+B,CAAC;AACvD,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAC3B,KAAK,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,EACxC,KAAK,CAAC,GAAG,SAAS,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EACrF,OAAO,EAAE,oBAAoB,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAqNrF"}
@@ -7,10 +7,14 @@ import { pithyCommandOf } from "./cli/command.js";
7
7
  import { BindingSpec } from "./capability/bindings.js";
8
8
  import { recordComposition } from "./capability/composition.js";
9
9
  import { validateBindings } from "./capability/validateBindings.js";
10
+ import { recordRouteGroups } from "./openapi/routeGroups.js";
11
+ import { describeRoute } from "./http/routeSpec.js";
12
+ import { registerPresenceRoutes } from "./presence/http/routes.js";
10
13
  import { refuseEncryptedKvStores } from "./privacy/encryptedColumns.js";
14
+ import { effectiveRetention, recordRetention } from "./retention/composed.js";
11
15
  import { workerVersion } from "./worker/identity.js";
12
- import { describeRoute } from "./http/routeSpec.js";
13
16
  import { buildDbRegistry, composeDatabases } from "./data/databases.js";
17
+ import { effectiveProcessing, recordProcessing } from "./processing/composed.js";
14
18
  import { isControlPlaneCapability } from "./controlPlane/capability.js";
15
19
  import { allowedOriginSet, corsSurface, registerControlPlaneCors } from "./controlPlane/http/cors.js";
16
20
  import { registerReadinessGuards } from "./controlPlane/http/readiness.js";
@@ -20,7 +24,7 @@ import { catalogFor, composeMessages } from "./i18n/registry.js";
20
24
  import { buildKvRegistry, composeKv } from "./kv/namespaces.js";
21
25
  import { bindRequestContext, createWorkerLogger } from "./logger/worker.js";
22
26
  import { loggingErrorHandler } from "./logger/errorHandler.js";
23
- import { recordRouteGroups } from "./openapi/routeGroups.js";
27
+ import { assertToolDeclarations } from "./mcp/tools.js";
24
28
  import { HEALTH_PATH } from "./worker/health.js";
25
29
  import { registeredWorkflowBinding } from "./workflow/bindings.js";
26
30
  import { buildWorkflowDispatcher } from "./workflow/dispatch.js";
@@ -96,6 +100,8 @@ function createBackend(options) {
96
100
  });
97
101
  for (const cap of all) cap.compose?.({ capabilities: all });
98
102
  recordComposition(all);
103
+ recordRetention(effectiveRetention(options.retention, all));
104
+ recordProcessing(effectiveProcessing(options.processing, all));
99
105
  const databases = composeDatabases(all);
100
106
  const messages = composeMessages(all);
101
107
  const defaultTranslator = bakedTranslator(catalogFor(messages, "en"));
@@ -162,7 +168,7 @@ function createBackend(options) {
162
168
  * The path is `worker/health.ts`'s, not a literal here. Three other sites need the same string — the
163
169
  * CLI's route allowlist, `pithy deploy`'s post-deploy probe, and the bare home screen a no-auth
164
170
  * scaffold seeds — and that last one is in somebody else's repository, rendering nothing but this
165
- * request's answer (#400).
171
+ * request's answer.
166
172
  *
167
173
  * The version is what turns `pithy deploy`'s post-deploy check from a liveness probe into an
168
174
  * assertion. `status: "ok"` at the declared domain proves *a* Worker is there; it does not prove it is
@@ -198,12 +204,14 @@ function createBackend(options) {
198
204
  for (const cap of all) {
199
205
  const start = app.routes.length;
200
206
  cap.routes?.(app);
207
+ if (cap.presence && cap.presence.rooms.length > 0) registerPresenceRoutes(app, cap.presence);
201
208
  groups.push({
202
209
  tag: cap.name,
203
210
  routes: app.routes.slice(start)
204
211
  });
205
212
  }
206
213
  recordRouteGroups(app, groups);
214
+ assertToolDeclarations(groups);
207
215
  return app;
208
216
  }
209
217
  //#endregion
@@ -3,6 +3,7 @@
3
3
  import type { ExecutionContext, ForwardableEmailMessage } from "@cloudflare/workers-types";
4
4
  import type { Capability } from "./capability/capability";
5
5
  import { type CreateBackendOptions } from "./createBackend";
6
+ import { type QueueBatch } from "./queue/consumer";
6
7
  /**
7
8
  * A deployable Worker entrypoint: `fetch`, the single inbound `email` handler the runtime permits
8
9
  * per Worker, and the single `scheduled` handler it permits for cron triggers. `createBackend`
@@ -23,7 +24,13 @@ export interface PithyEntrypoint {
23
24
  */
24
25
  email?: (message: ForwardableEmailMessage, env: Record<string, unknown>, ctx: ExecutionContext) => Promise<void>;
25
26
  /**
26
- * The Worker `scheduled` handler — starts every registered job that declares a `schedule`.
27
+ * The Worker `scheduled` handler — starts every registered job whose `schedule` is the cron that fired.
28
+ *
29
+ * A Worker carries one `scheduled` entry for all of its `triggers.crons`, and the runtime names the one
30
+ * that fired on `controller.cron`, verbatim as `wrangler.jsonc` declares it. Only the jobs whose
31
+ * `schedule` is that string start: a daily job composed beside an hourly one must not run every hour,
32
+ * and the hourly one must not run an extra time at the daily job's minute (#622). An event that names
33
+ * no cron, or one no job declares, starts nothing.
27
34
  *
28
35
  * **Present only when at least one job carries a cron.** The reason differs from `email`'s: an
29
36
  * inert `email()` silently *drops* mail, which is a correctness bug, whereas an inert `scheduled()`
@@ -43,6 +50,12 @@ export interface PithyEntrypoint {
43
50
  * tested in staging.
44
51
  */
45
52
  scheduled?: (controller: unknown, env: Record<string, unknown>, ctx: ExecutionContext) => Promise<void>;
53
+ /**
54
+ * The Worker `queue` handler — hands each composed capability the messages of a batch that name it (#824).
55
+ * **Present only when at least one capability consumes a queue**, for `email`'s reason: an inert handler would
56
+ * acknowledge every message delivered to it and drop it.
57
+ */
58
+ queue?: (batch: QueueBatch, env: Record<string, unknown>, ctx: ExecutionContext) => Promise<void>;
46
59
  }
47
60
  /**
48
61
  * Assemble capabilities into a Worker entrypoint object — `{ fetch, email }`. Use this instead of
@@ -1 +1 @@
1
- {"version":3,"file":"createEntrypoint.d.ts","sourceRoot":"","sources":["../src/createEntrypoint.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAC3F,OAAO,KAAK,EAAE,UAAU,EAA0B,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,KAAK,oBAAoB,EAAiB,MAAM,iBAAiB,CAAC;AAK3E;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,gBAAgB,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/G;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,uBAAuB,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjH;;;;;;;;;;;;;;;;;;;OAmBG;IACH,SAAS,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzG;AAkBD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,EACxC,KAAK,CAAC,GAAG,SAAS,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EACrF,OAAO,EAAE,oBAAoB,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,eAAe,CAyD3D"}
1
+ {"version":3,"file":"createEntrypoint.d.ts","sourceRoot":"","sources":["../src/createEntrypoint.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAC3F,OAAO,KAAK,EAAE,UAAU,EAA0B,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,KAAK,oBAAoB,EAAiB,MAAM,iBAAiB,CAAC;AAE3E,OAAO,EAAmD,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKpG;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,gBAAgB,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/G;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,uBAAuB,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjH;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,SAAS,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxG;;;;OAIG;IACH,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACnG;AAyBD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,EACxC,KAAK,CAAC,GAAG,SAAS,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EACrF,OAAO,EAAE,oBAAoB,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,eAAe,CAoE3D"}
@@ -1,10 +1,18 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
+ import { createWorkerLogger } from "./logger/worker.js";
3
4
  import { triggerWorkflow } from "./workflow/dispatch.js";
4
5
  import { composeWorkflows, scheduledWorkflows } from "./workflow/register.js";
5
6
  import { createBackend } from "./createBackend.js";
7
+ import { dispatchQueueBatch } from "./queue/consumer.js";
6
8
  import { withLocalServices } from "./worker/serviceLoopback.js";
7
9
  //#region src/createEntrypoint.ts
10
+ /** The cron expression a `scheduled` event fired for, or `undefined` when the event names none. */
11
+ function firedCron(controller) {
12
+ if (typeof controller !== "object" || controller === null) return void 0;
13
+ const cron = controller.cron;
14
+ return typeof cron === "string" ? cron : void 0;
15
+ }
8
16
  /**
9
17
  * The raw MIME stream of a `ForwardableEmailMessage` is **single-use** — once one handler reads it,
10
18
  * the next sees an empty stream. When more than one capability handles inbound mail we buffer the
@@ -33,15 +41,21 @@ function createEntrypoint(options) {
33
41
  const registry = composeWorkflows(all);
34
42
  const scheduled = scheduledWorkflows(registry);
35
43
  const entrypoint = { fetch: (request, env, ctx) => app.fetch(request, withLocalServices(env), ctx) };
36
- if (scheduled.length > 0) entrypoint.scheduled = async (_controller, env) => {
44
+ if (scheduled.length > 0) entrypoint.scheduled = async (controller, env) => {
45
+ const cron = firedCron(controller);
37
46
  const failures = [];
38
- for (const entry of scheduled) try {
39
- await triggerWorkflow(withLocalServices(env), registry, entry.key, {});
40
- } catch (error) {
41
- failures.push(error);
47
+ for (const entry of scheduled) {
48
+ if (entry.spec.schedule !== cron) continue;
49
+ try {
50
+ await triggerWorkflow(withLocalServices(env), registry, entry.key, {});
51
+ } catch (error) {
52
+ failures.push(error);
53
+ }
42
54
  }
43
55
  if (failures[0] !== void 0) throw failures[0];
44
56
  };
57
+ const consumers = new Map(all.flatMap((cap) => cap.queue ? [[cap.name, cap.queue]] : []));
58
+ if (consumers.size > 0) entrypoint.queue = (batch, env, ctx) => dispatchQueueBatch(batch, consumers, withLocalServices(env), ctx, createWorkerLogger({ name: "queue" }));
45
59
  if (handlers.length > 0) entrypoint.email = async (message, given, ctx) => {
46
60
  const env = withLocalServices(given);
47
61
  if (handlers.length === 1) {