@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,173 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { ControlPlaneKeyConflictError } from "../error/errors.js";
4
+ import { JsonDate } from "../../data/codecs.js";
5
+ import { z } from "zod";
6
+ //#region src/controlPlane/data/oidcTrust.ts
7
+ /**
8
+ * An OIDC trust: the second credential kind a connection may hold, beside a registered key
9
+ * (`docs/AGENT-ACCESS.md` §6.2, #722).
10
+ *
11
+ * A key is a bearer: one client holds the private half. A trust is a **policy**: a trusted issuer, the
12
+ * audience its tokens must name, and a matcher over the claims that say which workload a token was minted
13
+ * for. Nobody holds a secret. The workload asks its own identity provider for a short-lived token, and the
14
+ * Worker checks it against the issuer's published keys with the verifier the webhooks already use,
15
+ * `core/src/http/oidcWebhook.ts`.
16
+ *
17
+ * ## The claims become data here, and that is a deliberate departure
18
+ *
19
+ * In a webhook the claims check is a predicate the **route** holds, because whoever wrote the route knows
20
+ * the legitimate sender. A connection's trust is per adopter, decided at registration by the same person who
21
+ * grants the scopes, so the matcher is stored with the trust and validated on the way in. That is the whole
22
+ * reason {@link OidcClaimMatch} exists rather than a function.
23
+ *
24
+ * ## The claims check is the boundary, not the signature
25
+ *
26
+ * An identity provider signs for everybody with the same keys. GitHub signs a token for every repository on
27
+ * the planet. A trust whose matcher constrains nothing accepts all of them, so {@link OidcClaimMatch} refuses
28
+ * one at registration — structurally, not as a warning — and refuses the claims that name the token rather
29
+ * than the workload ({@link RESERVED_OIDC_CLAIMS}), since a matcher made of those constrains nothing either.
30
+ *
31
+ * ## Named claims, not the `sub` string
32
+ *
33
+ * A `sub` is a concatenation whose composition belongs to the provider and to the adopter's own template.
34
+ * The claims beneath it — GitHub's `repository_id`, `environment`, `ref`; GitLab's `project_id` — are
35
+ * published individually and are stable. So the matcher is a map of claim names to values, and `sub` is one
36
+ * claim among the others rather than a special case.
37
+ *
38
+ * ## No rotation, and revocation changes shape
39
+ *
40
+ * There is no key to append, prove and expire. A token cannot be revoked; the trust is, and every token
41
+ * already minted stays live until it expires — {@link TRUST_REVOCATION_LATENCY} is the sentence that says
42
+ * so at the moment it matters.
43
+ *
44
+ * Nothing in this module reads a clock, a binding or D1. `now` is injected wherever time matters.
45
+ */
46
+ /**
47
+ * Claims that name the token rather than the workload: who minted it, for whom, and when. A matcher built
48
+ * from these alone would accept every workload the issuer serves, so none of them may be registered.
49
+ * `iss` and `aud` are checked anyway, by the trust's own issuer and audience.
50
+ */
51
+ const RESERVED_OIDC_CLAIMS = [
52
+ "iss",
53
+ "aud",
54
+ "exp",
55
+ "nbf",
56
+ "iat",
57
+ "jti"
58
+ ];
59
+ /** The most claims one trust may match on. Far above any real constraint; a bound on a stored row. */
60
+ const MAX_TRUST_CLAIMS = 16;
61
+ /** The most claims a refusal records, so a token carrying a hundred cannot fill the audit trail. */
62
+ const MAX_OBSERVED_CLAIMS = 32;
63
+ /** The longest claim value a matcher stores or a refusal records. */
64
+ const MAX_CLAIM_VALUE = 256;
65
+ /** A claim name: the plain alphabet providers use, plus `.`, `:` and `-` for a customized template. */
66
+ const CLAIM_NAME = /^[A-Za-z0-9_.:-]{1,64}$/;
67
+ /** Every C0 and C1 control, the line separators, and the bidi controls: a value is one line of plain text. */
68
+ const UNRENDERABLE = /[\p{Cc}\p{Bidi_Control}\u2028\u2029]/u;
69
+ const reserved = new Set(RESERVED_OIDC_CLAIMS);
70
+ /**
71
+ * One claim name in a matcher. A name, not a path: nested claims are not matched, because a matcher that
72
+ * walks a structure is a matcher with more ways to be wrong on the check the whole trust rests on.
73
+ */
74
+ const OidcClaimName = z.string().regex(CLAIM_NAME, "A claim name is letters, digits, `_`, `.`, `:` or `-`, at most 64.").refine((name) => !reserved.has(name), { message: `${RESERVED_OIDC_CLAIMS.join(", ")} name the token, not the workload, so they cannot constrain a trust.` }).describe("A claim the token must carry, by name — `repository_id`, `environment`, `project_id`, `sub`. Never one of the claims that name the token itself.");
75
+ /** One claim value in a matcher: compared as a string against the token's claim of the same name. */
76
+ const OidcClaimValue = z.string().min(1, "A claim value cannot be empty.").max(256, `A claim value is 256 characters at most.`).refine((value) => !UNRENDERABLE.test(value), "A claim value is one line of plain text.").describe("The exact value that claim must have. A numeric or boolean claim is compared by its string form, so `1262274726` matches a `repository_id` whichever way the provider typed it.");
77
+ /**
78
+ * Which workloads a trust accepts: every named claim must equal its value.
79
+ *
80
+ * **At least one, and that is the refusal the whole credential kind rests on.** An issuer with no claim
81
+ * constraint accepts every workload it serves.
82
+ */
83
+ const OidcClaimMatch = z.record(OidcClaimName, OidcClaimValue).refine((claims) => Object.keys(claims).length > 0, { message: "A trust needs at least one claim constraint. An issuer alone accepts every workload it serves." }).refine((claims) => Object.keys(claims).length <= 16, { message: `A trust matches on 16 claims at most.` }).describe("The subject constraint: every named claim must equal its value. At least one, because an issuer alone accepts every workload it serves.");
84
+ /** An https URL. A trust's issuer and key endpoint are fetched from, so plain http is refused. */
85
+ const HttpsUrl = z.url({ protocol: /^https$/ });
86
+ /**
87
+ * One registered OIDC trust, an element of the connection's `trusts` column.
88
+ *
89
+ * Stored beside `keys` rather than inside it: the two kinds share nothing but the connection they grant
90
+ * through, and a union array would make every key reader learn about trusts.
91
+ */
92
+ const OidcTrust = z.object({
93
+ trustId: z.string().min(1).max(64).describe("The trust's id, named by a call on the `pithy-control-plane-trust` header the way a token's `kid` names a key. Not a secret."),
94
+ issuer: HttpsUrl.describe("The exact `iss` this trust accepts — `https://token.actions.githubusercontent.com`, `https://gitlab.com`. A token from any other issuer is refused before its claims are read."),
95
+ jwksUrl: HttpsUrl.describe("Where the issuer publishes the keys that sign its tokens, read from its discovery document at registration. Public, so configuration and not a secret."),
96
+ audience: z.string().min(1).max(512).describe("The `aud` a token must name. Defaults to this environment's own Worker origin, which is what stops a staging token being replayed against production."),
97
+ claims: OidcClaimMatch,
98
+ authorizedBy: z.email().max(254).describe("Who sanctioned this trust: the signed-in session's email at registration. Never who may use it — a trust's users are whoever its claims admit."),
99
+ validFrom: JsonDate.describe("When the trust was registered and began to be honored."),
100
+ revokedAt: JsonDate.nullable().describe("When the trust was revoked, or null. Takes effect on the next call; a token already minted is refused from then on, but stays in its holder's hands until it expires."),
101
+ firstCallAt: JsonDate.nullable().describe("When a call first verified under this trust, or null while it is awaiting a first call. Nothing can prove a trust at registration — there is no private key here and no workload present — so this is the only proof there is.")
102
+ }).describe("One OIDC trust: a trusted issuer, the audience its tokens must name, and the claims that say which workloads it admits.");
103
+ /**
104
+ * What a caller should expect after a trust is revoked, said at the moment it is revoked rather than
105
+ * discovered afterwards.
106
+ */
107
+ const TRUST_REVOCATION_LATENCY = "A token cannot be revoked, only the trust. Every call naming this trust is refused from now on, but a token already minted stays in its holder's hands until it expires — the issuer's own lifetime, typically minutes.";
108
+ /** Every trust that may verify a call at `now`: not revoked, and started. */
109
+ function activeTrusts(trusts, now) {
110
+ return trusts.filter((trust) => trust.revokedAt === null && trust.validFrom.getTime() <= now.getTime());
111
+ }
112
+ /** The trust a call names, if it is live at `now`, or null. The revocation check lives here so no caller forgets it. */
113
+ function findVerifyingTrust(trusts, trustId, now) {
114
+ return activeTrusts(trusts, now).find((trust) => trust.trustId === trustId) ?? null;
115
+ }
116
+ /** Register a trust beside the others. A duplicate id is refused: the id is what a call addresses. */
117
+ function appendTrust(trusts, trust) {
118
+ if (trusts.some((existing) => existing.trustId === trust.trustId)) throw new ControlPlaneKeyConflictError({
119
+ message: "That trust id is already registered on this connection.",
120
+ action: "Register the trust under a new id.",
121
+ detail: `duplicate trustId ${trust.trustId}`
122
+ });
123
+ return [...trusts, trust];
124
+ }
125
+ /**
126
+ * Revoke one trust at `now`, or answer null when no trust answers to that id. A trust already revoked keeps
127
+ * the instant it was first revoked: the window a call was refused under must not move.
128
+ */
129
+ function revokeTrust(trusts, trustId, now) {
130
+ if (!trusts.some((trust) => trust.trustId === trustId)) return null;
131
+ return trusts.map((trust) => trust.trustId === trustId && trust.revokedAt === null ? {
132
+ ...trust,
133
+ revokedAt: now
134
+ } : trust);
135
+ }
136
+ /** A claim's string form, or undefined for a value that is not a string, number or boolean. */
137
+ function claimString(value) {
138
+ if (typeof value === "string") return value;
139
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
140
+ if (typeof value === "boolean") return String(value);
141
+ }
142
+ /**
143
+ * Whether a token's claims satisfy a trust's matcher: every registered claim present and equal.
144
+ *
145
+ * An empty matcher matches nothing. Registration refuses one, and this refuses it again rather than letting
146
+ * a hand-edited row vacuously admit every workload.
147
+ */
148
+ function claimsMatch(match, claims) {
149
+ const entries = Object.entries(match);
150
+ if (entries.length === 0) return false;
151
+ return entries.every(([name, expected]) => claimString(claims[name]) === expected);
152
+ }
153
+ /**
154
+ * The claims a refused token carried, as a refusal records them: the workload's claims, as strings, capped.
155
+ *
156
+ * This is what makes a custom issuer workable and a profiled one self-correcting — register, let the
157
+ * workload run once, read what it actually sent. Only ever called once the signature, issuer and audience
158
+ * have verified, so the caller demonstrably holds a genuine token for this audience and naming its claims
159
+ * leaks nothing it does not already hold.
160
+ */
161
+ function observedClaims(claims) {
162
+ const recorded = {};
163
+ for (const [name, value] of Object.entries(claims)) {
164
+ if (Object.keys(recorded).length >= 32) break;
165
+ if (reserved.has(name) || !CLAIM_NAME.test(name)) continue;
166
+ const text = claimString(value);
167
+ if (text === void 0) continue;
168
+ recorded[name] = text.slice(0, 256);
169
+ }
170
+ return recorded;
171
+ }
172
+ //#endregion
173
+ export { MAX_CLAIM_VALUE, MAX_OBSERVED_CLAIMS, MAX_TRUST_CLAIMS, OidcClaimMatch, OidcClaimName, OidcClaimValue, OidcTrust, RESERVED_OIDC_CLAIMS, TRUST_REVOCATION_LATENCY, activeTrusts, appendTrust, claimsMatch, findVerifyingTrust, observedClaims, revokeTrust };
@@ -5,6 +5,7 @@ import type { Kysely } from "kysely";
5
5
  import type { z } from "zod";
