@pithy-sh/core 0.13.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 (354) 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/capability/bindings.d.ts +22 -0
  10. package/dist/capability/bindings.d.ts.map +1 -1
  11. package/dist/capability/bindings.js +32 -2
  12. package/dist/capability/capability.d.ts +123 -16
  13. package/dist/capability/capability.d.ts.map +1 -1
  14. package/dist/capability/capability.js +17 -2
  15. package/dist/capability/erasure.d.ts +75 -0
  16. package/dist/capability/erasure.d.ts.map +1 -0
  17. package/dist/capability/erasure.js +2 -0
  18. package/dist/capability/manifest.d.ts +5 -0
  19. package/dist/capability/manifest.d.ts.map +1 -1
  20. package/dist/capability/personColumns.d.ts +28 -0
  21. package/dist/capability/personColumns.d.ts.map +1 -0
  22. package/dist/capability/personColumns.js +66 -0
  23. package/dist/capability/personRows.d.ts +62 -0
  24. package/dist/capability/personRows.d.ts.map +1 -0
  25. package/dist/capability/personRows.js +59 -0
  26. package/dist/capability/purge.d.ts +86 -19
  27. package/dist/capability/purge.d.ts.map +1 -1
  28. package/dist/capability/purge.js +83 -5
  29. package/dist/capability/settings.d.ts +10 -0
  30. package/dist/capability/settings.d.ts.map +1 -1
  31. package/dist/capability/vectorIndex.d.ts +36 -0
  32. package/dist/capability/vectorIndex.d.ts.map +1 -0
  33. package/dist/capability/vectorIndex.js +25 -0
  34. package/dist/cli/commandCatalog.generated.d.ts +433 -3
  35. package/dist/cli/commandCatalog.generated.d.ts.map +1 -1
  36. package/dist/cli/commandCatalog.generated.js +449 -2
  37. package/dist/cli/commandFacts.d.ts +8 -5
  38. package/dist/cli/commandFacts.d.ts.map +1 -1
  39. package/dist/cli/commandFacts.js +12 -3
  40. package/dist/consent/purpose.d.ts +70 -0
  41. package/dist/consent/purpose.d.ts.map +1 -0
  42. package/dist/consent/purpose.js +97 -0
  43. package/dist/consent/reader.d.ts +99 -0
  44. package/dist/consent/reader.d.ts.map +1 -0
  45. package/dist/consent/reader.js +33 -0
  46. package/dist/controlPlane/audit/actions.d.ts +15 -4
  47. package/dist/controlPlane/audit/actions.d.ts.map +1 -1
  48. package/dist/controlPlane/audit/actions.js +16 -5
  49. package/dist/controlPlane/capability.d.ts +10 -0
  50. package/dist/controlPlane/capability.d.ts.map +1 -1
  51. package/dist/controlPlane/capability.js +56 -8
  52. package/dist/controlPlane/context.d.ts +4 -0
  53. package/dist/controlPlane/context.d.ts.map +1 -1
  54. package/dist/controlPlane/context.js +3 -2
  55. package/dist/controlPlane/data/connection.d.ts +21 -2
  56. package/dist/controlPlane/data/connection.d.ts.map +1 -1
  57. package/dist/controlPlane/data/connection.js +13 -4
  58. package/dist/controlPlane/data/connections.d.ts +94 -0
  59. package/dist/controlPlane/data/connections.d.ts.map +1 -0
  60. package/dist/controlPlane/data/connections.js +151 -0
  61. package/dist/controlPlane/data/hold.d.ts +46 -0
  62. package/dist/controlPlane/data/hold.d.ts.map +1 -0
  63. package/dist/controlPlane/data/hold.js +36 -0
  64. package/dist/controlPlane/data/oidcTrust.d.ts +122 -0
  65. package/dist/controlPlane/data/oidcTrust.d.ts.map +1 -0
  66. package/dist/controlPlane/data/oidcTrust.js +173 -0
  67. package/dist/controlPlane/data/tables.d.ts +4 -0
  68. package/dist/controlPlane/data/tables.d.ts.map +1 -1
  69. package/dist/controlPlane/data/tables.js +9 -4
  70. package/dist/controlPlane/data/trustFirstCall.d.ts +16 -0
  71. package/dist/controlPlane/data/trustFirstCall.d.ts.map +1 -0
  72. package/dist/controlPlane/data/trustFirstCall.js +25 -0
  73. package/dist/controlPlane/discovery/adminRoute.d.ts +165 -2
  74. package/dist/controlPlane/discovery/adminRoute.d.ts.map +1 -1
  75. package/dist/controlPlane/discovery/adminRoute.js +32 -8
  76. package/dist/controlPlane/discovery/routeInput.d.ts +23 -0
  77. package/dist/controlPlane/discovery/routeInput.d.ts.map +1 -0
  78. package/dist/controlPlane/discovery/routeInput.js +80 -0
  79. package/dist/controlPlane/discovery/toolName.d.ts +21 -0
  80. package/dist/controlPlane/discovery/toolName.d.ts.map +1 -0
  81. package/dist/controlPlane/discovery/toolName.js +25 -0
  82. package/dist/controlPlane/erasure/attest.d.ts +78 -0
  83. package/dist/controlPlane/erasure/attest.d.ts.map +1 -0
  84. package/dist/controlPlane/erasure/attest.js +164 -0
  85. package/dist/controlPlane/erasure/read.d.ts +39 -0
  86. package/dist/controlPlane/erasure/read.d.ts.map +1 -0
  87. package/dist/controlPlane/erasure/read.js +140 -0
  88. package/dist/controlPlane/error/errors.d.ts +61 -2
  89. package/dist/controlPlane/error/errors.d.ts.map +1 -1
  90. package/dist/controlPlane/error/errors.js +13 -0
  91. package/dist/controlPlane/evidence/derive.d.ts +124 -0
  92. package/dist/controlPlane/evidence/derive.d.ts.map +1 -0
  93. package/dist/controlPlane/evidence/derive.js +343 -0
  94. package/dist/controlPlane/evidence/mapping.d.ts +85 -0
  95. package/dist/controlPlane/evidence/mapping.d.ts.map +1 -0
  96. package/dist/controlPlane/evidence/mapping.js +114 -0
  97. package/dist/controlPlane/evidence/pack.d.ts +46 -0
  98. package/dist/controlPlane/evidence/pack.d.ts.map +1 -0
  99. package/dist/controlPlane/evidence/pack.js +124 -0
  100. package/dist/controlPlane/http/connections.d.ts +96 -0
  101. package/dist/controlPlane/http/connections.d.ts.map +1 -0
  102. package/dist/controlPlane/http/connections.js +109 -0
  103. package/dist/controlPlane/http/guard.d.ts +23 -2
  104. package/dist/controlPlane/http/guard.d.ts.map +1 -1
  105. package/dist/controlPlane/http/guard.js +69 -12
  106. package/dist/controlPlane/http/handlers.d.ts +212 -10
  107. package/dist/controlPlane/http/handlers.d.ts.map +1 -1
  108. package/dist/controlPlane/http/handlers.js +117 -26
  109. package/dist/controlPlane/http/holds.d.ts +57 -0
  110. package/dist/controlPlane/http/holds.d.ts.map +1 -0
  111. package/dist/controlPlane/http/holds.js +98 -0
  112. package/dist/controlPlane/http/presence.d.ts +27 -0
  113. package/dist/controlPlane/http/presence.d.ts.map +1 -0
  114. package/dist/controlPlane/http/presence.js +67 -0
  115. package/dist/controlPlane/http/processing.d.ts +73 -0
  116. package/dist/controlPlane/http/processing.d.ts.map +1 -0
  117. package/dist/controlPlane/http/processing.js +17 -0
  118. package/dist/controlPlane/http/responses.d.ts +927 -3
  119. package/dist/controlPlane/http/responses.d.ts.map +1 -1
  120. package/dist/controlPlane/http/responses.js +283 -7
  121. package/dist/controlPlane/http/routes.d.ts +12 -2
  122. package/dist/controlPlane/http/routes.d.ts.map +1 -1
  123. package/dist/controlPlane/http/routes.js +182 -5
  124. package/dist/controlPlane/http/schemas.d.ts +63 -0
  125. package/dist/controlPlane/http/schemas.d.ts.map +1 -1
  126. package/dist/controlPlane/http/schemas.js +39 -1
  127. package/dist/controlPlane/http/verify.d.ts.map +1 -1
  128. package/dist/controlPlane/http/verify.js +13 -1
  129. package/dist/controlPlane/http/verifyTrust.d.ts +76 -0
  130. package/dist/controlPlane/http/verifyTrust.d.ts.map +1 -0
  131. package/dist/controlPlane/http/verifyTrust.js +75 -0
  132. package/dist/controlPlane/migrations/0004_connection_trusts.d.ts +15 -0
  133. package/dist/controlPlane/migrations/0004_connection_trusts.d.ts.map +1 -0
  134. package/dist/controlPlane/migrations/0004_connection_trusts.js +23 -0
  135. package/dist/controlPlane/migrations/0005_holds.d.ts +12 -0
  136. package/dist/controlPlane/migrations/0005_holds.d.ts.map +1 -0
  137. package/dist/controlPlane/migrations/0005_holds.js +26 -0
  138. package/dist/controlPlane/processing/derive.d.ts +77 -0
  139. package/dist/controlPlane/processing/derive.d.ts.map +1 -0
  140. package/dist/controlPlane/processing/derive.js +206 -0
  141. package/dist/controlPlane/processing/read.d.ts +10 -0
  142. package/dist/controlPlane/processing/read.d.ts.map +1 -0
  143. package/dist/controlPlane/processing/read.js +89 -0
  144. package/dist/controlPlane/scope/kind.d.ts +46 -0
  145. package/dist/controlPlane/scope/kind.d.ts.map +1 -0
  146. package/dist/controlPlane/scope/kind.js +52 -0
  147. package/dist/controlPlane/scope/scope.d.ts +58 -3
  148. package/dist/controlPlane/scope/scope.d.ts.map +1 -1
  149. package/dist/controlPlane/scope/scope.js +59 -4
  150. package/dist/controlPlane/token/jws.js +1 -1
  151. package/dist/controlPlane/token/mint.js +1 -1
  152. package/dist/controlPlane/wire.d.ts +23 -0
  153. package/dist/controlPlane/wire.d.ts.map +1 -1
  154. package/dist/controlPlane/wire.js +24 -1
  155. package/dist/createBackend.d.ts +13 -0
  156. package/dist/createBackend.d.ts.map +1 -1
  157. package/dist/createBackend.js +11 -3
  158. package/dist/createEntrypoint.d.ts +7 -0
  159. package/dist/createEntrypoint.d.ts.map +1 -1
  160. package/dist/createEntrypoint.js +4 -0
  161. package/dist/error/http.d.ts +168 -0
  162. package/dist/error/http.d.ts.map +1 -1
  163. package/dist/error/payload.d.ts +336 -0
  164. package/dist/error/payload.d.ts.map +1 -1
  165. package/dist/error/payload.js +112 -0
  166. package/dist/error/pithyError.d.ts +22 -0
  167. package/dist/error/pithyError.d.ts.map +1 -1
  168. package/dist/error/pithyError.js +31 -1
  169. package/dist/http/routeSpec.d.ts +46 -1
  170. package/dist/http/routeSpec.d.ts.map +1 -1
  171. package/dist/http/routeSpec.js +39 -5
  172. package/dist/http/verification.d.ts.map +1 -1
  173. package/dist/http/verification.js +1 -1
  174. package/dist/i18n/translator.d.ts +2 -1
  175. package/dist/i18n/translator.d.ts.map +1 -1
  176. package/dist/index.d.ts +1 -1
  177. package/dist/index.d.ts.map +1 -1
  178. package/dist/index.js +3 -3
  179. package/dist/logger/record.d.ts +98 -0
  180. package/dist/logger/record.d.ts.map +1 -1
  181. package/dist/mcp/annotations.d.ts +20 -0
  182. package/dist/mcp/annotations.d.ts.map +1 -0
  183. package/dist/mcp/annotations.js +23 -0
  184. package/dist/mcp/tools.d.ts +75 -0
  185. package/dist/mcp/tools.d.ts.map +1 -0
  186. package/dist/mcp/tools.js +118 -0
  187. package/dist/openapi/document.d.ts.map +1 -1
  188. package/dist/openapi/document.js +8 -26
  189. package/dist/openapi/operations.d.ts +35 -0
  190. package/dist/openapi/operations.d.ts.map +1 -0
  191. package/dist/openapi/operations.js +37 -0
  192. package/dist/presence/channel.d.ts +11 -0
  193. package/dist/presence/channel.d.ts.map +1 -0
  194. package/dist/presence/channel.js +65 -0
  195. package/dist/presence/declaration.d.ts +154 -0
  196. package/dist/presence/declaration.d.ts.map +1 -0
  197. package/dist/presence/declaration.js +164 -0
  198. package/dist/presence/durableObject.d.ts +61 -0
  199. package/dist/presence/durableObject.d.ts.map +1 -0
  200. package/dist/presence/durableObject.js +257 -0
  201. package/dist/presence/frames.d.ts +166 -0
  202. package/dist/presence/frames.d.ts.map +1 -0
  203. package/dist/presence/frames.js +90 -0
  204. package/dist/presence/http/guard.d.ts +11 -0
  205. package/dist/presence/http/guard.d.ts.map +1 -0
  206. package/dist/presence/http/guard.js +20 -0
  207. package/dist/presence/http/responses.d.ts +31 -0
  208. package/dist/presence/http/responses.d.ts.map +1 -0
  209. package/dist/presence/http/responses.js +34 -0
  210. package/dist/presence/http/routes.d.ts +24 -0
  211. package/dist/presence/http/routes.d.ts.map +1 -0
  212. package/dist/presence/http/routes.js +127 -0
  213. package/dist/presence/http/schemas.d.ts +29 -0
  214. package/dist/presence/http/schemas.d.ts.map +1 -0
  215. package/dist/presence/http/schemas.js +28 -0
  216. package/dist/presence/names.d.ts +23 -0
  217. package/dist/presence/names.d.ts.map +1 -0
  218. package/dist/presence/names.js +22 -0
  219. package/dist/presence/room.d.ts +95 -0
  220. package/dist/presence/room.d.ts.map +1 -0
  221. package/dist/presence/room.js +105 -0
  222. package/dist/presence/ticket.d.ts +55 -0
  223. package/dist/presence/ticket.d.ts.map +1 -0
  224. package/dist/presence/ticket.js +109 -0
  225. package/dist/privacy/classify.js +1 -1
  226. package/dist/privacy/encrypted.js +1 -1
  227. package/dist/processing/activity.d.ts +134 -0
  228. package/dist/processing/activity.d.ts.map +1 -0
  229. package/dist/processing/activity.js +161 -0
  230. package/dist/processing/composed.d.ts +18 -0
  231. package/dist/processing/composed.d.ts.map +1 -0
  232. package/dist/processing/composed.js +28 -0
  233. package/dist/processing/vocabulary.d.ts +26 -0
  234. package/dist/processing/vocabulary.d.ts.map +1 -0
  235. package/dist/processing/vocabulary.js +35 -0
  236. package/dist/queue/consumer.d.ts +59 -0
  237. package/dist/queue/consumer.d.ts.map +1 -0
  238. package/dist/queue/consumer.js +46 -0
  239. package/dist/retention/composed.d.ts +37 -0
  240. package/dist/retention/composed.d.ts.map +1 -0
  241. package/dist/retention/composed.js +66 -0
  242. package/dist/retention/holds.d.ts +61 -0
  243. package/dist/retention/holds.d.ts.map +1 -0
  244. package/dist/retention/holds.js +107 -0
  245. package/dist/retention/holdsPurge.d.ts +22 -0
  246. package/dist/retention/holdsPurge.d.ts.map +1 -0
  247. package/dist/retention/holdsPurge.js +50 -0
  248. package/dist/retention/policy.d.ts +132 -0
  249. package/dist/retention/policy.d.ts.map +1 -0
  250. package/dist/retention/policy.js +197 -0
  251. package/dist/session/rotated.d.ts +34 -0
  252. package/dist/session/rotated.d.ts.map +1 -0
  253. package/dist/session/rotated.js +25 -0
  254. package/dist/test-utils/connectionFixtures.d.ts +13 -0
  255. package/dist/test-utils/connectionFixtures.d.ts.map +1 -0
  256. package/dist/test-utils/connectionFixtures.js +58 -0
  257. package/dist/test-utils/interleave.d.ts +12 -0
  258. package/dist/test-utils/interleave.d.ts.map +1 -0
  259. package/dist/test-utils/interleave.js +26 -0
  260. package/dist/testWorker.d.ts +8 -0
  261. package/dist/testWorker.d.ts.map +1 -0
  262. package/dist/testWorker.js +9 -0
  263. package/dist/version.generated.d.ts +1 -1
  264. package/dist/version.generated.js +1 -1
  265. package/dist/workflow/dispatchRoute.js +1 -1
  266. package/package.json +1 -1
  267. package/src/audit/auditEvent.ts +1 -1
  268. package/src/audit/chain.ts +551 -0
  269. package/src/audit/citations.ts +63 -0
  270. package/src/capability/bindings.ts +61 -0
  271. package/src/capability/capability.ts +156 -19
  272. package/src/capability/erasure.ts +82 -0
  273. package/src/capability/personColumns.ts +83 -0
  274. package/src/capability/personRows.ts +125 -0
  275. package/src/capability/purge.ts +158 -21
  276. package/src/capability/settings.ts +7 -0
  277. package/src/capability/vectorIndex.ts +60 -0
  278. package/src/cli/commandCatalog.generated.ts +482 -2
  279. package/src/cli/commandFacts.ts +12 -3
  280. package/src/cloudflare-test.d.ts +3 -1
  281. package/src/consent/purpose.ts +160 -0
  282. package/src/consent/reader.ts +134 -0
  283. package/src/controlPlane/audit/actions.ts +15 -4
  284. package/src/controlPlane/capability.ts +99 -20
  285. package/src/controlPlane/context.ts +10 -2
  286. package/src/controlPlane/data/connection.ts +16 -2
  287. package/src/controlPlane/data/connections.ts +231 -0
  288. package/src/controlPlane/data/hold.ts +52 -0
  289. package/src/controlPlane/data/oidcTrust.ts +249 -0
  290. package/src/controlPlane/data/tables.ts +7 -0
  291. package/src/controlPlane/data/trustFirstCall.ts +37 -0
  292. package/src/controlPlane/discovery/adminRoute.ts +71 -9
  293. package/src/controlPlane/discovery/routeInput.ts +86 -0
  294. package/src/controlPlane/discovery/toolName.ts +23 -0
  295. package/src/controlPlane/erasure/attest.ts +205 -0
  296. package/src/controlPlane/erasure/read.ts +169 -0
  297. package/src/controlPlane/error/errors.ts +69 -2
  298. package/src/controlPlane/evidence/derive.ts +426 -0
  299. package/src/controlPlane/evidence/mapping.ts +118 -0
  300. package/src/controlPlane/evidence/pack.ts +190 -0
  301. package/src/controlPlane/http/connections.ts +129 -0
  302. package/src/controlPlane/http/guard.ts +118 -9
  303. package/src/controlPlane/http/handlers.ts +172 -40
  304. package/src/controlPlane/http/holds.ts +108 -0
  305. package/src/controlPlane/http/presence.ts +71 -0
  306. package/src/controlPlane/http/processing.ts +19 -0
  307. package/src/controlPlane/http/responses.ts +590 -7
  308. package/src/controlPlane/http/routes.ts +302 -3
  309. package/src/controlPlane/http/schemas.ts +126 -0
  310. package/src/controlPlane/http/verify.ts +19 -2
  311. package/src/controlPlane/http/verifyTrust.ts +176 -0
  312. package/src/controlPlane/migrations/0004_connection_trusts.ts +30 -0
  313. package/src/controlPlane/migrations/0005_holds.ts +40 -0
  314. package/src/controlPlane/processing/derive.ts +359 -0
  315. package/src/controlPlane/processing/read.ts +102 -0
  316. package/src/controlPlane/scope/kind.ts +63 -0
  317. package/src/controlPlane/scope/scope.ts +65 -3
  318. package/src/controlPlane/wire.ts +26 -0
  319. package/src/createBackend.ts +31 -6
  320. package/src/createEntrypoint.ts +17 -0
  321. package/src/error/payload.ts +234 -0
  322. package/src/error/pithyError.ts +42 -0
  323. package/src/http/routeSpec.ts +75 -5
  324. package/src/http/verification.ts +3 -1
  325. package/src/i18n/translator.ts +2 -1
  326. package/src/index.ts +2 -0
  327. package/src/mcp/annotations.ts +38 -0
  328. package/src/mcp/tools.ts +220 -0
  329. package/src/openapi/document.ts +8 -28
  330. package/src/openapi/operations.ts +62 -0
  331. package/src/presence/channel.ts +46 -0
  332. package/src/presence/declaration.ts +283 -0
  333. package/src/presence/durableObject.ts +287 -0
  334. package/src/presence/frames.ts +153 -0
  335. package/src/presence/http/guard.ts +23 -0
  336. package/src/presence/http/responses.ts +63 -0
  337. package/src/presence/http/routes.ts +165 -0
  338. package/src/presence/http/schemas.ts +39 -0
  339. package/src/presence/names.ts +45 -0
  340. package/src/presence/room.ts +145 -0
  341. package/src/presence/ticket.ts +145 -0
  342. package/src/processing/activity.ts +289 -0
  343. package/src/processing/composed.ts +33 -0
  344. package/src/processing/vocabulary.ts +43 -0
  345. package/src/queue/consumer.ts +104 -0
  346. package/src/retention/composed.ts +75 -0
  347. package/src/retention/holds.ts +175 -0
  348. package/src/retention/holdsPurge.ts +50 -0
  349. package/src/retention/policy.ts +305 -0
  350. package/src/session/rotated.ts +53 -0
  351. package/src/test-utils/connectionFixtures.ts +58 -0
  352. package/src/test-utils/interleave.ts +31 -0
  353. package/src/testWorker.ts +13 -0
  354. package/src/version.generated.ts +1 -1
