@pithy-sh/core 0.10.0 → 0.12.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 (270) hide show
  1. package/dist/access/access.d.ts +172 -0
  2. package/dist/access/access.d.ts.map +1 -0
  3. package/dist/access/access.js +147 -0
  4. package/dist/access/acting.d.ts +49 -0
  5. package/dist/access/acting.d.ts.map +1 -0
  6. package/dist/access/acting.js +21 -0
  7. package/dist/access/policyCheck.d.ts +33 -0
  8. package/dist/access/policyCheck.d.ts.map +1 -0
  9. package/dist/access/policyCheck.js +48 -0
  10. package/dist/access/usage.d.ts +83 -0
  11. package/dist/access/usage.d.ts.map +1 -0
  12. package/dist/access/usage.js +104 -0
  13. package/dist/access/visibility.d.ts +66 -0
  14. package/dist/access/visibility.d.ts.map +1 -0
  15. package/dist/access/visibility.js +86 -0
  16. package/dist/audit/auditEvent.d.ts +5 -0
  17. package/dist/audit/auditEvent.d.ts.map +1 -1
  18. package/dist/audit/auditEvent.js +2 -0
  19. package/dist/audit/recorder.d.ts +10 -2
  20. package/dist/audit/recorder.d.ts.map +1 -1
  21. package/dist/capability/bindings.d.ts +47 -2
  22. package/dist/capability/bindings.d.ts.map +1 -1
  23. package/dist/capability/bindings.js +117 -7
  24. package/dist/capability/capability.d.ts +110 -28
  25. package/dist/capability/capability.d.ts.map +1 -1
  26. package/dist/capability/capability.js +2 -0
  27. package/dist/capability/manifest.d.ts +2 -1
  28. package/dist/capability/manifest.d.ts.map +1 -1
  29. package/dist/capability/manifest.js +1 -1
  30. package/dist/capability/purge.d.ts +80 -0
  31. package/dist/capability/purge.d.ts.map +1 -0
  32. package/dist/capability/purge.js +76 -0
  33. package/dist/capability/settings.d.ts +86 -2
  34. package/dist/capability/settings.d.ts.map +1 -1
  35. package/dist/capability/settings.js +80 -1
  36. package/dist/cli/commandCatalog.generated.d.ts +238 -24
  37. package/dist/cli/commandCatalog.generated.d.ts.map +1 -1
  38. package/dist/cli/commandCatalog.generated.js +251 -22
  39. package/dist/cli/commandFacts.d.ts +2 -1
  40. package/dist/cli/commandFacts.d.ts.map +1 -1
  41. package/dist/cli/commandFacts.js +2 -0
  42. package/dist/controlPlane/capability.d.ts.map +1 -1
  43. package/dist/controlPlane/capability.js +19 -2
  44. package/dist/controlPlane/context.d.ts +5 -0
  45. package/dist/controlPlane/context.d.ts.map +1 -1
  46. package/dist/controlPlane/context.js +3 -1
  47. package/dist/controlPlane/data/connection.d.ts +49 -12
  48. package/dist/controlPlane/data/connection.d.ts.map +1 -1
  49. package/dist/controlPlane/data/connection.js +56 -2
  50. package/dist/controlPlane/discovery/adminRoute.d.ts +29 -0
  51. package/dist/controlPlane/discovery/adminRoute.d.ts.map +1 -1
  52. package/dist/controlPlane/discovery/adminRoute.js +3 -0
  53. package/dist/controlPlane/error/errors.d.ts +4 -3
  54. package/dist/controlPlane/error/errors.d.ts.map +1 -1
  55. package/dist/controlPlane/http/cors.d.ts +4 -4
  56. package/dist/controlPlane/http/cors.js +4 -4
  57. package/dist/controlPlane/http/guard.d.ts +11 -0
  58. package/dist/controlPlane/http/guard.d.ts.map +1 -1
  59. package/dist/controlPlane/http/guard.js +17 -1
  60. package/dist/controlPlane/http/handlers.d.ts +139 -0
  61. package/dist/controlPlane/http/handlers.d.ts.map +1 -1
  62. package/dist/controlPlane/http/handlers.js +67 -4
  63. package/dist/controlPlane/http/readiness.d.ts +33 -0
  64. package/dist/controlPlane/http/readiness.d.ts.map +1 -0
  65. package/dist/controlPlane/http/readiness.js +39 -0
  66. package/dist/controlPlane/http/responses.d.ts +245 -0
  67. package/dist/controlPlane/http/responses.d.ts.map +1 -1
  68. package/dist/controlPlane/http/responses.js +101 -4
  69. package/dist/controlPlane/http/routes.d.ts +2 -0
  70. package/dist/controlPlane/http/routes.d.ts.map +1 -1
  71. package/dist/controlPlane/http/routes.js +31 -3
  72. package/dist/controlPlane/http/verify.d.ts.map +1 -1
  73. package/dist/controlPlane/http/verify.js +2 -1
  74. package/dist/controlPlane/migrationState/migrationState.d.ts +102 -0
  75. package/dist/controlPlane/migrationState/migrationState.d.ts.map +1 -0
  76. package/dist/controlPlane/migrationState/migrationState.js +142 -0
  77. package/dist/controlPlane/migrations/0003_connection_principal.d.ts +21 -0
  78. package/dist/controlPlane/migrations/0003_connection_principal.d.ts.map +1 -0
  79. package/dist/controlPlane/migrations/0003_connection_principal.js +33 -0
  80. package/dist/controlPlane/scope/scope.d.ts +23 -2
  81. package/dist/controlPlane/scope/scope.d.ts.map +1 -1
  82. package/dist/controlPlane/scope/scope.js +24 -3
  83. package/dist/createBackend.d.ts.map +1 -1
  84. package/dist/createBackend.js +9 -2
  85. package/dist/createEntrypoint.d.ts.map +1 -1
  86. package/dist/createEntrypoint.js +5 -3
  87. package/dist/crypto/envelope.d.ts +86 -0
  88. package/dist/crypto/envelope.d.ts.map +1 -0
  89. package/dist/crypto/envelope.js +129 -0
  90. package/dist/crypto/fieldKeys.d.ts +41 -0
  91. package/dist/crypto/fieldKeys.d.ts.map +1 -0
  92. package/dist/crypto/fieldKeys.js +56 -0
  93. package/dist/data/codecs.d.ts +23 -10
  94. package/dist/data/codecs.d.ts.map +1 -1
  95. package/dist/data/codecs.js +50 -36
  96. package/dist/entitlement/allowance.d.ts +25 -0
  97. package/dist/entitlement/allowance.d.ts.map +1 -0
  98. package/dist/entitlement/allowance.js +80 -0
  99. package/dist/entitlement/entitlement.d.ts +41 -0
  100. package/dist/entitlement/entitlement.d.ts.map +1 -1
  101. package/dist/entitlement/meter.d.ts +57 -0
  102. package/dist/entitlement/meter.d.ts.map +1 -0
  103. package/dist/entitlement/meter.js +13 -0
  104. package/dist/error/extend.d.ts +6 -5
  105. package/dist/error/extend.d.ts.map +1 -1
  106. package/dist/error/http.d.ts +168 -0
  107. package/dist/error/http.d.ts.map +1 -1
  108. package/dist/error/payload.d.ts +336 -0
  109. package/dist/error/payload.d.ts.map +1 -1
  110. package/dist/error/payload.js +116 -4
  111. package/dist/error/pithyError.d.ts +18 -7
  112. package/dist/error/pithyError.d.ts.map +1 -1
  113. package/dist/error/pithyError.js +6 -0
  114. package/dist/http/authContext.d.ts +7 -0
  115. package/dist/http/authContext.d.ts.map +1 -1
  116. package/dist/http/authContext.js +8 -1
  117. package/dist/http/scopeGates.d.ts +20 -0
  118. package/dist/http/scopeGates.d.ts.map +1 -0
  119. package/dist/http/scopeGates.js +36 -0
  120. package/dist/index.d.ts +1 -1
  121. package/dist/index.d.ts.map +1 -1
  122. package/dist/index.js +2 -2
  123. package/dist/logger/logger.d.ts +12 -5
  124. package/dist/logger/logger.d.ts.map +1 -1
  125. package/dist/logger/record.d.ts +98 -0
  126. package/dist/logger/record.d.ts.map +1 -1
  127. package/dist/migrations/capabilitySets.d.ts +23 -0
  128. package/dist/migrations/capabilitySets.d.ts.map +1 -0
  129. package/dist/migrations/capabilitySets.js +74 -0
  130. package/dist/migrations/registry.d.ts +26 -0
  131. package/dist/migrations/registry.d.ts.map +1 -1
  132. package/dist/migrations/registry.js +38 -7
  133. package/dist/migrations/state.d.ts +60 -0
  134. package/dist/migrations/state.d.ts.map +1 -0
  135. package/dist/migrations/state.js +46 -0
  136. package/dist/naming/feature.d.ts +27 -5
  137. package/dist/naming/feature.d.ts.map +1 -1
  138. package/dist/naming/feature.js +36 -6
  139. package/dist/naming/limits.d.ts +47 -3
  140. package/dist/naming/limits.d.ts.map +1 -1
  141. package/dist/naming/limits.js +47 -3
  142. package/dist/naming/provisionScope.d.ts +6 -0
  143. package/dist/naming/provisionScope.d.ts.map +1 -1
  144. package/dist/naming/provisionScope.js +8 -3
  145. package/dist/naming/resourceNames.d.ts +21 -2
  146. package/dist/naming/resourceNames.d.ts.map +1 -1
  147. package/dist/naming/resourceNames.js +21 -3
  148. package/dist/privacy/blindIndex.d.ts +27 -0
  149. package/dist/privacy/blindIndex.d.ts.map +1 -0
  150. package/dist/privacy/blindIndex.js +57 -0
  151. package/dist/privacy/classes.d.ts +142 -0
  152. package/dist/privacy/classes.d.ts.map +1 -0
  153. package/dist/privacy/classes.js +209 -0
  154. package/dist/privacy/classify.d.ts +336 -0
  155. package/dist/privacy/classify.d.ts.map +1 -0
  156. package/dist/privacy/classify.js +1024 -0
  157. package/dist/privacy/encrypted.d.ts +210 -0
  158. package/dist/privacy/encrypted.d.ts.map +1 -0
  159. package/dist/privacy/encrypted.js +350 -0
  160. package/dist/privacy/encryptedColumns.d.ts +64 -0
  161. package/dist/privacy/encryptedColumns.d.ts.map +1 -0
  162. package/dist/privacy/encryptedColumns.js +134 -0
  163. package/dist/privacy/fieldRotation.d.ts +34 -0
  164. package/dist/privacy/fieldRotation.d.ts.map +1 -0
  165. package/dist/privacy/fieldRotation.js +186 -0
  166. package/dist/privacy/inventory.d.ts +12 -0
  167. package/dist/privacy/inventory.d.ts.map +1 -0
  168. package/dist/privacy/inventory.js +154 -0
  169. package/dist/privacy/posture.d.ts +114 -0
  170. package/dist/privacy/posture.d.ts.map +1 -0
  171. package/dist/privacy/posture.js +136 -0
  172. package/dist/privacy/redact.d.ts +7 -0
  173. package/dist/privacy/redact.d.ts.map +1 -0
  174. package/dist/privacy/redact.js +404 -0
  175. package/dist/privacy/report.d.ts +58 -0
  176. package/dist/privacy/report.d.ts.map +1 -0
  177. package/dist/privacy/report.js +15 -0
  178. package/dist/privacy/retirement.d.ts +68 -0
  179. package/dist/privacy/retirement.d.ts.map +1 -0
  180. package/dist/privacy/retirement.js +72 -0
  181. package/dist/privacy/sealed.d.ts +87 -0
  182. package/dist/privacy/sealed.d.ts.map +1 -0
  183. package/dist/privacy/sealed.js +221 -0
  184. package/dist/privacy/types.d.ts +559 -0
  185. package/dist/privacy/types.d.ts.map +1 -0
  186. package/dist/privacy/types.js +2 -0
  187. package/dist/seed/writeD1.d.ts +7 -1
  188. package/dist/seed/writeD1.d.ts.map +1 -1
  189. package/dist/seed/writeD1.js +9 -3
  190. package/dist/seed/writeKv.d.ts +2 -0
  191. package/dist/seed/writeKv.d.ts.map +1 -1
  192. package/dist/seed/writeKv.js +6 -2
  193. package/dist/version.generated.d.ts +1 -1
  194. package/dist/version.generated.js +1 -1
  195. package/dist/worker/serviceLoopback.d.ts +36 -0
  196. package/dist/worker/serviceLoopback.d.ts.map +1 -0
  197. package/dist/worker/serviceLoopback.js +74 -0
  198. package/dist/workflow/faults.d.ts +12 -1
  199. package/dist/workflow/faults.d.ts.map +1 -1
  200. package/dist/workflow/faults.js +22 -15
  201. package/package.json +2 -2
  202. package/src/access/access.ts +298 -0
  203. package/src/access/acting.ts +59 -0
  204. package/src/access/policyCheck.ts +77 -0
  205. package/src/access/usage.ts +141 -0
  206. package/src/access/visibility.ts +109 -0
  207. package/src/audit/auditEvent.ts +4 -0
  208. package/src/audit/recorder.ts +10 -2
  209. package/src/capability/bindings.ts +159 -13
  210. package/src/capability/capability.ts +114 -29
  211. package/src/capability/purge.ts +124 -0
  212. package/src/capability/settings.ts +146 -2
  213. package/src/cli/commandCatalog.generated.ts +271 -22
  214. package/src/cli/commandFacts.ts +2 -0
  215. package/src/controlPlane/capability.ts +36 -1
  216. package/src/controlPlane/context.ts +4 -0
  217. package/src/controlPlane/data/connection.ts +90 -0
  218. package/src/controlPlane/discovery/adminRoute.ts +11 -0
  219. package/src/controlPlane/error/errors.ts +4 -3
  220. package/src/controlPlane/http/cors.ts +4 -4
  221. package/src/controlPlane/http/guard.ts +21 -0
  222. package/src/controlPlane/http/handlers.ts +98 -4
  223. package/src/controlPlane/http/readiness.ts +50 -0
  224. package/src/controlPlane/http/responses.ts +240 -2
  225. package/src/controlPlane/http/routes.ts +55 -1
  226. package/src/controlPlane/http/verify.ts +2 -0
  227. package/src/controlPlane/migrationState/migrationState.ts +200 -0
  228. package/src/controlPlane/migrations/0003_connection_principal.ts +37 -0
  229. package/src/controlPlane/scope/scope.ts +25 -2
  230. package/src/controlPlane/token/base64url.ts +1 -1
  231. package/src/createBackend.ts +28 -6
  232. package/src/createEntrypoint.ts +9 -3
  233. package/src/crypto/envelope.ts +196 -0
  234. package/src/crypto/fieldKeys.ts +76 -0
  235. package/src/data/codecs.ts +69 -37
  236. package/src/entitlement/allowance.ts +85 -0
  237. package/src/entitlement/entitlement.ts +38 -0
  238. package/src/entitlement/meter.ts +69 -0
  239. package/src/error/extend.ts +6 -5
  240. package/src/error/payload.ts +253 -4
  241. package/src/error/pithyError.ts +21 -7
  242. package/src/http/authContext.ts +13 -1
  243. package/src/http/scopeGates.ts +34 -0
  244. package/src/index.ts +2 -0
  245. package/src/logger/logger.ts +12 -5
  246. package/src/migrations/capabilitySets.ts +87 -0
  247. package/src/migrations/registry.ts +46 -2
  248. package/src/migrations/state.ts +94 -0
  249. package/src/naming/feature.ts +46 -7
  250. package/src/naming/limits.ts +35 -3
  251. package/src/naming/provisionScope.ts +19 -1
  252. package/src/naming/resourceNames.ts +52 -5
  253. package/src/privacy/blindIndex.ts +81 -0
  254. package/src/privacy/classes.ts +277 -0
  255. package/src/privacy/classify.ts +1447 -0
  256. package/src/privacy/encrypted.ts +513 -0
  257. package/src/privacy/encryptedColumns.ts +185 -0
  258. package/src/privacy/fieldRotation.ts +234 -0
  259. package/src/privacy/inventory.ts +147 -0
  260. package/src/privacy/posture.ts +205 -0
  261. package/src/privacy/redact.ts +423 -0
  262. package/src/privacy/report.ts +64 -0
  263. package/src/privacy/retirement.ts +102 -0
  264. package/src/privacy/sealed.ts +323 -0
  265. package/src/privacy/types.ts +804 -0
  266. package/src/seed/writeD1.ts +13 -4
  267. package/src/seed/writeKv.ts +6 -2
  268. package/src/version.generated.ts +1 -1
  269. package/src/worker/serviceLoopback.ts +105 -0
  270. package/src/workflow/faults.ts +51 -24