6
6
  import { type DatabaseSchema } from "../../data/db";
7
7
  import { ControlPlaneConnection } from "./connection";
8
+ import { LegalHold } from "./hold";
8
9
  import { ControlPlaneReplay } from "./replay";
9
10
  /**
10
11
  * The connections table. `CamelCasePlugin` snake-cases it to `pithy_controlplane_connections` — the
@@ -19,6 +20,8 @@ export declare const CONTROL_PLANE_CONNECTIONS_TABLE = "pithyControlplaneConnect
19
20
  * makes the claim a primary-key insert and therefore strongly consistent. See `../replay/guard.ts`.
20
21
  */
21
22
  export declare const CONTROL_PLANE_REPLAYS_TABLE = "pithyControlplaneReplays";
23
+ /** Legal holds, kept after release as the record that one stood. */
24
+ export declare const CONTROL_PLANE_HOLDS_TABLE = "pithyControlplaneHolds";
22
25
  /**
23
26
  * The control-plane tables map. Both are always present: a Worker that composes the seam and has never
24
27
  * been connected still needs somewhere for the answer "nobody is connected" to come from, and the
@@ -29,6 +32,7 @@ export declare function controlPlaneTables(): Record<string, z.ZodObject>;
29
32
  export type ControlPlaneTables = {
30
33
  [CONTROL_PLANE_CONNECTIONS_TABLE]: typeof ControlPlaneConnection;
31
34
  [CONTROL_PLANE_REPLAYS_TABLE]: typeof ControlPlaneReplay;
35
+ [CONTROL_PLANE_HOLDS_TABLE]: typeof LegalHold;
32
36
  };
33
37
  export type ControlPlaneDatabase = Kysely<DatabaseSchema<ControlPlaneTables>>;
34
38
  /** Build the control-plane database from the `DB` binding (CamelCasePlugin installed). */