@@ -0,0 +1,98 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { countActiveHolds, listHolds, placeHold, releaseHold } from "../../retention/holds.js";
4
+ import { ControlPlaneAuditActions, safeEmit } from "../audit/actions.js";
5
+ import { caller } from "./handlers.js";
6
+ //#region src/controlPlane/http/holds.ts
7
+ /**
8
+ * The legal-hold routes: place, release, list.
9
+ *
10
+ * Placing and releasing are each audited under `controlplane/*`, which the retention floor keeps at least a year,
11
+ * with the subject, the hold and the reason. A hold suspends every purge, prune and inactivity deletion touching its
12
+ * subject; the capabilities that erase read it through `retention/holds.ts`. **Nothing here shortens a retention**:
13
+ * a hold can only preserve, and its release returns the subject to the policy the Worker was deployed with.
14
+ */
15
+ /** The default page of `GET /control-plane/holds`. */
16
+ const DEFAULT_HOLD_LIMIT = 100;
17
+ /** A hold, as the routes answer it. */
18
+ function holdView(hold) {
19
+ return {
20
+ id: hold.id,
21
+ subjectType: hold.subjectType,
22
+ subjectId: hold.subjectId,
23
+ reason: hold.reason,
24
+ placedBy: hold.placedBy,
25
+ placedAt: hold.placedAt.toISOString(),
26
+ state: hold.state,
27
+ releasedAt: hold.releasedAt?.toISOString() ?? null,
28
+ releasedBy: hold.releasedBy,
29
+ releaseReason: hold.releaseReason
30
+ };
31
+ }
32
+ /** The audit event for a placement or a release: the subject as the resource, the hold and the reason beside it. */
33
+ async function auditHold(c, action, hold, reason) {
34
+ const context = caller(c);
35
+ await safeEmit(c.var.emit, {
36
+ action,
37
+ outcome: "success",
38
+ severity: "warning",
39
+ actorType: "control-plane",
40
+ actorId: context.subject,
41
+ resourceType: hold.subjectType === "audit" ? "audit_trail" : hold.subjectType,
42
+ resourceId: hold.subjectId,
43
+ requestId: c.req.header("cf-ray"),
44
+ ip: c.req.header("cf-connecting-ip"),
45
+ userAgent: c.req.header("user-agent"),
46
+ metadata: {
47
+ holdId: hold.id,
48
+ subjectType: hold.subjectType,
49
+ reason
50
+ }
51
+ }, c.var.log);
52
+ }
53
+ /** `POST /control-plane/holds` — place a hold. */
54
+ function placeHoldHandler(deps) {
55
+ return async (c, body) => {
56
+ const context = caller(c);
57
+ const hold = await placeHold(deps.database(c), {
58
+ subjectType: body.subjectType,
59
+ subjectId: body.subjectId,
60
+ reason: body.reason,
61
+ actor: { subject: context.subject },
62
+ at: deps.now()
63
+ });
64
+ await auditHold(c, ControlPlaneAuditActions.holdPlaced, hold, body.reason);
65
+ return c.json({ hold: holdView(hold) }, 201);
66
+ };
67
+ }
68
+ /** `POST /control-plane/holds/:holdId/release` — release a hold, with a reason. */
69
+ function releaseHoldHandler(deps) {
70
+ return async (c, params, body) => {
71
+ const context = caller(c);
72
+ const hold = await releaseHold(deps.database(c), {
73
+ id: params.holdId,
74
+ reason: body.reason,
75
+ actor: { subject: context.subject },
76
+ at: deps.now()
77
+ });
78
+ await auditHold(c, ControlPlaneAuditActions.holdReleased, hold, body.reason);
79
+ return c.json({ hold: holdView(hold) });
80
+ };
81
+ }
82
+ /** `GET /control-plane/holds` — every hold, standing first. Read-only. */
83
+ function listHoldsHandler(deps) {
84
+ return async (c, query) => {
85
+ caller(c);
86
+ const db = deps.database(c);
87
+ const holds = await listHolds(db, {
88
+ ...query.state ? { state: query.state } : {},
89
+ limit: query.limit ?? DEFAULT_HOLD_LIMIT
90
+ });
91
+ return c.json({
92
+ active: await countActiveHolds(db),
93
+ holds: holds.map(holdView)
94
+ });
95
+ };
96
+ }
97
+ //#endregion
98
+ export { holdView, listHoldsHandler, placeHoldHandler, releaseHoldHandler };
@@ -0,0 +1,27 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import type { Context, MiddlewareHandler } from "hono";
4
+ import type { PithyHonoEnv } from "../../capability/capability";
5
+ import type { ControlPlanePresenceTicketRequest } from "../../presence/http/schemas";
6
+ import { type ControlPlaneRequirementResolver } from "./guard";
7
+ import type { ControlPlaneHandlerDeps } from "./handlers";
8
+ /**
9
+ * `POST /control-plane/presence/tickets` — a ticket into any room this Worker composes, for a management
10
+ * client.
11
+ *
12
+ * **The scope is the room kind's, and the gate checks it.** Which scope a call needs is named in its body, so
13
+ * {@link presenceTicketRequirement} reads the kind from a copy of the body before the gate verifies, and the
14
+ * gate then verifies against that kind's scope exactly as it would against a route's own: one allowed row
15
+ * when it covers, one denial row naming the kind's scope when it does not, never both. Presence adds no scope
16
+ * of its own: a connection that may read a record may see who else has it open.
17
+ *
18
+ * A body that names no declared kind needs only a verified caller, so an unverified one is refused before any
19
+ * kind is looked at, and a verified one then gets the handler's 404 — the manifest lists every kind, so its
20
+ * existence is no secret.
21
+ */
22
+ export declare function presenceTicketRequirement(deps: ControlPlaneHandlerDeps): ControlPlaneRequirementResolver;
23
+ /** The gate the route wears: {@link requireControlPlaneFor} over the room kind's scope. */
24
+ export declare function presenceTicketGate(deps: ControlPlaneHandlerDeps): MiddlewareHandler<PithyHonoEnv>;
25
+ /** The handler, behind {@link presenceTicketGate}: the kind's scope is already verified, so it mints. */
26
+ export declare function presenceTicketHandler(deps: ControlPlaneHandlerDeps): (c: Context<PithyHonoEnv>, body: ControlPlanePresenceTicketRequest) => Promise<Response>;
27
+ //# sourceMappingURL=presence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/presence.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAIhE,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,6BAA6B,CAAC;AAErF,OAAO,EAAE,KAAK,+BAA+B,EAA0B,MAAM,SAAS,CAAC;AACvF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,uBAAuB,GAAG,+BAA+B,CAOxG;AAED,2FAA2F;AAC3F,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,uBAAuB,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAEjG;AAgBD,yGAAyG;AACzG,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,uBAAuB,OAChD,OAAO,CAAC,YAAY,CAAC,QAAQ,iCAAiC,KAAG,OAAO,CAAC,QAAQ,CAAC,CAapG"}
@@ -0,0 +1,67 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { NotFoundError } from "../../error/pithyError.js";
4
+ import { ANY_VERIFIED_CALLER } from "../scope/scope.js";
5
+ import { issuePresenceTicket, roomKind } from "../../presence/http/routes.js";
6
+ import { requireControlPlaneFor } from "./guard.js";
7
+ //#region src/controlPlane/http/presence.ts
8
+ /**
9
+ * `POST /control-plane/presence/tickets` — a ticket into any room this Worker composes, for a management
10
+ * client.
11
+ *
12
+ * **The scope is the room kind's, and the gate checks it.** Which scope a call needs is named in its body, so
13
+ * {@link presenceTicketRequirement} reads the kind from a copy of the body before the gate verifies, and the
14
+ * gate then verifies against that kind's scope exactly as it would against a route's own: one allowed row
15
+ * when it covers, one denial row naming the kind's scope when it does not, never both. Presence adds no scope
16
+ * of its own: a connection that may read a record may see who else has it open.
17
+ *
18
+ * A body that names no declared kind needs only a verified caller, so an unverified one is refused before any
19
+ * kind is looked at, and a verified one then gets the handler's 404 — the manifest lists every kind, so its
20
+ * existence is no secret.
21
+ */
22
+ function presenceTicketRequirement(deps) {
23
+ return async (c) => {
24
+ const kind = await bodyKind(c.req.raw);
25
+ const presence = kind === void 0 ? void 0 : deps.composedPresence().get(kind);
26
+ if (kind === void 0 || !presence) return ANY_VERIFIED_CALLER;
27
+ return roomKind(presence, kind).scope;
28
+ };
29
+ }
30
+ /** The gate the route wears: {@link requireControlPlaneFor} over the room kind's scope. */
31
+ function presenceTicketGate(deps) {
32
+ return requireControlPlaneFor(presenceTicketRequirement(deps));
33
+ }
34
+ /**
35
+ * The body's `kind`, read from a copy so the route's validator still reads the original. Only to choose a
36
+ * scope: the validator is what parses the body, and anything unreadable here is simply no kind.
37
+ */
38
+ async function bodyKind(request) {
39
+ try {
40
+ const body = await request.clone().json();
41
+ const kind = typeof body === "object" && body !== null ? body.kind : void 0;
42
+ return typeof kind === "string" ? kind : void 0;
43
+ } catch {
44
+ return;
45
+ }
46
+ }
47
+ /** The handler, behind {@link presenceTicketGate}: the kind's scope is already verified, so it mints. */
48
+ function presenceTicketHandler(deps) {
49
+ return async (c, body) => {
50
+ const presence = deps.composedPresence().get(body.kind);
51
+ if (!presence) throw new NotFoundError({
52
+ message: "That room kind does not exist.",
53
+ params: { kind: body.kind }
54
+ });
55
+ const room = roomKind(presence, body.kind);
56
+ const ticket = await issuePresenceTicket(c, presence, {
57
+ kind: room.kind,
58
+ recordId: body.recordId,
59
+ ref: body.participant.ref,
60
+ name: body.participant.name,
61
+ origin: "control-plane"
62
+ });
63
+ return c.json(ticket, 201);
64
+ };
65
+ }
66
+ //#endregion
67
+ export { presenceTicketGate, presenceTicketHandler, presenceTicketRequirement };
@@ -0,0 +1,73 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import type { Context } from "hono";
4
+ import type { PithyHonoEnv } from "../../capability/capability";
5
+ import { type ControlPlaneHandlerDeps } from "./handlers";
6
+ /**
7
+ * `GET /control-plane/processing` — the record of processing activities, GDPR Article 30. Each activity's purpose,
8
+ * classes, legal basis, recipients, retention and measures, and every gap named. Read-only.
9
+ */
10
+ export declare function processingHandler(deps: ControlPlaneHandlerDeps): (c: Context<PithyHonoEnv>) => Promise<Response & import("hono").TypedResponse<{
11
+ environment: string;
12
+ generatedAt: string;
13
+ version: string | null;
14
+ activities: {
15
+ id: string;
16
+ purpose: string;
17
+ declaredBy: string;
18
+ classes: string[];
19
+ legalBasis: "consent" | "contract" | "legal-obligation" | "legitimate-interests" | "public-task" | "vital-interests" | null;
20
+ basisSource: "capability" | "config" | null;
21
+ consent: {
22
+ purpose: string;
23
+ noticeVersion: number | null;
24
+ explicit: boolean | null;
25
+ grants: number | null;
26
+ withdrawals: number | null;
27
+ standing: number | null;
28
+ } | null;
29
+ recipients: {
30
+ name: string;
31
+ receives: string;
32
+ classes: string[];
33
+ source: "binding" | "declared" | "platform";
34
+ }[];
35
+ retention: {
36
+ classAges: {
37
+ class: string;
38
+ days: number;
39
+ }[];
40
+ purgeWindows: {
41
+ subject: "organization" | "user";
42
+ days: number;
43
+ source: "capability" | "floor" | "policy";
44
+ }[];
45
+ } | null;
46
+ measures: ("audit-logging" | "change-history" | "csrf" | "data-protection" | "key-rotation" | "management-access" | "route-verification")[];
47
+ gaps: {
48
+ kind: "class-not-stored" | "class-unclaimed" | "no-consent-purpose" | "no-legal-basis" | "no-standing-grant" | "phi-not-covered";
49
+ subject: string;
50
+ detail: string;
51
+ }[];
52
+ }[];
53
+ recipients: {
54
+ name: string;
55
+ receives: string;
56
+ classes: string[];
57
+ source: "binding" | "declared" | "platform";
58
+ }[];
59
+ measures: {
60
+ control: "audit-logging" | "change-history" | "csrf" | "data-protection" | "key-rotation" | "management-access" | "route-verification";
61
+ title: string;
62
+ soc2: string[];
63
+ iso27001: string[];
64
+ state: "evidenced" | "gap" | "not-derivable" | null;
65
+ }[];
66
+ gaps: {
67
+ kind: "class-not-stored" | "class-unclaimed" | "no-consent-purpose" | "no-legal-basis" | "no-standing-grant" | "phi-not-covered";
68
+ subject: string;
69
+ detail: string;
70
+ }[];
71
+ notDerivable: string[];
72
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
73
+ //# sourceMappingURL=processing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processing.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/processing.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE,OAAO,EAAE,KAAK,uBAAuB,EAAU,MAAM,YAAY,CAAC;AAGlE;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,uBAAuB,OAC5C,OAAO,CAAC,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEAIvC"}
@@ -0,0 +1,17 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { caller } from "./handlers.js";
4
+ import { readProcessingRecord } from "../processing/read.js";
5
+ //#region src/controlPlane/http/processing.ts
6
+ /**
7
+ * `GET /control-plane/processing` — the record of processing activities, GDPR Article 30. Each activity's purpose,
8
+ * classes, legal basis, recipients, retention and measures, and every gap named. Read-only.
9
+ */
10
+ function processingHandler(deps) {
11
+ return async (c) => {
12
+ const context = caller(c);
13
+ return c.json(await readProcessingRecord(c, deps, context));
14
+ };
15
+ }
16
+ //#endregion
17
+ export { processingHandler };