@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
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  //#region src/cli/commandFacts.ts
4
4
  /**
5
- * **What the catalog cannot say about a `pithy` command, written down once (#711).**
5
+ * **What the catalog cannot say about a `pithy` command, written down once.**
6
6
  *
7
7
  * `commandCatalog.generated.ts` is the parser's own account of every command: its arguments, its flags, which
8
8
  * are required, which have defaults, which go together. Four facts are not in any parser, and each was the
@@ -29,6 +29,7 @@ const WORKER_SCOPED = [
29
29
  "add",
30
30
  "dashboard connect",
31
31
  "email provision",
32
+ "mcp connect",
32
33
  "media provision",
33
34
  "payments provision",
34
35
  "storage provision",
@@ -48,15 +49,20 @@ const WORKER_SCOPED = [
48
49
  * first that answers, and the flag narrows.
49
50
  */
50
51
  const WORKER_NARROWS = [
52
+ "backup",
51
53
  "contract",
54
+ "dashboard connections",
52
55
  "dashboard disconnect",
53
56
  "dashboard revoke-key",
57
+ "dashboard revoke-trust",
54
58
  "dashboard rotate",
55
59
  "dashboard status",
56
60
  "doctor",
57
61
  "env",
58
62
  "init",
63
+ "mcp disconnect",
59
64
  "migrate",
65
+ "restore",
60
66
  "secrets tables",
61
67
  "seed",
62
68
  "support deprovision",
@@ -93,8 +99,10 @@ const MEANING_ONLY_WITH = {
93
99
  const DESTRUCTIVE_COMMANDS = {
94
100
  "dashboard disconnect": "the environment's dashboard connection and the key it signs with",
95
101
  "dashboard revoke-key": "a signing key the dashboard holds",
102
+ "dashboard revoke-trust": "an OIDC trust a workload calls under",
96
103
  "email deprovision": "the email Workers, and with --suppression the suppression database",
97
104
  "feature destroy": "the feature's worktree, its branch and every resource it provisioned",
105
+ "mcp disconnect": "an agent's key or trust, its key file and its client entries",
98
106
  "media deprovision": "the media Worker, and with --storage its bucket",
99
107
  remove: "a capability's wiring",
100
108
  "secrets deprovision": "the secrets manager, and with --keys the store's keys",
@@ -116,6 +124,7 @@ const DESTRUCTIVE_FLAGS = {
116
124
  "--destroy-retained": "a resource kept for recovery",
117
125
  "--drop": "a capability's tables",
118
126
  "--redo": "the data a seed wrote",
127
+ "--revoke": "every key and trust a principal's connections hold",
119
128
  "--rollback": "the schema a migration group applied"
120
129
  };
121
130
  /**
@@ -190,14 +199,14 @@ const PRODUCTION_CONFIRMS = {
190
199
  "vector provision": null
191
200
  };
192
201
  /**
193
- * **A command that acts on every environment when its `--env` is left off (#711)**, production among them. `pithy
202
+ * **A command that acts on every environment when its `--env` is left off**, production among them. `pithy
194
203
  * testers provision` with no `--env` provisions every declared environment, so the bare line touches production as
195
204
  * surely as `--env prod` does, and is a person's decision for the same reason. Each declares `--env` with no
196
205
  * default; `command.test.ts` holds that against the catalog.
197
206
  */
198
207
  const EVERY_ENVIRONMENT_WITHOUT_ENV = ["testers provision"];
199
208
  /**
200
- * **A command that acts on every environment on every run (#711)**, production among them, with no `--env` to narrow
209
+ * **A command that acts on every environment on every run**, production among them, with no `--env` to narrow
201
210
  * it. `pithy secrets provision` deploys each declared environment's manager and mints its store entries, so every line
202
211
  * naming it touches production and is a person's decision — never the fix for one binding, one database or one
203
212
  * setting. None declares `--env`; `command.test.ts` holds that against the catalog.
@@ -0,0 +1,70 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { z } from "zod";
4
+ /**
5
+ * Consent purposes: what a person is asked to agree to, declared where the processing is.
6
+ *
7
+ * ## Declared, never discovered
8
+ *
9
+ * A capability that processes under consent says so, the way it states its migrations: `@pithy-sh/email` declares
10
+ * `email.marketing` and `email.tracking`. The adopter adds their own to `consent({ purposes })`. The consent
11
+ * capability composes every declaration into one catalog, and `hasConsent` answers only for a purpose in it.
12
+ *
13
+ * ## A purpose says what it covers and what it demands
14
+ *
15
+ * Beside its notice version, a purpose names the data classes it covers, whether it is **explicit** (GDPR
16
+ * Article 9), the **minimum method** a grant needs, and whether a withdrawal must be made at least at the grade
17
+ * of the grant it withdraws, the way a HIPAA revocation must be in writing.
18
+ *
19
+ * ## The id is the capability's own
20
+ *
21
+ * `<domain>.<name>`, and a capability may declare purposes only under its own `name`, the rule `pithy_<name>_*`
22
+ * tables and `<name>/…` error codes follow, for the same reason: the domain is what keeps two declarations from
23
+ * colliding. `defineCapability` refuses anything else, naming the capability.
24
+ */
25
+ /**
26
+ * How a grant was given, weakest first. The order is the grade: a purpose's `minimumMethod` refuses a grant below
27
+ * it, and a purpose with `writtenWithdrawal` refuses a withdrawal below the grant it withdraws.
28
+ */
29
+ export declare const CONSENT_METHODS: readonly ["click", "typed", "drawn", "provider"];
30
+ /** How a consent was given or withdrawn. */
31
+ export declare const ConsentMethod: z.ZodEnum<{
32
+ click: "click";
33
+ drawn: "drawn";
34
+ provider: "provider";
35
+ typed: "typed";
36
+ }>;
37
+ export type ConsentMethod = z.output<typeof ConsentMethod>;
38
+ /** A method's grade: its place in {@link CONSENT_METHODS}, so `click` is 0 and `provider` is 3. */
39
+ export declare function methodRank(method: ConsentMethod): number;
40
+ /** Whether `method` meets `minimum`: at its grade or above. */
41
+ export declare function meetsMethod(method: ConsentMethod, minimum: ConsentMethod): boolean;
42
+ /** A purpose id: `<domain>.<name>`, lowercase, the domain being the declaring capability's name. */
43
+ export declare const ConsentPurposeId: z.ZodString;
44
+ export type ConsentPurposeId = z.output<typeof ConsentPurposeId>;
45
+ /** One purpose a capability or the adopter processes under consent. */
46
+ export declare const ConsentPurpose: z.ZodObject<{
47
+ id: z.ZodString;
48
+ summary: z.ZodString;
49
+ noticeVersion: z.ZodNumber;
50
+ classes: z.ZodDefault<z.ZodArray<z.ZodString>>;
51
+ explicit: z.ZodDefault<z.ZodBoolean>;
52
+ minimumMethod: z.ZodDefault<z.ZodEnum<{
53
+ click: "click";
54
+ drawn: "drawn";
55
+ provider: "provider";
56
+ typed: "typed";
57
+ }>>;
58
+ writtenWithdrawal: z.ZodDefault<z.ZodBoolean>;
59
+ }, z.core.$strip>;
60
+ export type ConsentPurpose = z.output<typeof ConsentPurpose>;
61
+ export type ConsentPurposeInput = z.input<typeof ConsentPurpose>;
62
+ /** The domain half of a purpose id: `email` for `email.marketing`. */
63
+ export declare function purposeDomain(id: string): string;
64
+ /**
65
+ * Parse one declarer's purposes and refuse what no consent capability could answer for: an id that is not a
66
+ * purpose id, one under a domain that is not the declarer's, or two with one id. `domain` is the declaring
67
+ * capability's name, or `null` for the adopter's own, which may use any domain but a reserved one.
68
+ */
69
+ export declare function parseConsentPurposes(declarer: string, purposes: readonly ConsentPurposeInput[], domain: string | null, reserved?: ReadonlySet<string>): ConsentPurpose[];
70
+ //# sourceMappingURL=purpose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"purpose.d.ts","sourceRoot":"","sources":["../../src/consent/purpose.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;GAGG;AACH,eAAO,MAAM,eAAe,YAAI,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,CAAU,CAAC;AAEhF,4CAA4C;AAC5C,eAAO,MAAM,aAAa;;;;;EAIvB,CAAC;AACJ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAE3D,mGAAmG;AACnG,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAExD;AAED,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAElF;AAED,oGAAoG;AACpG,eAAO,MAAM,gBAAgB,aAS1B,CAAC;AACJ,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEjE,uEAAuE;AACvE,eAAO,MAAM,cAAc;;;;;;;;;;;;;iBAuCsF,CAAC;AAClH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAC7D,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEjE,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAGhD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,SAAS,mBAAmB,EAAE,EACxC,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,QAAQ,GAAE,WAAW,CAAC,MAAM,CAAa,GACxC,cAAc,EAAE,CAiClB"}
@@ -0,0 +1,97 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { ValidationError } from "../error/pithyError.js";
4
+ import { PrivacyClassName } from "../privacy/classes.js";
5
+ import { z } from "zod";
6
+ //#region src/consent/purpose.ts
7
+ /**
8
+ * Consent purposes: what a person is asked to agree to, declared where the processing is.
9
+ *
10
+ * ## Declared, never discovered
11
+ *
12
+ * A capability that processes under consent says so, the way it states its migrations: `@pithy-sh/email` declares
13
+ * `email.marketing` and `email.tracking`. The adopter adds their own to `consent({ purposes })`. The consent
14
+ * capability composes every declaration into one catalog, and `hasConsent` answers only for a purpose in it.
15
+ *
16
+ * ## A purpose says what it covers and what it demands
17
+ *
18
+ * Beside its notice version, a purpose names the data classes it covers, whether it is **explicit** (GDPR
19
+ * Article 9), the **minimum method** a grant needs, and whether a withdrawal must be made at least at the grade
20
+ * of the grant it withdraws, the way a HIPAA revocation must be in writing.
21
+ *
22
+ * ## The id is the capability's own
23
+ *
24
+ * `<domain>.<name>`, and a capability may declare purposes only under its own `name`, the rule `pithy_<name>_*`
25
+ * tables and `<name>/…` error codes follow, for the same reason: the domain is what keeps two declarations from
26
+ * colliding. `defineCapability` refuses anything else, naming the capability.
27
+ */
28
+ /**
29
+ * How a grant was given, weakest first. The order is the grade: a purpose's `minimumMethod` refuses a grant below
30
+ * it, and a purpose with `writtenWithdrawal` refuses a withdrawal below the grant it withdraws.
31
+ */
32
+ const CONSENT_METHODS = [
33
+ "click",
34
+ "typed",
35
+ "drawn",
36
+ "provider"
37
+ ];
38
+ /** How a consent was given or withdrawn. */
39
+ const ConsentMethod = z.enum(CONSENT_METHODS).describe("How a consent was given or withdrawn, weakest first: `click` (a checkbox or a button), `typed` (the person typed their name), `drawn` (a drawn signature), or `provider` (an e-signature provider's completed envelope). The order is the grade a purpose's minimum is held against.");
40
+ /** A method's grade: its place in {@link CONSENT_METHODS}, so `click` is 0 and `provider` is 3. */
41
+ function methodRank(method) {
42
+ return CONSENT_METHODS.indexOf(method);
43
+ }
44
+ /** Whether `method` meets `minimum`: at its grade or above. */
45
+ function meetsMethod(method, minimum) {
46
+ return methodRank(method) >= methodRank(minimum);
47
+ }
48
+ /** A purpose id: `<domain>.<name>`, lowercase, the domain being the declaring capability's name. */
49
+ const ConsentPurposeId = z.string().regex(/^[a-z][a-z0-9-]*\.[a-z][a-z0-9_.-]*$/, "A consent purpose id is `<domain>.<name>`: lowercase, the domain being the declaring capability's name.").max(128).describe("A consent purpose id, `<domain>.<name>` — `email.marketing`. The domain is the declaring capability's name, or the adopter's own domain for a purpose declared in `consent({ purposes })`.");
50
+ /** One purpose a capability or the adopter processes under consent. */
51
+ const ConsentPurpose = z.object({
52
+ id: ConsentPurposeId,
53
+ summary: z.string().min(1).max(500).describe("One sentence, written for the person, on what agreeing allows — `Send me news and offers by email.` Shown on the consent settings screen."),
54
+ noticeVersion: z.number().int().positive().describe("The version of the notice a person agrees to. Bump it when the notice changes: every grant under an older version then needs renewing, and `hasConsent` answers no for it until it is."),
55
+ classes: z.array(PrivacyClassName).default([]).describe("The data classes this purpose covers — `pii`, `phi`, or an adopter's own. The processing record reads it to name a classed field with no consent behind it."),
56
+ explicit: z.boolean().default(false).describe("Whether this purpose needs explicit consent (GDPR Article 9), as processing health data does. Recorded so an auditor can see which purposes claim it."),
57
+ minimumMethod: ConsentMethod.default("click").describe("The weakest method a grant may be given by. A grant below it is refused, and `hasConsent` answers no for one recorded below it before the minimum was raised."),
58
+ writtenWithdrawal: z.boolean().default(false).describe("Whether a withdrawal must be made at least at the grade of the grant it withdraws, as a HIPAA revocation must be in writing. Off, a click withdraws any grant: withdrawing is then never harder than granting.")
59
+ }).describe("One purpose processed under consent: what it allows, its notice version, and what a grant demands.");
60
+ /** The domain half of a purpose id: `email` for `email.marketing`. */
61
+ function purposeDomain(id) {
62
+ const dot = id.indexOf(".");
63
+ return dot === -1 ? id : id.slice(0, dot);
64
+ }
65
+ /**
66
+ * Parse one declarer's purposes and refuse what no consent capability could answer for: an id that is not a
67
+ * purpose id, one under a domain that is not the declarer's, or two with one id. `domain` is the declaring
68
+ * capability's name, or `null` for the adopter's own, which may use any domain but a reserved one.
69
+ */
70
+ function parseConsentPurposes(declarer, purposes, domain, reserved = /* @__PURE__ */ new Set()) {
71
+ const seen = /* @__PURE__ */ new Set();
72
+ return purposes.map((input) => {
73
+ const parsed = ConsentPurpose.safeParse(input);
74
+ if (!parsed.success) throw new ValidationError({
75
+ message: `${declarer} declares a consent purpose that is not valid: ${parsed.error.issues[0]?.message ?? "invalid"}.`,
76
+ action: "Give it an id of the form `<domain>.<name>`, a summary, and a positive notice version."
77
+ });
78
+ const purpose = parsed.data;
79
+ const own = purposeDomain(purpose.id);
80
+ if (domain !== null && own !== domain) throw new ValidationError({
81
+ message: `The ${declarer} capability declares the consent purpose "${purpose.id}" outside its own domain.`,
82
+ action: `Name it under ${domain}. — a capability declares purposes only under its own name.`
83
+ });
84
+ if (domain === null && reserved.has(own)) throw new ValidationError({
85
+ message: `The consent purpose "${purpose.id}" is under ${own}., which a composed capability owns.`,
86
+ action: "Name your own purposes under your own domain, such as your app's name."
87
+ });
88
+ if (seen.has(purpose.id)) throw new ValidationError({
89
+ message: `${declarer} declares the consent purpose "${purpose.id}" twice.`,
90
+ action: "Declare each purpose once."
91
+ });
92
+ seen.add(purpose.id);
93
+ return purpose;
94
+ });
95
+ }
96
+ //#endregion
97
+ export { CONSENT_METHODS, ConsentMethod, ConsentPurpose, ConsentPurposeId, meetsMethod, methodRank, parseConsentPurposes, purposeDomain };
@@ -0,0 +1,99 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import type { Capability } from "../capability/capability";
4
+ import type { ConsentPurpose } from "./purpose";
5
+ /**
6
+ * The consent seam: the one question a capability asks before consent-based processing.
7
+ *
8
+ * `@pithy-sh/consent` answers it, and nothing imports that package to ask: a capability finds the composed reader
9
+ * through {@link composedConsent}, the shape `composedAuditEmit` gives the audit recorder, so `@pithy-sh/email`
10
+ * gates its tracking without depending on a sibling (principle 4).
11
+ *
12
+ * **Absent is not "no".** With no consent capability composed there is no record to consult, so
13
+ * {@link composedConsent} answers `null`, and a capability gates nothing on it. `pithy doctor`
14
+ * names that state, because processing that a law may require consent for is running with no record behind it.
15
+ */
16
+ /** The subject a consent is recorded against: an account's user id, or a visitor's anonymous device id. */
17
+ export interface ConsentSubject {
18
+ /** `account` — a user id from `@pithy-sh/auth`; `visitor` — an anonymous device id held in a first-party cookie. */
19
+ readonly kind: "account" | "visitor";
20
+ /** The id in that kind. */
21
+ readonly id: string;
22
+ }
23
+ /** What the consent capability answers. */
24
+ export interface ConsentReader {
25
+ /**
26
+ * Whether `subject` holds consent to `purpose` now: a grant under the purpose's current notice version, at or
27
+ * above its minimum method, not withdrawn since, and not expired. An account's answer includes what the visitors
28
+ * merged into it granted. A purpose the catalog does not know answers no.
29
+ */
30
+ hasConsent(subject: ConsentSubject, purpose: string): Promise<boolean>;
31
+ /**
32
+ * Every purpose in the composed catalog, the adopter's included, with how many subjects stand where on it now. What
33
+ * the processing record cites for a consent-based activity. Optional on the seam: a reader without it leaves the
34
+ * counts unknown, never zero.
35
+ */
36
+ standings?(): Promise<readonly ConsentPurposeStanding[]>;
37
+ /**
38
+ * Every purpose in the composed catalog, the adopter's included, read from memory and never from the record. What
39
+ * the processing record checks a consent basis against when `standings` cannot answer. Optional on the seam: a
40
+ * reader without it leaves the catalog unknown, and the record then reports no gap that rests on the catalog.
41
+ */
42
+ purposes?(): readonly ConsentPurpose[];
43
+ }
44
+ /** One purpose in the catalog, and where its subjects stand on it now. */
45
+ export interface ConsentPurposeStanding {
46
+ /** The purpose as the catalog composed it. */
47
+ readonly purpose: ConsentPurpose;
48
+ /** Subjects whose latest choice is a grant, under any notice version, expired or not. */
49
+ readonly grants: number;
50
+ /** Subjects whose latest choice is a withdrawal. */
51
+ readonly withdrawals: number;
52
+ /**
53
+ * Subjects `hasConsent` answers yes for now: a grant under the current notice version, at or above the purpose's
54
+ * minimum method, unexpired, and for a visitor not merged into an account, inside the visitor window.
55
+ */
56
+ readonly standing: number;
57
+ }
58
+ /** One withdrawal, as a capability that keeps its own state in step with consent is told of it. */
59
+ export interface ConsentWithdrawal {
60
+ /** Who withdrew. */
61
+ readonly subject: ConsentSubject;
62
+ /** What they withdrew from. */
63
+ readonly purpose: string;
64
+ /** The Worker's bindings for this request. */
65
+ readonly env: Record<string, unknown>;
66
+ /**
67
+ * The subject's email address, read on demand from the capability that owns accounts, or `null` for a visitor
68
+ * or an account with none. A function, so a listener that needs no address reads none.
69
+ */
70
+ readonly address: () => Promise<string | null>;
71
+ }
72
+ /**
73
+ * Hear of a withdrawal from one of this capability's own purposes. `@pithy-sh/email` suppresses the address for
74
+ * marketing when `email.marketing` is withdrawn, so the suppression list and the consent record never disagree.
75
+ * Called after the withdrawal is recorded; a throw is the listener's own failure and never undoes the record.
76
+ */
77
+ export type ConsentWithdrawnListener = (withdrawal: ConsentWithdrawal) => Promise<void>;
78
+ /** One grant that now stands, as a capability that keeps its own state in step with consent is told of it. */
79
+ export type ConsentGrant = ConsentWithdrawal;
80
+ /**
81
+ * Hear of a grant to one of this capability's own purposes, once it stands. The other half of
82
+ * {@link ConsentWithdrawnListener}: `@pithy-sh/email` lifts the marketing suppression a withdrawal wrote when
83
+ * `email.marketing` is granted again, and nothing else, so a person who changes their mind back is heard. Called
84
+ * after the grant is recorded and only when the subject's standing is `granted`; a throw never undoes the record.
85
+ */
86
+ export type ConsentGrantedListener = (grant: ConsentGrant) => Promise<void>;
87
+ /** Every purpose the composed capabilities declare, in composition order. */
88
+ export declare function composedConsentPurposes(capabilities: readonly Capability[]): ConsentPurpose[];
89
+ /** The composed consent reader for this env, or `null` when no capability provides one. */
90
+ export declare function composedConsent(capabilities: readonly Capability[], env: Record<string, unknown>): ConsentReader | null;
91
+ /** Whether any composed capability provides the consent seam. */
92
+ export declare function providesConsent(capabilities: readonly Capability[]): boolean;
93
+ /**
94
+ * The account's address, read through the capability that owns accounts (`@pithy-sh/auth`'s `addressOf`), or
95
+ * `null` where nothing composed can say. Never throws: a listener that cannot learn the address does less, and the
96
+ * withdrawal it heard of stands.
97
+ */
98
+ export declare function composedAddress(capabilities: readonly Capability[], env: Record<string, unknown>, subject: ConsentSubject): Promise<string | null>;
99
+ //# sourceMappingURL=reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../src/consent/reader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD;;;;;;;;;;GAUG;AAEH,2GAA2G;AAC3G,MAAM,WAAW,cAAc;IAC7B,oHAAoH;IACpH,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,CAAC;IACrC,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvE;;;;OAIG;IACH,SAAS,CAAC,IAAI,OAAO,CAAC,SAAS,sBAAsB,EAAE,CAAC,CAAC;IACzD;;;;OAIG;IACH,QAAQ,CAAC,IAAI,SAAS,cAAc,EAAE,CAAC;CACxC;AAED,0EAA0E;AAC1E,MAAM,WAAW,sBAAsB;IACrC,8CAA8C;IAC9C,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,yFAAyF;IACzF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oDAAoD;IACpD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,mGAAmG;AACnG,MAAM,WAAW,iBAAiB;IAChC,oBAAoB;IACpB,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,+BAA+B;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAChD;AAED;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,UAAU,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAExF,8GAA8G;AAC9G,MAAM,MAAM,YAAY,GAAG,iBAAiB,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5E,6EAA6E;AAC7E,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,SAAS,UAAU,EAAE,GAAG,cAAc,EAAE,CAE7F;AAED,2FAA2F;AAC3F,wBAAgB,eAAe,CAC7B,YAAY,EAAE,SAAS,UAAU,EAAE,EACnC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,aAAa,GAAG,IAAI,CAGtB;AAED,iEAAiE;AACjE,wBAAgB,eAAe,CAAC,YAAY,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAE5E;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,YAAY,EAAE,SAAS,UAAU,EAAE,EACnC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASxB"}
@@ -0,0 +1,33 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ //#region src/consent/reader.ts
4
+ /** Every purpose the composed capabilities declare, in composition order. */
5
+ function composedConsentPurposes(capabilities) {
6
+ return capabilities.flatMap((capability) => [...capability.consentPurposes ?? []]);
7
+ }
8
+ /** The composed consent reader for this env, or `null` when no capability provides one. */
9
+ function composedConsent(capabilities, env) {
10
+ const provider = capabilities.find((capability) => capability.consentReader !== void 0);
11
+ return provider?.consentReader ? provider.consentReader(env) : null;
12
+ }
13
+ /** Whether any composed capability provides the consent seam. */
14
+ function providesConsent(capabilities) {
15
+ return capabilities.some((capability) => capability.consentReader !== void 0);
16
+ }
17
+ /**
18
+ * The account's address, read through the capability that owns accounts (`@pithy-sh/auth`'s `addressOf`), or
19
+ * `null` where nothing composed can say. Never throws: a listener that cannot learn the address does less, and the
20
+ * withdrawal it heard of stands.
21
+ */
22
+ async function composedAddress(capabilities, env, subject) {
23
+ if (subject.kind !== "account") return null;
24
+ const provider = capabilities.find((capability) => capability.addressOf !== void 0);
25
+ if (!provider?.addressOf) return null;
26
+ try {
27
+ return await provider.addressOf(env, subject.id);
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+ //#endregion
33
+ export { composedAddress, composedConsent, composedConsentPurposes, providesConsent };
@@ -22,8 +22,8 @@ import type { Logger } from "../../logger/logger";
22
22
  * Emission goes through core's `emit` seam (`c.var.emit`), a no-op when the audit capability is
23
23
  * absent, so the seam never imports audit at runtime either (principle 4).
24
24
  *
25
- * **Four of these are emitted by a route; three are emitted by the CLI** (#294). The connection
26
- * lifecycle — registered, updated, removed — is written by `pithy dashboard` opening the adopter's D1
25
+ * **Most of these are emitted by a route; four are emitted by the CLI, one of them by a route as well.** The
26
+ * connection lifecycle — registered, updated, removed — is written by `pithy dashboard` opening the adopter's D1
27
27
  * directly, because those operations never reach their Worker: a first connect has no key to sign with
28
28
  * and the Worker may not be deployed, an update re-points an address the Worker never reads, and a
29
29
  * disconnect withdraws trust, which must not depend on a working connection (docs/CONTROL-PLANE.md §15).
@@ -32,8 +32,12 @@ import type { Logger } from "../../logger/logger";
32
32
  * `control-plane`, meaning the management client called in and proved it, while a CLI-side event carries
33
33
  * the adopter's own operator and no session at all.
34
34
  *
35
- * A declared code that nothing emits is a surface the trail promises and never delivers, which is what
36
- * these three were until #294. `packages/cli/src/ci/auditActions.test.ts` fails the build on one.
35
+ * `connectionRevoked` is the one written from both sides: by `POST {basePath}/connections/:connectionId/revoke`,
36
+ * with `actorType` `control-plane` and the caller's connection, and by `pithy dashboard connections --revoke`, with
37
+ * the operator as actor and no session.
38
+ *
39
+ * A declared code that nothing emits is a surface the trail promises and never delivers.
40
+ * `packages/cli/src/ci/auditActions.test.ts` fails the build on one.
37
41
  */
38
42
  export declare const ControlPlaneAuditActions: {
39
43
  /** A verified, in-scope management call was admitted. The trail of what the dashboard actually did. */
@@ -50,6 +54,13 @@ export declare const ControlPlaneAuditActions: {
50
54
  readonly connectionUpdated: "controlplane/connection_updated";
51
55
  /** A connection was removed. The seam returns to its shipped state: connected to nothing, denying everything. */
52
56
  readonly connectionRemoved: "controlplane/connection_removed";
57
+ /**
58
+ * Another connection's keys and trusts were revoked, with a reason: by a management client over the seam, or by the
59
+ * operator at the CLI.
60
+ */
61
+ readonly connectionRevoked: "controlplane/connection_revoked";
62
+ readonly holdPlaced: "controlplane/hold_placed";
63
+ readonly holdReleased: "controlplane/hold_released";
53
64
  };
54
65
  /** One of the control-plane audit action codes. */
55
66
  export type ControlPlaneAuditAction = (typeof ControlPlaneAuditActions)[keyof typeof ControlPlaneAuditActions];
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/audit/actions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,wBAAwB;IACnC,uGAAuG;aACvG,WAAW,EAAE,2BAA2B;IACxC,8GAA8G;aAC9G,UAAU,EAAE,0BAA0B;IACtC,mFAAmF;aACnF,aAAa,EAAE,6BAA6B;IAC5C,gFAAgF;aAChF,UAAU,EAAE,0BAA0B;IACtC,qGAAqG;aACrG,oBAAoB,EAAE,oCAAoC;IAC1D,+GAA+G;aAC/G,iBAAiB,EAAE,iCAAiC;IACpD,iHAAiH;aACjH,iBAAiB,EAAE,iCAAiC;CAC5C,CAAC;AAEX,mDAAmD;AACnD,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,OAAO,wBAAwB,CAAC,CAAC;AAE/G;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMnG"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/audit/actions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,wBAAwB;IACnC,uGAAuG;aACvG,WAAW,EAAE,2BAA2B;IACxC,8GAA8G;aAC9G,UAAU,EAAE,0BAA0B;IACtC,mFAAmF;aACnF,aAAa,EAAE,6BAA6B;IAC5C,gFAAgF;aAChF,UAAU,EAAE,0BAA0B;IACtC,qGAAqG;aACrG,oBAAoB,EAAE,oCAAoC;IAC1D,+GAA+G;aAC/G,iBAAiB,EAAE,iCAAiC;IACpD,iHAAiH;aACjH,iBAAiB,EAAE,iCAAiC;IACpD;;;OAGG;aACH,iBAAiB,EAAE,iCAAiC;aACpD,UAAU,EAAE,0BAA0B;aACtC,YAAY,EAAE,4BAA4B;CAClC,CAAC;AAEX,mDAAmD;AACnD,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,OAAO,wBAAwB,CAAC,CAAC;AAE/G;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMnG"}
@@ -20,8 +20,8 @@
20
20
  * Emission goes through core's `emit` seam (`c.var.emit`), a no-op when the audit capability is
21
21
  * absent, so the seam never imports audit at runtime either (principle 4).
22
22
  *
23
- * **Four of these are emitted by a route; three are emitted by the CLI** (#294). The connection
24
- * lifecycle — registered, updated, removed — is written by `pithy dashboard` opening the adopter's D1
23
+ * **Most of these are emitted by a route; four are emitted by the CLI, one of them by a route as well.** The
24
+ * connection lifecycle — registered, updated, removed — is written by `pithy dashboard` opening the adopter's D1
25
25
  * directly, because those operations never reach their Worker: a first connect has no key to sign with
26
26
  * and the Worker may not be deployed, an update re-points an address the Worker never reads, and a
27
27
  * disconnect withdraws trust, which must not depend on a working connection (docs/CONTROL-PLANE.md §15).
@@ -30,8 +30,12 @@
30
30
  * `control-plane`, meaning the management client called in and proved it, while a CLI-side event carries
31
31
  * the adopter's own operator and no session at all.
32
32
  *
33
- * A declared code that nothing emits is a surface the trail promises and never delivers, which is what
34
- * these three were until #294. `packages/cli/src/ci/auditActions.test.ts` fails the build on one.
33
+ * `connectionRevoked` is the one written from both sides: by `POST {basePath}/connections/:connectionId/revoke`,
34
+ * with `actorType` `control-plane` and the caller's connection, and by `pithy dashboard connections --revoke`, with
35
+ * the operator as actor and no session.
36
+ *
37
+ * A declared code that nothing emits is a surface the trail promises and never delivers.
38
+ * `packages/cli/src/ci/auditActions.test.ts` fails the build on one.
35
39
  */
36
40
  const ControlPlaneAuditActions = {
37
41
  /** A verified, in-scope management call was admitted. The trail of what the dashboard actually did. */
@@ -47,7 +51,14 @@ const ControlPlaneAuditActions = {
47
51
  /** An existing connection changed — its granted scopes, the Worker URL it points at, or the keys it trusts. */
48
52
  connectionUpdated: "controlplane/connection_updated",
49
53
  /** A connection was removed. The seam returns to its shipped state: connected to nothing, denying everything. */
50
- connectionRemoved: "controlplane/connection_removed"
54
+ connectionRemoved: "controlplane/connection_removed",
55
+ /**
56
+ * Another connection's keys and trusts were revoked, with a reason: by a management client over the seam, or by the
57
+ * operator at the CLI.
58
+ */
59
+ connectionRevoked: "controlplane/connection_revoked",
60
+ holdPlaced: "controlplane/hold_placed",
61
+ holdReleased: "controlplane/hold_released"
51
62
  };
52
63
  /**
53
64
  * Emit an audit event and swallow any failure.
@@ -17,6 +17,16 @@ import { CONTROL_PLANE_KV_BINDING } from "./replay/kvGuard";
17
17
  */
18
18
  export declare const CONTROLPLANE_MIGRATION_ORDER = 1100;
19
19
  export type ControlPlaneOptions = ControlPlaneConfigInput;
20
+ /** The standing legal holds, on the seam's own manifest entry. Behind the scope the holds listing requires. */
21
+ export declare const ACTIVE_HOLDS_HEALTH_KEY: {
22
+ readonly key: "activeHolds";
23
+ readonly kind: "count";
24
+ readonly states: null;
25
+ readonly scope: string;
26
+ readonly cost: "indexed";
27
+ readonly summary: "Legal holds standing. While one stands, no purge, prune or inactivity deletion touches its subject.";
28
+ readonly nominal: null;
29
+ };
20
30
  /** The control-plane capability, with its resolved config attached. */
21
31
  export interface ControlPlaneCapability extends Capability<DatabaseSpecMap, KvNamespaceSpecMap, "controlplane"> {
22
32
  /** The resolved seam config. */
@@ -1 +1 @@
1
- {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../../src/controlPlane/capability.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,UAAU,EAAuC,MAAM,0BAA0B,CAAC;AAChG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAc,MAAM,kBAAkB,CAAC;AAKvE,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAkBnF,OAAO,EACL,wBAAwB,EAIzB,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,MAAM,MAAM,mBAAmB,GAAG,uBAAuB,CAAC;AAE1D,uEAAuE;AACvE,MAAM,WAAW,sBAAuB,SAAQ,UAAU,CAAC,eAAe,EAAE,kBAAkB,EAAE,cAAc,CAAC;IAC7G,gCAAgC;IAChC,kBAAkB,EAAE,kBAAkB,CAAC;CACxC;AAED,qGAAqG;AACrG,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,IAAI,sBAAsB,CAErG;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,sBAAsB,CA6LtF;AAED,4GAA4G;AAC5G,OAAO,EAAE,wBAAwB,EAAE,CAAC"}
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../../src/controlPlane/capability.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,UAAU,EAAuC,MAAM,0BAA0B,CAAC;AAChG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,KAAK,EAAE,kBAAkB,EAAc,MAAM,kBAAkB,CAAC;AAWvE,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAqBnF,OAAO,EACL,wBAAwB,EAIzB,MAAM,kBAAkB,CAAC;AAG1B;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,MAAM,MAAM,mBAAmB,GAAG,uBAAuB,CAAC;AAE1D,+GAA+G;AAC/G,eAAO,MAAM,uBAAuB;aAClC,GAAG,EAAE,aAAa;aAClB,IAAI,EAAE,OAAO;aACb,MAAM;aACN,KAAK;aACL,IAAI,EAAE,SAAS;aACf,OAAO,EAAE,qGAAqG;aAC9G,OAAO;CACC,CAAC;AAEX,uEAAuE;AACvE,MAAM,WAAW,sBAAuB,SAAQ,UAAU,CAAC,eAAe,EAAE,kBAAkB,EAAE,cAAc,CAAC;IAC7G,gCAAgC;IAChC,kBAAkB,EAAE,kBAAkB,CAAC;CACxC;AAED,qGAAqG;AACrG,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,IAAI,sBAAsB,CAErG;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,sBAAsB,CAsPtF;AAED,4GAA4G;AAC5G,OAAO,EAAE,wBAAwB,EAAE,CAAC"}