@@ -1 +1 @@
1
- {"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/data/tables.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE9C;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,iCAAiC,CAAC;AAE9E;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,6BAA6B,CAAC;AAEtE;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAKhE;AAED,+DAA+D;AAC/D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,+BAA+B,CAAC,EAAE,OAAO,sBAAsB,CAAC;IACjE,CAAC,2BAA2B,CAAC,EAAE,OAAO,kBAAkB,CAAC;CAC1D,CAAC;AACF,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAE9E,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,UAAU,GAAG,oBAAoB,CAKzE"}
1
+ {"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/data/tables.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE9C;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,iCAAiC,CAAC;AAE9E;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,6BAA6B,CAAC;AAEtE,oEAAoE;AACpE,eAAO,MAAM,yBAAyB,2BAA2B,CAAC;AAElE;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAMhE;AAED,+DAA+D;AAC/D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,+BAA+B,CAAC,EAAE,OAAO,sBAAsB,CAAC;IACjE,CAAC,2BAA2B,CAAC,EAAE,OAAO,kBAAkB,CAAC;IACzD,CAAC,yBAAyB,CAAC,EAAE,OAAO,SAAS,CAAC;CAC/C,CAAC;AACF,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAE9E,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,UAAU,GAAG,oBAAoB,CAMzE"}
@@ -1,7 +1,8 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
- import { ControlPlaneConnection } from "./connection.js";
3
+ import { LegalHold } from "./hold.js";
4
4
  import { createDatabase } from "../../data/db.js";