@@ -1,7 +1,7 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
- import { ControlPlaneScope } from "../scope/scope.js";
4
3
  import { JsonDate, SQLiteDate, sqliteJson } from "../../data/codecs.js";
4
+ import { ControlPlaneScope } from "../scope/scope.js";
5
5
  import { z } from "zod";
6
6
  //#region src/controlPlane/data/connection.ts
7
7
  /**
@@ -35,6 +35,57 @@ const RegisteredKey = z.object({
35
35
  revokedAt: JsonDate.nullable().describe("When this key was revoked outright, or null. Revocation ignores `validUntil` and takes effect immediately — it is the adopter's unilateral control, and it must not wait for a window to close.")
36
36
  }).describe("One registered public key with its validity window. Two live at once during a rotation overlap.");
37
37
  /**
38
+ * What kind of client a connection is for (#721): `agent`, `dashboard` or `script`.
39
+ *
40
+ * The audit trail's `actorType: "control-plane"` names all three identically, and the questions asked
41
+ * after an incident are exactly the ones that tell them apart — was it a person at the dashboard, a
42
+ * script somebody wrote, or an agent running unattended. So the kind is recorded on the connection when
43
+ * it is registered and stamped from there onto every row its calls write.
44
+ *
45
+ * It follows the path, never a guess: the device-code flow is a dashboard, always, and a key the
46
+ * operator registered themselves is whichever of the other two they say, out loud, with `--kind`.
47
+ */
48
+ const ControlPlaneActorKind = z.enum([
49
+ "agent",
50
+ "dashboard",
51
+ "script"
52
+ ]).describe("What kind of client a connection is for: `agent` (an automated client acting on its own judgment, often unattended), `dashboard` (a management dashboard a person drives, registered through the device-code flow), or `script` (an operator's own automation, doing one fixed thing).");
53
+ /**
54
+ * Who sanctioned a connection: the email address of the signed-in Cloudflare session that registered it.
55
+ *
56
+ * **A plain string, deliberately not a reference.** An adopter's `pithy_auth_users` are their customers,
57
+ * and the operator who registers a connection is their staff, so a join into the organization model would
58
+ * be empty for most of them. A string is readable by anybody, and matchable against a directory where the
59
+ * operator is in one.
60
+ *
61
+ * **Derived, never asserted.** No flag supplies it; the CLI reads it from `GET /user` under the session.
62
+ */
63
+ const ConnectionPrincipal = z.email().max(254).describe("The email address of the person who sanctioned this connection, read from their signed-in Cloudflare session at registration. Never typed, so never asserted.");
64
+ /** The longest purpose a connection may carry. One line on a review screen, with room to say what it does. */
65
+ const MAX_CONNECTION_PURPOSE = 200;
66
+ /**
67
+ * Characters a purpose may not carry: every C0 and C1 control (so no terminal escape, no newline and no
68
+ * carriage return), the Unicode line and paragraph separators, every `Bidi_Control` character — the
69
+ * embeddings, overrides and isolates, and the LRM, RLM and ALM marks — that lets text render in a
70
+ * different order from the one it is stored in, and the invisible zero-width space, word joiner and
71
+ * byte-order mark that split a word without showing it. The zero-width joiner and non-joiner stay: Persian
72
+ * and the Indic scripts cannot be written without them.
73
+ *
74
+ * Each of those is a way for a sentence to look like something else once it reaches a renderer: a line
75
+ * in `pithy dashboard status` forged beneath the real one, a screen cleared, a scope name read backwards.
76
+ * Escaping them at every renderer is a promise each renderer has to keep. Refusing them at the boundary
77
+ * is one promise, kept here.
78
+ */
79
+ const UNRENDERABLE = /[\p{Cc}\p{Bidi_Control}\u2028\u2029\u200B\u2060\uFEFF]/u;
80
+ /**
81
+ * What a connection is for, in the words of whoever registered it (#721).
82
+ *
83
+ * **Required at registration, and refused when absent**, because a review listing credentials by key id
84
+ * cannot support the decision it exists for. **Untrusted input**: a customer writes it and something else
85
+ * renders it, so it is validated on the way in, and again on every read of the row.
86
+ */
87
+ const ConnectionPurpose = z.string().trim().min(1, "Say what this client is for.").max(200, `A purpose is 200 characters at most.`).refine((purpose) => !UNRENDERABLE.test(purpose), "A purpose is one line of plain text: no control, bidi or invisible characters.").describe(`What this connection's client is for, in the registering operator's words — one line of plain text, 200 characters at most, with no control, bidi or invisible characters. Written by a customer and rendered elsewhere, so validated at the boundary.`);
88
+ /**
38
89
  * One management-client connection — the row in `pithy_controlplane_connections`.
39
90
  *
40
91
  * Keys are a versioned JSON column rather than a child table for two reasons. **Rotation becomes one
@@ -49,10 +100,13 @@ const ControlPlaneConnection = z.object({
49
100
  workerUrl: z.url().describe("This environment's deployed Worker URL, captured at connect. The address the management client calls; re-pointed by `pithy dashboard connect --update` when a custom domain or a rename moves it."),
50
101
  basePath: z.string().min(1).default("/control-plane").describe("Where this Worker mounts the control-plane seam, captured at connect from its resolved config. Stored beside `workerUrl` because the two together fully determine the manifest address — and this is the one part of it a client cannot discover, since it *is* the manifest's own address. Defaulted rather than required so a connection registered before the column existed still parses, reading as the default it was necessarily using."),
51
102
  managementOrigin: z.url().nullable().default(null).describe("Where the management client that registered this connection answers — the origin the CLI calls for a verify, a rotation or a disconnect. Stored because it is not derivable: `issuer` is what that client *signs as*, and nothing says a dashboard's API answers at its own `iss`. Null for a connection registered before this column, which reads as the issuer rather than as the hosted dashboard — an older row is still a row about somebody's own deployment. Nothing on the Worker's side reads it; verification cares about `issuer` alone."),
103
+ authorizedBy: ConnectionPrincipal.nullable().default(null).describe("Who sanctioned this connection: the email of the signed-in Cloudflare session that registered it, never a flag. Null for a connection registered before principals were recorded (#721), which keeps working and reads as exactly that; registering again is the only way to set it."),
104
+ actorKind: ControlPlaneActorKind.nullable().default(null).describe("What kind of client this connection is for — `agent`, `dashboard` or `script` — stamped onto every audit row its calls write so the trail can tell them apart. Null for a connection registered before it was recorded."),
105
+ purpose: ConnectionPurpose.nullable().default(null).describe("What this connection's client is for, in the registering operator's words. Required at registration and editable with `pithy dashboard connect --update --purpose`; null only for a connection registered before it was recorded."),
52
106
  scopes: sqliteJson(z.array(ControlPlaneScope)).describe("The operations this connection was granted, stored and enforced on the adopter's side. Enforced only by the caller, a scope would not be a limit at all."),
53
107
  keys: sqliteJson(z.array(RegisteredKey)).describe("Every key this connection may sign with, current and superseded. One JSON column rather than a child table, so a rotation is one atomic UPDATE and verification is one read."),
54
108
  createdAt: SQLiteDate.describe("When the connection was registered. Ms-epoch in SQLite, a Date in TypeScript."),
55
109
  updatedAt: SQLiteDate.describe("When the row last changed — a key registered or expired, or the Worker URL re-pointed.")
56
110
  }).describe("One management-client connection: its identity, the environment and URL it is bound to, the operations it was granted, and its versioned public keys.");
57
111
  //#endregion
58
- export { ControlPlaneConnection, Ed25519PublicJwk, RegisteredKey };
112
+ export { ConnectionPrincipal, ConnectionPurpose, ControlPlaneActorKind, ControlPlaneConnection, Ed25519PublicJwk, MAX_CONNECTION_PURPOSE, RegisteredKey };
@@ -218,6 +218,35 @@ export declare const ControlPlaneManifest: z.ZodObject<{
218
218
  environment: z.ZodString;
219
219
  connectionId: z.ZodString;
220
220
  version: z.ZodNullable<z.ZodString>;
221
+ versionCreatedAt: z.ZodOptional<z.ZodNullable<z.ZodISODateTime>>;
222
+ privacy: z.ZodOptional<z.ZodObject<{
223
+ declared: z.ZodNullable<z.ZodArray<z.ZodString>>;
224
+ observed: z.ZodNullable<z.ZodArray<z.ZodString>>;
225
+ counts: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodNumber>>;
226
+ observedNotDeclared: z.ZodNullable<z.ZodArray<z.ZodString>>;
227
+ declaredNotObserved: z.ZodNullable<z.ZodArray<z.ZodString>>;
228
+ consoleGate: z.ZodEnum<{
229
+ enforced: "enforced";
230
+ not_required: "not_required";
231
+ unattested: "unattested";
232
+ unverifiable: "unverifiable";
233
+ }>;
234
+ consoleGateReason: z.ZodNullable<z.ZodString>;
235
+ attestedAt: z.ZodNullable<z.ZodISODateTime>;
236
+ sources: z.ZodArray<z.ZodEnum<{
237
+ d1: "d1";
238
+ kv: "kv";
239
+ }>>;
240
+ retirement: z.ZodOptional<z.ZodObject<{
241
+ blocked: z.ZodBoolean;
242
+ reasons: z.ZodArray<z.ZodEnum<{
243
+ "incomplete-coverage": "incomplete-coverage";
244
+ stale: "stale";
245
+ unrotatable: "unrotatable";
246
+ }>>;
247
+ liveVersions: z.ZodNumber;
248
+ }, z.core.$strip>>;
249
+ }, z.core.$strip>>;
221
250
  capabilities: z.ZodArray<z.ZodCodec<z.ZodObject<{
222
251
  name: z.ZodString;
223
252
  version: z.ZodNullable<z.ZodString>;
@@ -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;AAKxB;;;;;;;;;;;;;;;;;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuBkE,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;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"}
@@ -2,6 +2,7 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  import { ControlPlaneScope } from "../scope/scope.js";
4
4
  import { CapabilityHealthReport, HealthSummary, HealthSummaryKey, healthReport, healthWire } from "./healthSummary.js";
5
+ import { PrivacyPosture } from "../../privacy/posture.js";
5
6
  import { ManifestConfigKey, ManifestConfigValues } from "./configuration.js";
6
7
  import { z } from "zod";
7
8
  //#region src/controlPlane/discovery/adminRoute.ts
@@ -138,6 +139,8 @@ const ControlPlaneManifest = z.object({
138
139
  environment: z.string().describe("The environment this connection is bound to, echoed so a client can label what it is looking at."),
139
140
  connectionId: z.string().describe("The connection this call authenticated as."),
140
141
  version: z.string().nullable().describe("The Cloudflare version id of the build answering this call, from the `CF_VERSION_METADATA` binding, or null where the binding is absent. Opaque and per-deploy: it identifies which build is running, never which features it has. Null is honest — a Worker scaffolded before the binding was declared genuinely cannot say."),
142
+ versionCreatedAt: z.iso.datetime().nullable().optional().describe("When the version answering this call was uploaded, ISO-8601, from the same `CF_VERSION_METADATA` binding as `version` — or null where the binding is absent. The id alone cannot tell a deploy from a rollback: a rollback reactivates an existing version, so the id returns to one already seen while this moves backwards. Relayed, never interpreted. Absent from a Worker older than #132."),
143
+ privacy: PrivacyPosture.optional().describe("What this project declares about privacy and what its running code holds: classes and counts, never field names (`GET /control-plane/privacy` has those, behind `privacy:read`). Present on every Worker from #132, `declared` explicitly empty when nothing was declared; absent from an older Worker."),
141
144
  capabilities: z.array(CapabilityDescriptor).describe("Every capability composed into this Worker, in composition order with the adopter's own app last. A capability absent here has no data to show, which is a fact the client discovers rather than a setting anybody maintains."),
142
145
  grantedScopes: z.array(ControlPlaneScope).describe("Every scope this connection holds. Together with each route's own `scope`, this is what tells a client which operations to offer and which to hide.")
143
146
  }).describe("What this Worker is, what it composes, and how to call the admin surface it exposes.");
@@ -2,6 +2,7 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  import { PithyError } from "../../error/pithyError";
4
4
  import type { MessageParams } from "../../i18n/catalog";
5
+ import type { UnmarkedString } from "../../privacy/types";
5
6
  /**
6
7
  * The `control-plane` strategy's throw sugar. The `controlplane/*` codes live in core's closed
7
8
  * `KitErrorPayload` union (CLAUDE.md §Errors); these subclasses are the vehicles that set one.
@@ -16,9 +17,9 @@ import type { MessageParams } from "../../i18n/catalog";
16
17
  * the response into an oracle that tells an attacker exactly how far they got.
17
18
  */