5
+ import { ControlPlaneConnection } from "./connection.js";
5
6
  import { ControlPlaneReplay } from "./replay.js";
6
7
  //#region src/controlPlane/data/tables.ts
7
8
  /**
@@ -17,6 +18,8 @@ const CONTROL_PLANE_CONNECTIONS_TABLE = "pithyControlplaneConnections";
17
18
  * makes the claim a primary-key insert and therefore strongly consistent. See `../replay/guard.ts`.
18
19
  */
19
20
  const CONTROL_PLANE_REPLAYS_TABLE = "pithyControlplaneReplays";
21
+ /** Legal holds, kept after release as the record that one stood. */
22
+ const CONTROL_PLANE_HOLDS_TABLE = "pithyControlplaneHolds";
20
23
  /**
21
24
  * The control-plane tables map. Both are always present: a Worker that composes the seam and has never
22
25
  * been connected still needs somewhere for the answer "nobody is connected" to come from, and the
@@ -25,15 +28,17 @@ const CONTROL_PLANE_REPLAYS_TABLE = "pithyControlplaneReplays";
25
28
  function controlPlaneTables() {
26
29
  return {
27
30
  [CONTROL_PLANE_CONNECTIONS_TABLE]: ControlPlaneConnection,
28
- [CONTROL_PLANE_REPLAYS_TABLE]: ControlPlaneReplay
31
+ [CONTROL_PLANE_REPLAYS_TABLE]: ControlPlaneReplay,
32
+ [CONTROL_PLANE_HOLDS_TABLE]: LegalHold
29
33
  };
30
34
  }
31
35
  /** Build the control-plane database from the `DB` binding (CamelCasePlugin installed). */
32
36
  function controlPlaneDatabase(d1) {
33
37
  return createDatabase(d1, {
34
38
  [CONTROL_PLANE_CONNECTIONS_TABLE]: ControlPlaneConnection,
35
- [CONTROL_PLANE_REPLAYS_TABLE]: ControlPlaneReplay
39
+ [CONTROL_PLANE_REPLAYS_TABLE]: ControlPlaneReplay,
40
+ [CONTROL_PLANE_HOLDS_TABLE]: LegalHold
36
41
  });
37
42
  }
38
43
  //#endregion