18
19
  interface ControlPlaneErrorArgs {
19
- message?: string;
20
- action?: string;
21
- detail?: string;
20
+ message?: UnmarkedString;
21
+ action?: UnmarkedString;
22
+ detail?: UnmarkedString;
22
23
  /**
23
24
  * Values a translating client interpolates into its own wording for this code. Client-facing, so —
24
25
  * unlike `action` and `detail` — these cross the boundary with `message`.
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/error/errors.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD;;;;;;;;;;;;GAYG;AAEH,UAAU,qBAAqB;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED;;;GAGG;AACH,qBAAa,6BAA8B,SAAQ,UAAU;IAC3D,YAAY,IAAI,GAAE,qBAA0B,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAc1E;CACF;AAED;;;GAGG;AACH,qBAAa,kCAAmC,SAAQ,UAAU;IAChE,YAAY,IAAI,GAAE,qBAA0B,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAc1E;CACF;AAED,sEAAsE;AACtE,qBAAa,kCAAmC,SAAQ,UAAU;IAChE,YAAY,IAAI,GAAE,qBAA0B,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAc1E;CACF;AAED,0DAA0D;AAC1D,qBAAa,4BAA6B,SAAQ,UAAU;IAC1D,YAAY,IAAI,GAAE,qBAA0B,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAY1E;CACF;AAED;;;;GAIG;AACH,qBAAa,4BAA6B,SAAQ,UAAU;IAC1D,YAAY,IAAI,GAAE,qBAA0B,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAY1E;CACF"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/error/errors.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;;;;;;;;GAYG;AAEH,UAAU,qBAAqB;IAC7B,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB;;;OAGG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED;;;GAGG;AACH,qBAAa,6BAA8B,SAAQ,UAAU;IAC3D,YAAY,IAAI,GAAE,qBAA0B,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAc1E;CACF;AAED;;;GAGG;AACH,qBAAa,kCAAmC,SAAQ,UAAU;IAChE,YAAY,IAAI,GAAE,qBAA0B,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAc1E;CACF;AAED,sEAAsE;AACtE,qBAAa,kCAAmC,SAAQ,UAAU;IAChE,YAAY,IAAI,GAAE,qBAA0B,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAc1E;CACF;AAED,0DAA0D;AAC1D,qBAAa,4BAA6B,SAAQ,UAAU;IAC1D,YAAY,IAAI,GAAE,qBAA0B,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAY1E;CACF;AAED;;;;GAIG;AACH,qBAAa,4BAA6B,SAAQ,UAAU;IAC1D,YAAY,IAAI,GAAE,qBAA0B,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAY1E;CACF"}
@@ -93,10 +93,10 @@ export declare function corsMiddleware(entry: CorsSurfaceEntry, origins: Readonl
93
93
  /**
94
94
  * Mount one `app.use(path, …)` per entry.
95
95
  *
96
- * **Called from the capability's `middleware` hook, never its `routes` hook, and that is load-bearing.**
97
- * `createBackend` runs every capability's `middleware` hook before **any** capability's `routes` hook
98
- * (`createBackend.ts:262-267`), which is what makes this independent of the order an adopter happens to
99
- * list their capabilities in.
96
+ * **Called from `createBackend` ahead of every capability's `middleware`, never from a `routes` hook,
97
+ * and that is load-bearing.** Registered there, it is independent of the order an adopter happens to
98
+ * list their capabilities in, and it can put a header on whatever a capability's middleware or a
99
+ * readiness guard short-circuits.
100
100
  *
101
101
  * From `routes` it looks like it works and does not. The preflight still answers — an `OPTIONS` has no
102
102
  * route handler to lose to, so this `use` is the only thing that matches it — but a capability composed
@@ -170,10 +170,10 @@ function corsMiddleware(entry, origins, maxAgeSeconds) {
170
170
  /**
171
171
  * Mount one `app.use(path, …)` per entry.
172
172
  *
173
- * **Called from the capability's `middleware` hook, never its `routes` hook, and that is load-bearing.**
174
- * `createBackend` runs every capability's `middleware` hook before **any** capability's `routes` hook
175
- * (`createBackend.ts:262-267`), which is what makes this independent of the order an adopter happens to
176
- * list their capabilities in.
173
+ * **Called from `createBackend` ahead of every capability's `middleware`, never from a `routes` hook,
174
+ * and that is load-bearing.** Registered there, it is independent of the order an adopter happens to
175
+ * list their capabilities in, and it can put a header on whatever a capability's middleware or a
176
+ * readiness guard short-circuits.
177
177
  *
178
178
  * From `routes` it looks like it works and does not. The preflight still answers — an `OPTIONS` has no
179
179
  * route handler to lose to, so this `use` is the only thing that matches it — but a capability composed
@@ -1,8 +1,10 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
3
  import type { MiddlewareHandler } from "hono";
4
+ import type { AuditEmit } from "../../audit/recorder";
4
5
  import type { PithyHonoEnv } from "../../capability/capability";
5
6
  import type { ControlPlaneContext } from "../context";
7
+ import type { ControlPlaneActorKind } from "../data/connection";
6
8
  import type { ControlPlaneRequirement } from "../scope/scope";
7
9
  import { type ControlPlaneVerifyDeps } from "./verify";
8
10
  /**
@@ -76,4 +78,13 @@ export declare const CONTROL_PLANE_GUARD: unique symbol;
76
78
  /** Whether a mounted handler is a control-plane gate. */
77
79
  export declare function isControlPlaneGuard(handler: unknown): boolean;
78
80
  export declare function requireControlPlane(requirement: ControlPlaneRequirement): MiddlewareHandler<PithyHonoEnv>;
81
+ /**
82
+ * The recorder a verified call's handlers write through: the request's own, with the connection's actor
83
+ * kind added to every `control-plane` event that does not already carry one.
84
+ *
85
+ * Only `control-plane` events, because the kind describes a management client and nothing else — a
86
+ * handler recording what happened to a user is recording a user. An event that states a kind keeps it.
87
+ * A connection with no recorded kind adds nothing, so its rows read exactly as they did before.
88
+ */
89
+ export declare function stampActorKind(emit: AuditEmit, actorKind: ControlPlaneActorKind | null): AuditEmit;
79
90
  //# sourceMappingURL=guard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/guard.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAMhE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAE9D,OAAO,EAAE,KAAK,sBAAsB,EAA0B,MAAM,UAAU,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,CACjC,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,uBAAuB,KACjC,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAElC;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,sBAAsB,GAAG,oBAAoB,CAgB7F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMzE;AAED;;;;;;GAMG;AACH;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,eAAwC,CAAC;AAEzE,yDAAyD;AACzD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAE7D;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,uBAAuB,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAkEzG"}
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/guard.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAMhE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAE9D,OAAO,EAAE,KAAK,sBAAsB,EAA0B,MAAM,UAAU,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,CACjC,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,uBAAuB,KACjC,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAElC;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,sBAAsB,GAAG,oBAAoB,CAgB7F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMzE;AAED;;;;;;GAMG;AACH;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,eAAwC,CAAC;AAEzE,yDAAyD;AACzD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAE7D;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,uBAAuB,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAuEzG;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,qBAAqB,GAAG,IAAI,GAAG,SAAS,CAIlG"}
@@ -85,6 +85,7 @@ function requireControlPlane(requirement) {
85
85
  throw cause;
86
86
  }
87
87
  c.set("controlPlane", context);
88
+ c.set("emit", stampActorKind(c.var.emit, context.actorKind));
88
89
  await safeEmit(c.var.emit, {
89
90
  action: ControlPlaneAuditActions.callAllowed,
90
91
  outcome: "success",
@@ -110,6 +111,21 @@ function requireControlPlane(requirement) {
110
111
  return guard;
111
112
  }
112
113
  /**
114
+ * The recorder a verified call's handlers write through: the request's own, with the connection's actor
115
+ * kind added to every `control-plane` event that does not already carry one.
116
+ *
117
+ * Only `control-plane` events, because the kind describes a management client and nothing else — a
118
+ * handler recording what happened to a user is recording a user. An event that states a kind keeps it.
119
+ * A connection with no recorded kind adds nothing, so its rows read exactly as they did before.
120
+ */
121
+ function stampActorKind(emit, actorKind) {
122
+ if (actorKind === null) return emit;
123
+ return (event) => emit(event.actorType === "control-plane" && event.actorKind == null ? {
124
+ ...event,
125
+ actorKind
126
+ } : event);
127
+ }
128
+ /**
113
129
  * Record a refused call.
114
130
  *
115
131
  * **Denials are audited, not only successes.** `denied` is a first-class outcome precisely for this, and
@@ -151,4 +167,4 @@ function connectStep(env) {
151
167
  return remedy("dashboard connect", { flags: { "--env": env } }, { runtime: true }).say((command) => `run ${command}`);
152
168
  }
153
169
  //#endregion
154
- export { CONTROL_PLANE_GUARD, createControlPlaneVerifier, isControlPlaneGuard, requireControlPlane, workerVersionHeaders };
170
+ export { CONTROL_PLANE_GUARD, createControlPlaneVerifier, isControlPlaneGuard, requireControlPlane, stampActorKind, workerVersionHeaders };
@@ -2,10 +2,13 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  import type { Context } from "hono";
4
4
  import type { PithyHonoEnv } from "../../capability/capability";
5
+ import type { PrivacyInventory } from "../../privacy/report";
6
+ import type { RetirementVerdict } from "../../privacy/retirement";
5
7
  import type { ControlPlaneConfig } from "../config/config";
6
8
  import { type ControlPlaneDatabase } from "../data/tables";
7
9
  import type { CapabilityDeclaration } from "../discovery/adminRoute";
8
10
  import { type CapabilityHealthSource } from "../discovery/health";
11
+ import { type ComposedMigrationDatabase } from "../migrationState/migrationState";
9
12
  import type { ExpireKeyParams, ExpireKeyRequest, RegisterKeyRequest } from "./schemas";
10
13
  /** The pieces of the composed capability a handler needs. Passed in, so nothing reaches for a global. */
11
14
  export interface ControlPlaneHandlerDeps {
@@ -31,6 +34,21 @@ export interface ControlPlaneHandlerDeps {
31
34
  * value is not: the numbers are resolved per request, behind the scope each one is declared under.
32
35
  */
33
36
  composedHealth: () => ReadonlyMap<string, CapabilityHealthSource>;
37
+ /**
38
+ * Every database this Worker binds, with the provider this build composes for it — captured by the same
39
+ * `compose` hook through `collectMigrationSets`, the function `pithy migrate` composes with (#729).
40
+ */
41
+ composedMigrations: () => readonly ComposedMigrationDatabase[];
42
+ /**
43
+ * The privacy inventory of every storage schema this Worker composed (#132), walked on the first call and
44
+ * cached for the isolate. A thunk, so a Worker whose control plane is never called never walks.
45
+ */
46
+ privacyInventory: () => PrivacyInventory;
47
+ /**
48
+ * The field key's retirement verdict (#390): the guard over this Worker's encrypted columns, read through its own
49
+ * bindings. Never throws: whatever it cannot read is incomplete coverage.
50
+ */
51
+ retirement: (env: Record<string, unknown>) => Promise<RetirementVerdict>;
34
52
  /** The clock, injected so a test can stand at any instant. */
35
53
  now: () => Date;
36
54
  }
@@ -73,6 +91,25 @@ export declare function manifestHandler(deps: ControlPlaneHandlerDeps): (c: Cont
73
91
  environment: string;
74
92
  connectionId: string;
75
93
  version: string | null;
94
+ versionCreatedAt: string | null;
95
+ privacy: {
96
+ declared: string[] | null;
97
+ observed: string[] | null;
98
+ counts: {
99
+ [x: string]: number;
100
+ } | null;
101
+ observedNotDeclared: string[] | null;
102
+ declaredNotObserved: string[] | null;
103
+ consoleGate: "enforced" | "not_required" | "unattested" | "unverifiable";
104
+ consoleGateReason: string | null;
105
+ attestedAt: string | null;
106
+ sources: ("d1" | "kv")[];
107
+ retirement: {
108
+ blocked: boolean;
109
+ reasons: ("incomplete-coverage" | "stale" | "unrotatable")[];
110
+ liveVersions: number;
111
+ };
112
+ };
76
113
  capabilities: {
77
114
  health: import("../..").HealthSummary | null;
78
115
  healthUnavailable: boolean;
@@ -108,6 +145,57 @@ export declare function manifestHandler(deps: ControlPlaneHandlerDeps): (c: Cont
108
145
  }[];
109
146
  grantedScopes: string[];
110
147
  }, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
148
+ /**
149
+ * `GET /control-plane/migrations` — where each database this Worker binds stands (#729).
150
+ *
151
+ * Read-only: it reports, and nothing over the seam runs, reverses or resets a migration.
152
+ *
153
+ * **One unreadable ledger costs one database its answer.** Each read catches its own failure and lands on
154
+ * `unreadable`, so `Promise.all` still resolves and the route answers 200 with what it has. The cause is
155
+ * logged here, for the operator, and never projected: a D1 error can name a table or a query.
156
+ */
157
+ export declare function migrationsHandler(deps: ControlPlaneHandlerDeps): (c: Context<PithyHonoEnv>) => Promise<Response & import("hono").TypedResponse<{
158
+ environment: string;
159
+ databases: ({
160
+ state: "readable";
161
+ database: string;
162
+ binding: string;
163
+ applied: {
164
+ name: string;
165
+ namespace: string | null;
166
+ }[];
167
+ pending: {
168
+ name: string;
169
+ namespace: string | null;
170
+ }[];
171
+ undeclared: {
172
+ name: string;
173
+ namespace: string | null;
174
+ }[];
175
+ lastGroup: {
176
+ group: string;
177
+ appliedAt: string;
178
+ migrations: {
179
+ name: string;
180
+ namespace: string | null;
181
+ }[];
182
+ position: {
183
+ state: "top";
184
+ } | {
185
+ state: "buried";
186
+ above: string[];
187
+ ungrouped: {
188
+ name: string;
189
+ namespace: string | null;
190
+ }[];
191
+ };
192
+ } | null;
193
+ } | {
194
+ state: "unreadable";
195
+ database: string;
196
+ binding: string;
197
+ })[];
198
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
111
199
  /** `GET /control-plane/keys` — the registration state, so a client can surface a stale key. */
112
200
  export declare function listKeysHandler(deps: ControlPlaneHandlerDeps): (c: Context<PithyHonoEnv>) => Promise<Response & import("hono").TypedResponse<{
113
201
  connectionId: string;
@@ -123,6 +211,9 @@ export declare function listKeysHandler(deps: ControlPlaneHandlerDeps): (c: Cont
123
211
  validUntil: string | null;
124
212
  revokedAt: string | null;
125
213
  }[];
214
+ authorizedBy: string | null;
215
+ actorKind: "agent" | "dashboard" | "script" | null;
216
+ purpose: string | null;
126
217
  }, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
127
218
  /**
128
219
  * `POST /control-plane/keys` — register a new public key, authenticated by the key it succeeds.
@@ -179,4 +270,52 @@ export declare function expireKeyHandler(deps: ControlPlaneHandlerDeps): (c: Con
179
270
  revokedAt: string | null;
180
271
  }[];
181
272
  }, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
273
+ /**
274
+ * `GET /control-plane/privacy` — the full privacy inventory (#132).
275
+ *
276
+ * Every storage schema this Worker composed that holds a marked field, each field's path and class, and where it
277
+ * is stored — derived from the running code, so unmarking a field removes it on the next deploy with nothing in
278
+ * between. Behind `privacy:read`, because field names are the kind of thing an adopter may withhold from a client
279
+ * that has no business seeing them. Read-only.
280
+ */
281
+ export declare function privacyHandler(deps: ControlPlaneHandlerDeps): (c: Context<PithyHonoEnv>) => Promise<Response & import("hono").TypedResponse<{
282
+ environment: string;
283
+ posture: {
284
+ declared: string[] | null;
285
+ observed: string[] | null;
286
+ counts: {
287
+ [x: string]: number;
288
+ } | null;
289
+ observedNotDeclared: string[] | null;
290
+ declaredNotObserved: string[] | null;
291
+ consoleGate: "enforced" | "not_required" | "unattested" | "unverifiable";
292
+ consoleGateReason: string | null;
293
+ attestedAt: string | null;
294
+ sources: ("d1" | "kv")[];
295
+ retirement: {
296
+ blocked: boolean;
297
+ reasons: ("incomplete-coverage" | "stale" | "unrotatable")[];
298
+ liveVersions: number;
299
+ };
300
+ };
301
+ schemasWalked: number;
302
+ schemas: {
303
+ capability: string;
304
+ storage: import("../../privacy/report").PrivacySource;
305
+ container: string;
306
+ name: string;
307
+ fields: {
308
+ path: string;
309
+ class: string;
310
+ truncated?: true;
311
+ sameAs?: string;
312
+ encryptedAtRest?: boolean;
313
+ unrotatable?: true;
314
+ }[];
315
+ encrypted: {
316
+ path: string;
317
+ unrotatable?: true;
318
+ }[];
319
+ }[];
320
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
182
321
  //# sourceMappingURL=handlers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/handlers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAI3D,OAAO,EAAmC,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC5F,OAAO,KAAK,EAAE,qBAAqB,EAA4B,MAAM,yBAAyB,CAAC;AAC/F,OAAO,EAAE,KAAK,sBAAsB,EAAwB,MAAM,qBAAqB,CAAC;AAUxF,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAuBvF,yGAAyG;AACzG,MAAM,WAAW,uBAAuB;IACtC,yDAAyD;IACzD,MAAM,EAAE,kBAAkB,CAAC;IAC3B,oEAAoE;IACpE,QAAQ,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,oBAAoB,CAAC;IAC7D;;;;;;;;OAQG;IACH,oBAAoB,EAAE,MAAM,SAAS,qBAAqB,EAAE,CAAC;IAC7D;;;;;;OAMG;IACH,cAAc,EAAE,MAAM,WAAW,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IAClE,8DAA8D;IAC9D,GAAG,EAAE,MAAM,IAAI,CAAC;CACjB;AAgED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,uBAAuB,OAC5C,OAAO,CAAC,YAAY,CAAC;;;;;;kEAUjC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,uBAAuB,OAC1C,OAAO,CAAC,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEAyBvC;AAED,+FAA+F;AAC/F,wBAAgB,eAAe,CAAC,IAAI,EAAE,uBAAuB,OAC1C,OAAO,CAAC,YAAY,CAAC;;;;;;;;;;;;;;mEASvC;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,uBAAuB,OAC7C,OAAO,CAAC,YAAY,CAAC,QAAQ,kBAAkB;;;;;;;;;;;;;;iBAoDjE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,OAC3C,OAAO,CAAC,YAAY,CAAC,UAAU,eAAe,QAAQ,gBAAgB;;;;;;;;;;;;;;mEA8CxF"}
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/handlers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAI3D,OAAO,EAAmC,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC5F,OAAO,KAAK,EAAE,qBAAqB,EAA4B,MAAM,yBAAyB,CAAC;AAC/F,OAAO,EAAE,KAAK,sBAAsB,EAAwB,MAAM,qBAAqB,CAAC;AAGxF,OAAO,EAAE,KAAK,yBAAyB,EAA0B,MAAM,kCAAkC,CAAC;AAU1G,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAuBvF,yGAAyG;AACzG,MAAM,WAAW,uBAAuB;IACtC,yDAAyD;IACzD,MAAM,EAAE,kBAAkB,CAAC;IAC3B,oEAAoE;IACpE,QAAQ,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,oBAAoB,CAAC;IAC7D;;;;;;;;OAQG;IACH,oBAAoB,EAAE,MAAM,SAAS,qBAAqB,EAAE,CAAC;IAC7D;;;;;;OAMG;IACH,cAAc,EAAE,MAAM,WAAW,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IAClE;;;OAGG;IACH,kBAAkB,EAAE,MAAM,SAAS,yBAAyB,EAAE,CAAC;IAC/D;;;OAGG;IACH,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;IACzC;;;OAGG;IACH,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACzE,8DAA8D;IAC9D,GAAG,EAAE,MAAM,IAAI,CAAC;CACjB;AAgED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,uBAAuB,OAC5C,OAAO,CAAC,YAAY,CAAC;;;;;;kEAUjC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,uBAAuB,OAC1C,OAAO,CAAC,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEAoCvC;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,uBAAuB,OAC5C,OAAO,CAAC,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEAgBvC;AAED,+FAA+F;AAC/F,wBAAgB,eAAe,CAAC,IAAI,EAAE,uBAAuB,OAC1C,OAAO,CAAC,YAAY,CAAC;;;;;;;;;;;;;;;;;mEAcvC;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,uBAAuB,OAC7C,OAAO,CAAC,YAAY,CAAC,QAAQ,kBAAkB;;;;;;;;;;;;;;iBAoDjE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,OAC3C,OAAO,CAAC,YAAY,CAAC,UAAU,eAAe,QAAQ,gBAAgB;;;;;;;;;;;;;;mEA8CxF;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,uBAAuB,OACzC,OAAO,CAAC,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEAiBvC"}
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
- import { workerVersion } from "../../worker/identity.js";
3
+ import { workerVersionMetadata } from "../../worker/identity.js";
4
4
  import { ControlPlaneConnection } from "../data/connection.js";
5
5
  import { CONTROL_PLANE_CONNECTIONS_TABLE } from "../data/tables.js";
6
6
  import { healthWire } from "../discovery/healthSummary.js";
@@ -8,6 +8,9 @@ import { readCapabilityHealth } from "../discovery/health.js";
8
8
  import { ControlPlaneAuditActions, safeEmit } from "../audit/actions.js";
9
9
  import { ControlPlaneInvalidCredentialError, ControlPlaneKeyConflictError } from "../error/errors.js";
10
10
  import { appendKey, expireKey, pruneKeys } from "../data/keyLifecycle.js";
11
+ import { privacyAttestation, privacyPosture } from "../../privacy/posture.js";
12
+ import { causeMessage } from "../../error/cause.js";
13
+ import { readDatabaseMigrations } from "../migrationState/migrationState.js";
11
14
  //#region src/controlPlane/http/handlers.ts
12
15
  /**
13
16
  * The seam's own route handlers.
@@ -112,15 +115,45 @@ function manifestHandler(deps) {
112
115
  ...declaration,
113
116
  ...healthWire(await readCapabilityHealth(sources.get(declaration.name), context.grantedScopes, (source) => source.read(c)))
114
117
  })));
118
+ const build = workerVersionMetadata(c.env);
115
119
  return c.json({
116
120
  environment: context.environment,
117
121
  connectionId: context.connectionId,
118
- version: workerVersion(c.env),
122
+ version: build.id,
123
+ versionCreatedAt: build.createdAt,
124
+ privacy: {
125
+ ...privacyPosture(privacyAttestation(c.env), deps.privacyInventory),
126
+ retirement: await deps.retirement(c.env)
127
+ },
119
128
  capabilities,
120
129
  grantedScopes: [...context.grantedScopes]
121
130
  });
122
131
  };
123
132
  }
133
+ /**
134
+ * `GET /control-plane/migrations` — where each database this Worker binds stands (#729).
135
+ *
136
+ * Read-only: it reports, and nothing over the seam runs, reverses or resets a migration.
137
+ *
138
+ * **One unreadable ledger costs one database its answer.** Each read catches its own failure and lands on
139
+ * `unreadable`, so `Promise.all` still resolves and the route answers 200 with what it has. The cause is
140
+ * logged here, for the operator, and never projected: a D1 error can name a table or a query.
141
+ */
142
+ function migrationsHandler(deps) {
143
+ return async (c) => {
144
+ const context = caller(c);
145
+ const env = c.env;
146
+ const databases = await Promise.all(deps.composedMigrations().map((entry) => readDatabaseMigrations(env, entry, (failed, cause) => c.var.log.warn("migration ledger unreadable", {
147
+ database: failed.database,
148
+ binding: failed.binding,
149
+ reason: causeMessage(cause) ?? String(cause)
150
+ }))));
151
+ return c.json({
152
+ environment: context.environment,
153
+ databases
154
+ });
155
+ };
156
+ }
124
157
  /** `GET /control-plane/keys` — the registration state, so a client can surface a stale key. */
125
158
  function listKeysHandler(deps) {
126
159
  return async (c) => {
@@ -129,7 +162,10 @@ function listKeysHandler(deps) {
129
162
  return c.json({
130
163
  connectionId: connection.id,
131
164
  environment: connection.environment,
132
- keys: connection.keys.map(publicKeyView)
165
+ keys: connection.keys.map(publicKeyView),
166
+ authorizedBy: connection.authorizedBy,
167
+ actorKind: connection.actorKind,
168
+ purpose: connection.purpose
133
169
  });
134
170
  };
135
171
  }
@@ -243,5 +279,32 @@ function expireKeyHandler(deps) {
243
279
  });
244
280
  };
245
281
  }
282
+ /**
283
+ * `GET /control-plane/privacy` — the full privacy inventory (#132).
284
+ *
285
+ * Every storage schema this Worker composed that holds a marked field, each field's path and class, and where it
286
+ * is stored — derived from the running code, so unmarking a field removes it on the next deploy with nothing in
287
+ * between. Behind `privacy:read`, because field names are the kind of thing an adopter may withhold from a client
288
+ * that has no business seeing them. Read-only.
289
+ */
290
+ function privacyHandler(deps) {
291
+ return async (c) => {
292
+ const context = caller(c);
293
+ const inventory = deps.privacyInventory();
294
+ return c.json({
295
+ environment: context.environment,
296
+ posture: {
297
+ ...privacyPosture(privacyAttestation(c.env), () => inventory),
298
+ retirement: await deps.retirement(c.env)
299
+ },
300
+ schemasWalked: inventory.schemasWalked,
301
+ schemas: inventory.schemas.map((schema) => ({
302
+ ...schema,
303
+ fields: schema.fields.map((field) => ({ ...field })),
304
+ encrypted: schema.encrypted.map((field) => ({ ...field }))
305
+ }))
306
+ });
307
+ };
308
+ }
246
309
  //#endregion
247
- export { expireKeyHandler, listKeysHandler, manifestHandler, pingHandler, registerKeyHandler };
310
+ export { expireKeyHandler, listKeysHandler, manifestHandler, migrationsHandler, pingHandler, privacyHandler, registerKeyHandler };
@@ -0,0 +1,33 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import type { Hono } from "hono";
4
+ import type { PithyHonoEnv, PithyReadinessGuard } from "../../capability/capability";
5
+ /**
6
+ * Mount every capability's readiness guard, exempting the admin surface.
7
+ *
8
+ * **The control plane answers whatever else is wrong with the Worker.** It is the diagnostic surface: a
9
+ * management client reads the manifest, migration state and drift through it. A guard that refuses every
10
+ * request because an index drifted would take that surface down on exactly the fault it exists to report,
11
+ * and the client could not tell drift from a Worker that is simply down.
12
+ *
13
+ * **The exemption is the guard, not the middleware.** The seam itself runs on capability middleware —
14
+ * `controlplane()` publishes the verifier and `audit()` publishes `emit` — so skipping middleware on a
15
+ * seam request would trade a 500 for a seam that denies everything, or one that stops auditing without a
16
+ * word. Readiness guards are the only middleware that refuses because the Worker is broken, so they are
17
+ * the only thing skipped.
18
+ *
19
+ * **Hono decides what is on the surface, not a matcher written here.** One `app.use` per admin path marks
20
+ * the request, so a `:segment` matches exactly as it does for the route and the CORS layer, and a literal
21
+ * path never matches what is beneath it. The surface is the one `corsSurface(all)` computes, which
22
+ * `routeContract.test.ts` already holds to the registered routes, so there is no second list to drift.
23
+ *
24
+ * The mark is a `WeakSet` over the raw `Request`, closed over here. A context variable would put an
25
+ * internal flag on `PithyVars`, where every capability could read it and one could set it.
26
+ *
27
+ * Call after every capability's `middleware` and before any capability's `routes`. Before the routes,
28
+ * because a terminal handler never calls `next()` and a guard mounted after it never runs.
29
+ */
30
+ export declare function registerReadinessGuards(app: Hono<PithyHonoEnv>, surface: readonly {
31
+ path: string;
32
+ }[], guards: readonly PithyReadinessGuard[]): void;
33
+ //# sourceMappingURL=readiness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readiness.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/readiness.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAErF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,IAAI,CAAC,YAAY,CAAC,EACvB,OAAO,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,EACpC,MAAM,EAAE,SAAS,mBAAmB,EAAE,GACrC,IAAI,CAcN"}