39
- export { CONTROL_PLANE_CONNECTIONS_TABLE, CONTROL_PLANE_REPLAYS_TABLE, controlPlaneDatabase, controlPlaneTables };
44
+ export { CONTROL_PLANE_CONNECTIONS_TABLE, CONTROL_PLANE_HOLDS_TABLE, CONTROL_PLANE_REPLAYS_TABLE, controlPlaneDatabase, controlPlaneTables };
@@ -0,0 +1,16 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { type ControlPlaneDatabase } from "./tables";
4
+ /**
5
+ * Record the first call a trust answered (#722), so a listing stops saying *awaiting a first call*.
6
+ *
7
+ * **One statement that touches one field, never a read-modify-write of the column.** The verifier read the row
8
+ * moments ago, and an operator may have revoked the trust since. Writing back the whole `trusts` array as the
9
+ * verifier saw it would resurrect that trust — a revocation undone by the very call it was meant to stop. So the
10
+ * write is `json_set` on the matching element's `firstCallAt` alone, and only while that element is still
11
+ * unrevoked and still uncalled: a revoked trust is left exactly as revoked, and a second first call changes nothing.
12
+ *
13
+ * The instant is written as ISO-8601, the shape `JsonDate` stores inside the column.
14
+ */
15
+ export declare function recordTrustFirstCall(db: ControlPlaneDatabase, connectionId: string, trustId: string, at: Date): Promise<void>;
16
+ //# sourceMappingURL=trustFirstCall.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trustFirstCall.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/data/trustFirstCall.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmC,KAAK,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAEtF;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,oBAAoB,EACxB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,IAAI,GACP,OAAO,CAAC,IAAI,CAAC,CAcf"}
@@ -0,0 +1,25 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { CONTROL_PLANE_CONNECTIONS_TABLE } from "./tables.js";
4
+ import { sql } from "kysely";
5
+ //#region src/controlPlane/data/trustFirstCall.ts
6
+ /**
7
+ * Record the first call a trust answered (#722), so a listing stops saying *awaiting a first call*.
8
+ *
9
+ * **One statement that touches one field, never a read-modify-write of the column.** The verifier read the row
10
+ * moments ago, and an operator may have revoked the trust since. Writing back the whole `trusts` array as the
11
+ * verifier saw it would resurrect that trust — a revocation undone by the very call it was meant to stop. So the
12
+ * write is `json_set` on the matching element's `firstCallAt` alone, and only while that element is still
13
+ * unrevoked and still uncalled: a revoked trust is left exactly as revoked, and a second first call changes nothing.
14
+ *
15
+ * The instant is written as ISO-8601, the shape `JsonDate` stores inside the column.
16
+ */
17
+ async function recordTrustFirstCall(db, connectionId, trustId, at) {
18
+ const trusts = sql.ref("trusts");
19
+ const uncalled = (alias) => sql`json_extract(${sql.ref(`${alias}.value`)}, '$.trustId') = ${trustId}
20
+ and json_extract(${sql.ref(`${alias}.value`)}, '$.revokedAt') is null
21
+ and json_extract(${sql.ref(`${alias}.value`)}, '$.firstCallAt') is null`;
22
+ await db.updateTable(CONTROL_PLANE_CONNECTIONS_TABLE).set({ trusts: sql`json_set(${trusts}, '$[' || (select ${sql.ref("t.key")} from json_each(${trusts}) as t where ${uncalled("t")} limit 1) || '].firstCallAt', ${at.toISOString()})` }).where("id", "=", connectionId).where(sql`exists (select 1 from json_each(${trusts}) as u where ${uncalled("u")})`).execute();
23
+ }
24
+ //#endregion
25
+ export { recordTrustFirstCall };
@@ -1,6 +1,8 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
3
  import { z } from "zod";
4
+ import { ScopeKind } from "../scope/kind";
5
+ import { ControlPlaneScope } from "../scope/scope";
4
6
  /**
5
7
  * What a capability tells a management client about its own admin surface.
6
8
  *
@@ -28,6 +30,24 @@ export declare const AdminRouteMethod: z.ZodEnum<{
28
30
  PUT: "PUT";
29
31
  }>;
30
32
  export type AdminRouteMethod = z.infer<typeof AdminRouteMethod>;
33
+ /**
34
+ * An admin route's operation id (`docs/AGENT-ACCESS.md` §5): lowercase words joined by `.`, `_` or `-`.
35
+ *
36
+ * **Permanent once published.** An agent names a tool in prompts, saved workflows and its own record of what
37
+ * worked, so a renamed operation breaks callers silently — the same class of rule as a role name. Unique within
38
+ * its capability; `packages/cli/src/ci/adminOperations.test.ts` holds every kit capability's to a table.
39
+ */
40
+ export declare const AdminOperation: z.ZodString;
41
+ export type AdminOperation = z.infer<typeof AdminOperation>;
42
+ /**
43
+ * An admin route's input as JSON Schema: an object whose `path`, `query` and `body` properties are each
44
+ * the JSON Schema of the validator the route runs on that part of the request.
45
+ *
46
+ * A record rather than a modeled schema, because it is JSON Schema — a vocabulary this manifest relays, never
47
+ * one it defines — and an MCP client publishes it verbatim as a tool's `inputSchema`.
48
+ */
49
+ export declare const AdminRouteInput: z.ZodRecord<z.ZodString, z.ZodUnknown>;
50
+ export type AdminRouteInput = z.infer<typeof AdminRouteInput>;
31
51
  /** One admin route a capability contributes behind the `control-plane` strategy. */
32
52
  export declare const AdminRoute: z.ZodObject<{
33
53
  method: z.ZodEnum<{
@@ -40,8 +60,29 @@ export declare const AdminRoute: z.ZodObject<{
40
60
  path: z.ZodString;
41
61
  scope: z.ZodNullable<z.ZodString>;
42
62
  summary: z.ZodString;
63
+ kind: z.ZodOptional<z.ZodEnum<{
64
+ charges: "charges";
65
+ credentials: "credentials";
66
+ deletes: "deletes";
67
+ reads: "reads";
68
+ sends: "sends";
69
+ writes: "writes";
70
+ }>>;
71
+ operation: z.ZodOptional<z.ZodString>;
72
+ input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
43
73
  }, z.core.$strip>;
44
74
  export type AdminRoute = z.infer<typeof AdminRoute>;
75
+ /**
76
+ * An admin route as a capability declares it: a scoped route states its kind, and a route with no scope has none.
77
+ * `Capability.adminRoutes` takes this, so a scoped route without a kind does not compile.
78
+ */
79
+ export type AdminRouteDeclaration = Omit<AdminRoute, "scope" | "kind"> & ({
80
+ scope: ControlPlaneScope;
81
+ kind: ScopeKind;
82
+ } | {
83
+ scope: null;
84
+ kind?: undefined;
85
+ });
45
86
  /**
46
87
  * One composed capability's declaration — everything about it that is the same for every caller.
47
88
  *
@@ -64,6 +105,16 @@ export declare const CapabilityDeclaration: z.ZodObject<{
64
105
  path: z.ZodString;
65
106
  scope: z.ZodNullable<z.ZodString>;
66
107
  summary: z.ZodString;
108
+ kind: z.ZodOptional<z.ZodEnum<{
109
+ charges: "charges";
110
+ credentials: "credentials";
111
+ deletes: "deletes";
112
+ reads: "reads";
113
+ sends: "sends";
114
+ writes: "writes";
115
+ }>>;
116
+ operation: z.ZodOptional<z.ZodString>;
117
+ input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
67
118
  }, z.core.$strip>>;
68
119
  healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
69
120
  key: z.ZodString;
@@ -89,6 +140,14 @@ export declare const CapabilityDeclaration: z.ZodObject<{
89
140
  summary: z.ZodString;
90
141
  }, z.core.$strip>>>;
91
142
  config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
143
+ presenceRooms: z.ZodOptional<z.ZodArray<z.ZodObject<{
144
+ kind: z.ZodString;
145
+ scope: z.ZodString;
146
+ activities: z.ZodArray<z.ZodString>;
147
+ maxParticipants: z.ZodNumber;
148
+ sessionTicketPath: z.ZodNullable<z.ZodString>;
149
+ socketPath: z.ZodString;
150
+ }, z.core.$strip>>>;
92
151
  }, z.core.$strip>;
93
152
  export type CapabilityDeclaration = z.infer<typeof CapabilityDeclaration>;
94
153
  export declare const CapabilityDescriptor: z.ZodCodec<z.ZodObject<{
@@ -106,6 +165,16 @@ export declare const CapabilityDescriptor: z.ZodCodec<z.ZodObject<{
106
165
  path: z.ZodString;
107
166
  scope: z.ZodNullable<z.ZodString>;
108
167
  summary: z.ZodString;
168
+ kind: z.ZodOptional<z.ZodEnum<{
169
+ charges: "charges";
170
+ credentials: "credentials";
171
+ deletes: "deletes";
172
+ reads: "reads";
173
+ sends: "sends";
174
+ writes: "writes";
175
+ }>>;
176
+ operation: z.ZodOptional<z.ZodString>;
177
+ input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
109
178
  }, z.core.$strip>>;
110
179
  healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
111
180
  key: z.ZodString;
@@ -131,6 +200,14 @@ export declare const CapabilityDescriptor: z.ZodCodec<z.ZodObject<{
131
200
  summary: z.ZodString;
132
201
  }, z.core.$strip>>>;
133
202
  config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
203
+ presenceRooms: z.ZodOptional<z.ZodArray<z.ZodObject<{
204
+ kind: z.ZodString;
205
+ scope: z.ZodString;
206
+ activities: z.ZodArray<z.ZodString>;
207
+ maxParticipants: z.ZodNumber;
208
+ sessionTicketPath: z.ZodNullable<z.ZodString>;
209
+ socketPath: z.ZodString;
210
+ }, z.core.$strip>>>;
134
211
  health: z.ZodDefault<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>>;
135
212
  healthUnavailable: z.ZodDefault<z.ZodBoolean>;
136
213
  }, z.core.$strip>, z.ZodObject<{
@@ -148,6 +225,16 @@ export declare const CapabilityDescriptor: z.ZodCodec<z.ZodObject<{
148
225
  path: z.ZodString;
149
226
  scope: z.ZodNullable<z.ZodString>;
150
227
  summary: z.ZodString;
228
+ kind: z.ZodOptional<z.ZodEnum<{
229
+ charges: "charges";
230
+ credentials: "credentials";
231
+ deletes: "deletes";
232
+ reads: "reads";
233
+ sends: "sends";
234
+ writes: "writes";
235
+ }>>;
236
+ operation: z.ZodOptional<z.ZodString>;
237
+ input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
151
238
  }, z.core.$strip>>;
152
239
  healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
153
240
  key: z.ZodString;
@@ -173,6 +260,14 @@ export declare const CapabilityDescriptor: z.ZodCodec<z.ZodObject<{
173
260
  summary: z.ZodString;
174
261
  }, z.core.$strip>>>;
175
262
  config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
263
+ presenceRooms: z.ZodOptional<z.ZodArray<z.ZodObject<{
264
+ kind: z.ZodString;
265
+ scope: z.ZodString;
266
+ activities: z.ZodArray<z.ZodString>;
267
+ maxParticipants: z.ZodNumber;
268
+ sessionTicketPath: z.ZodNullable<z.ZodString>;
269
+ socketPath: z.ZodString;
270
+ }, z.core.$strip>>>;
176
271
  health: z.ZodDiscriminatedUnion<[z.ZodObject<{
177
272
  state: z.ZodLiteral<"undeclared">;
178
273
  }, z.core.$strip>, z.ZodObject<{
@@ -193,7 +288,7 @@ export type CapabilityDescriptor = z.infer<typeof CapabilityDescriptor>;
193
288
  * now — so a capability that changed its paths or its scopes reports the change directly, and a schema
194
289
  * version would be a second source of truth to keep in sync with the first. That reasoning is unchanged.
195
290
  *
196
- * **And `capabilities[].version` travels with the package it belongs to** (#626). A version is only
291
+ * **And `capabilities[].version` travels with the package it belongs to**. A version is only
197
292
  * actionable joined against a release feed, a feed is keyed by package name, and a capability name is
198
293
  * not one — `controlplane` ships inside `@pithy-sh/core`. Reporting the version alone left every client
199
294
  * guessing the key, and the guess failed silently on the most frequently released package there is.
@@ -207,7 +302,7 @@ export type CapabilityDescriptor = z.infer<typeof CapabilityDescriptor>;
207
302
  * we just fixed", and "does this project predate the capability a pane needs". Reporting only one leaves
208
303
  * half the questions unanswerable, and they are the halves people actually ask.
209
304
  *
210
- * **And each entry carries a third thing: the configured facts that capability states** (#422). Knowing
305
+ * **And each entry carries a third thing: the configured facts that capability states**. Knowing
211
306
  * where a route is and which scope it needs is not always enough to call it — `POST
212
307
  * {base}/entitlements/grant` names a holder, and whether this project's holders are people or
213
308
  * organizations is a decision the adopter made in config. A client that cannot read the decision guesses
@@ -247,6 +342,38 @@ export declare const ControlPlaneManifest: z.ZodObject<{
247
342
  liveVersions: z.ZodNumber;
248
343
  }, z.core.$strip>>;
249
344
  }, z.core.$strip>>;
345
+ retention: z.ZodOptional<z.ZodObject<{
346
+ purgeWindows: z.ZodArray<z.ZodObject<{
347
+ subject: z.ZodEnum<{
348
+ organization: "organization";
349
+ user: "user";
350
+ }>;
351
+ days: z.ZodNumber;
352
+ source: z.ZodEnum<{
353
+ capability: "capability";
354
+ floor: "floor";
355
+ policy: "policy";
356
+ }>;
357
+ }, z.core.$strip>>;
358
+ audit: z.ZodObject<{
359
+ defaultDays: z.ZodNullable<z.ZodNumber>;
360
+ floorDays: z.ZodNumber;
361
+ rules: z.ZodArray<z.ZodObject<{
362
+ prefix: z.ZodString;
363
+ days: z.ZodNumber;
364
+ source: z.ZodEnum<{
365
+ capability: "capability";
366
+ floor: "floor";
367
+ policy: "policy";
368
+ }>;
369
+ }, z.core.$strip>>;
370
+ floored: z.ZodArray<z.ZodString>;
371
+ }, z.core.$strip>;
372
+ classAges: z.ZodArray<z.ZodObject<{
373
+ class: z.ZodString;
374
+ days: z.ZodNumber;
375
+ }, z.core.$strip>>;
376
+ }, z.core.$strip>>;
250
377
  capabilities: z.ZodArray<z.ZodCodec<z.ZodObject<{
251
378
  name: z.ZodString;
252
379
  version: z.ZodNullable<z.ZodString>;
@@ -262,6 +389,16 @@ export declare const ControlPlaneManifest: z.ZodObject<{
262
389
  path: z.ZodString;
263
390
  scope: z.ZodNullable<z.ZodString>;
264
391
  summary: z.ZodString;
392
+ kind: z.ZodOptional<z.ZodEnum<{
393
+ charges: "charges";
394
+ credentials: "credentials";
395
+ deletes: "deletes";
396
+ reads: "reads";
397
+ sends: "sends";
398
+ writes: "writes";
399
+ }>>;
400
+ operation: z.ZodOptional<z.ZodString>;
401
+ input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
265
402
  }, z.core.$strip>>;
266
403
  healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
267
404
  key: z.ZodString;
@@ -287,6 +424,14 @@ export declare const ControlPlaneManifest: z.ZodObject<{
287
424
  summary: z.ZodString;
288
425
  }, z.core.$strip>>>;
289
426
  config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
427
+ presenceRooms: z.ZodOptional<z.ZodArray<z.ZodObject<{
428
+ kind: z.ZodString;
429
+ scope: z.ZodString;
430
+ activities: z.ZodArray<z.ZodString>;
431
+ maxParticipants: z.ZodNumber;
432
+ sessionTicketPath: z.ZodNullable<z.ZodString>;
433
+ socketPath: z.ZodString;
434
+ }, z.core.$strip>>>;
290
435
  health: z.ZodDefault<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>>;
291
436
  healthUnavailable: z.ZodDefault<z.ZodBoolean>;
292
437
  }, z.core.$strip>, z.ZodObject<{
@@ -304,6 +449,16 @@ export declare const ControlPlaneManifest: z.ZodObject<{
304
449
  path: z.ZodString;
305
450
  scope: z.ZodNullable<z.ZodString>;
306
451
  summary: z.ZodString;
452
+ kind: z.ZodOptional<z.ZodEnum<{
453
+ charges: "charges";
454
+ credentials: "credentials";
455
+ deletes: "deletes";
456
+ reads: "reads";
457
+ sends: "sends";
458
+ writes: "writes";
459
+ }>>;
460
+ operation: z.ZodOptional<z.ZodString>;
461
+ input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
307
462
  }, z.core.$strip>>;
308
463
  healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
309
464
  key: z.ZodString;
@@ -329,6 +484,14 @@ export declare const ControlPlaneManifest: z.ZodObject<{
329
484
  summary: z.ZodString;
330
485
  }, z.core.$strip>>>;
331
486
  config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
487
+ presenceRooms: z.ZodOptional<z.ZodArray<z.ZodObject<{
488
+ kind: z.ZodString;
489
+ scope: z.ZodString;
490
+ activities: z.ZodArray<z.ZodString>;
491
+ maxParticipants: z.ZodNumber;
492
+ sessionTicketPath: z.ZodNullable<z.ZodString>;
493
+ socketPath: z.ZodString;
494
+ }, z.core.$strip>>>;
332
495
  health: z.ZodDiscriminatedUnion<[z.ZodObject<{
333
496
  state: z.ZodLiteral<"undeclared">;
334
497
  }, z.core.$strip>, z.ZodObject<{
@@ -1 +1 @@
1
- {"version":3,"file":"adminRoute.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/discovery/adminRoute.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB;;;;;;;;;;;;;;;;;GAiBG;AAEH,+CAA+C;AAC/C,eAAO,MAAM,gBAAgB;;;;;;EAE8B,CAAC;AAC5D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE,oFAAoF;AACpF,eAAO,MAAM,UAAU;;;;;;;;;;;iBAmBpB,CAAC;AACJ,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqD/B,CAAC;AACJ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAiD1E,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAsC9B,CAAC;AACJ,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiCkE,CAAC;AACpG,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
1
+ {"version":3,"file":"adminRoute.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/discovery/adminRoute.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAInD;;;;;;;;;;;;;;;;;GAiBG;AAEH,+CAA+C;AAC/C,eAAO,MAAM,gBAAgB;;;;;;EAE8B,CAAC;AAC5D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,aAOgE,CAAC;AAC5F,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,wCAE+D,CAAC;AAC5F,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,oFAAoF;AACpF,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;iBA+BpB,CAAC;AACJ,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,CAAC,GACpE,CAAC;IAAE,KAAK,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC,CAAC;AAEtF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6D/B,CAAC;AACJ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAiD1E,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAsC9B,CAAC;AACJ,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoCkE,CAAC;AACpG,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC"}