@pithy-sh/core 0.9.0 → 0.11.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 (298) 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/asyncapi/document.d.ts +46 -0
  17. package/dist/asyncapi/document.d.ts.map +1 -0
  18. package/dist/asyncapi/document.js +115 -0
  19. package/dist/audit/auditEvent.d.ts +5 -0
  20. package/dist/audit/auditEvent.d.ts.map +1 -1
  21. package/dist/audit/auditEvent.js +2 -0
  22. package/dist/capability/bindings.d.ts +47 -2
  23. package/dist/capability/bindings.d.ts.map +1 -1
  24. package/dist/capability/bindings.js +117 -7
  25. package/dist/capability/capability.d.ts +105 -28
  26. package/dist/capability/capability.d.ts.map +1 -1
  27. package/dist/capability/composition.d.ts.map +1 -1
  28. package/dist/capability/composition.js +5 -1
  29. package/dist/capability/manifest.d.ts +2 -1
  30. package/dist/capability/manifest.d.ts.map +1 -1
  31. package/dist/capability/manifest.js +1 -1
  32. package/dist/capability/settings.d.ts +96 -4
  33. package/dist/capability/settings.d.ts.map +1 -1
  34. package/dist/capability/settings.js +85 -4
  35. package/dist/cli/command.d.ts +364 -0
  36. package/dist/cli/command.d.ts.map +1 -0
  37. package/dist/cli/command.js +418 -0
  38. package/dist/cli/commandCatalog.generated.d.ts +2437 -0
  39. package/dist/cli/commandCatalog.generated.d.ts.map +1 -0
  40. package/dist/cli/commandCatalog.generated.js +2564 -0
  41. package/dist/cli/commandFacts.d.ts +164 -0
  42. package/dist/cli/commandFacts.d.ts.map +1 -0
  43. package/dist/cli/commandFacts.js +216 -0
  44. package/dist/controlPlane/capability.d.ts.map +1 -1
  45. package/dist/controlPlane/capability.js +12 -2
  46. package/dist/controlPlane/context.d.ts +5 -0
  47. package/dist/controlPlane/context.d.ts.map +1 -1
  48. package/dist/controlPlane/context.js +3 -1
  49. package/dist/controlPlane/data/connection.d.ts +47 -0
  50. package/dist/controlPlane/data/connection.d.ts.map +1 -1
  51. package/dist/controlPlane/data/connection.js +55 -1
  52. package/dist/controlPlane/error/errors.d.ts.map +1 -1
  53. package/dist/controlPlane/error/errors.js +4 -3
  54. package/dist/controlPlane/http/cors.d.ts +4 -4
  55. package/dist/controlPlane/http/cors.js +4 -4
  56. package/dist/controlPlane/http/guard.d.ts +11 -0
  57. package/dist/controlPlane/http/guard.d.ts.map +1 -1
  58. package/dist/controlPlane/http/guard.js +28 -2
  59. package/dist/controlPlane/http/handlers.d.ts +60 -0
  60. package/dist/controlPlane/http/handlers.d.ts.map +1 -1
  61. package/dist/controlPlane/http/handlers.js +31 -2
  62. package/dist/controlPlane/http/readiness.d.ts +33 -0
  63. package/dist/controlPlane/http/readiness.d.ts.map +1 -0
  64. package/dist/controlPlane/http/readiness.js +39 -0
  65. package/dist/controlPlane/http/responses.d.ts +147 -0
  66. package/dist/controlPlane/http/responses.d.ts.map +1 -1
  67. package/dist/controlPlane/http/responses.js +61 -4
  68. package/dist/controlPlane/http/routes.d.ts +2 -1
  69. package/dist/controlPlane/http/routes.d.ts.map +1 -1
  70. package/dist/controlPlane/http/routes.js +50 -9
  71. package/dist/controlPlane/http/verify.d.ts.map +1 -1
  72. package/dist/controlPlane/http/verify.js +2 -1
  73. package/dist/controlPlane/migrationState/migrationState.d.ts +102 -0
  74. package/dist/controlPlane/migrationState/migrationState.d.ts.map +1 -0
  75. package/dist/controlPlane/migrationState/migrationState.js +142 -0
  76. package/dist/controlPlane/migrations/0003_connection_principal.d.ts +21 -0
  77. package/dist/controlPlane/migrations/0003_connection_principal.d.ts.map +1 -0
  78. package/dist/controlPlane/migrations/0003_connection_principal.js +33 -0
  79. package/dist/controlPlane/scope/scope.d.ts +13 -2
  80. package/dist/controlPlane/scope/scope.d.ts.map +1 -1
  81. package/dist/controlPlane/scope/scope.js +14 -3
  82. package/dist/createBackend.d.ts +7 -0
  83. package/dist/createBackend.d.ts.map +1 -1
  84. package/dist/createBackend.js +41 -6
  85. package/dist/createEntrypoint.d.ts.map +1 -1
  86. package/dist/createEntrypoint.js +5 -3
  87. package/dist/entitlement/allowance.d.ts +25 -0
  88. package/dist/entitlement/allowance.d.ts.map +1 -0
  89. package/dist/entitlement/allowance.js +80 -0
  90. package/dist/entitlement/entitlement.d.ts +41 -0
  91. package/dist/entitlement/entitlement.d.ts.map +1 -1
  92. package/dist/entitlement/meter.d.ts +57 -0
  93. package/dist/entitlement/meter.d.ts.map +1 -0
  94. package/dist/entitlement/meter.js +13 -0
  95. package/dist/entitlement/require.js +1 -1
  96. package/dist/error/cause.d.ts +16 -116
  97. package/dist/error/cause.d.ts.map +1 -1
  98. package/dist/error/cause.js +19 -153
  99. package/dist/error/http.d.ts +184 -0
  100. package/dist/error/http.d.ts.map +1 -1
  101. package/dist/error/payload.d.ts +368 -0
  102. package/dist/error/payload.d.ts.map +1 -1
  103. package/dist/error/payload.js +126 -4
  104. package/dist/error/pithyError.d.ts +44 -0
  105. package/dist/error/pithyError.d.ts.map +1 -1
  106. package/dist/error/pithyError.js +56 -1
  107. package/dist/error/unresolved.d.ts +265 -0
  108. package/dist/error/unresolved.d.ts.map +1 -0
  109. package/dist/error/unresolved.js +599 -0
  110. package/dist/error/wire.d.ts +20 -0
  111. package/dist/error/wire.d.ts.map +1 -0
  112. package/dist/error/wire.js +19 -0
  113. package/dist/http/authContext.d.ts +7 -0
  114. package/dist/http/authContext.d.ts.map +1 -1
  115. package/dist/http/authContext.js +8 -1
  116. package/dist/http/oidcWebhook.d.ts +3 -3
  117. package/dist/http/oidcWebhook.js +3 -3
  118. package/dist/http/routeContract.js +1 -1
  119. package/dist/http/routeSpec.d.ts +66 -0
  120. package/dist/http/routeSpec.d.ts.map +1 -0
  121. package/dist/http/routeSpec.js +40 -0
  122. package/dist/http/sameOrigin.d.ts +1 -1
  123. package/dist/http/sameOrigin.js +1 -1
  124. package/dist/http/scopeGates.d.ts +20 -0
  125. package/dist/http/scopeGates.d.ts.map +1 -0
  126. package/dist/http/scopeGates.js +36 -0
  127. package/dist/http/signedWebhook.d.ts +3 -3
  128. package/dist/http/signedWebhook.js +3 -3
  129. package/dist/http/socket.d.ts +52 -0
  130. package/dist/http/socket.d.ts.map +1 -0
  131. package/dist/http/socket.js +2 -0
  132. package/dist/http/subprotocol.d.ts +29 -0
  133. package/dist/http/subprotocol.d.ts.map +1 -0
  134. package/dist/http/subprotocol.js +37 -0
  135. package/dist/http/validation.d.ts +40 -8
  136. package/dist/http/validation.d.ts.map +1 -1
  137. package/dist/http/validation.js +25 -1
  138. package/dist/index.d.ts +1 -1
  139. package/dist/index.d.ts.map +1 -1
  140. package/dist/index.js +4 -4
  141. package/dist/logger/record.d.ts +107 -0
  142. package/dist/logger/record.d.ts.map +1 -1
  143. package/dist/migrations/bookkeeping.d.ts +21 -0
  144. package/dist/migrations/bookkeeping.d.ts.map +1 -1
  145. package/dist/migrations/bookkeeping.js +32 -3
  146. package/dist/migrations/capabilitySets.d.ts +23 -0
  147. package/dist/migrations/capabilitySets.d.ts.map +1 -0
  148. package/dist/migrations/capabilitySets.js +74 -0
  149. package/dist/migrations/groups.d.ts +140 -0
  150. package/dist/migrations/groups.d.ts.map +1 -0
  151. package/dist/migrations/groups.js +191 -0
  152. package/dist/migrations/migrateStep.d.ts +13 -0
  153. package/dist/migrations/migrateStep.d.ts.map +1 -0
  154. package/dist/migrations/migrateStep.js +20 -0
  155. package/dist/migrations/owner.d.ts +7 -0
  156. package/dist/migrations/owner.d.ts.map +1 -1
  157. package/dist/migrations/owner.js +11 -7
  158. package/dist/migrations/registry.d.ts +26 -0
  159. package/dist/migrations/registry.d.ts.map +1 -1
  160. package/dist/migrations/registry.js +38 -7
  161. package/dist/migrations/retained.js +2 -2
  162. package/dist/migrations/runner.d.ts +76 -5
  163. package/dist/migrations/runner.d.ts.map +1 -1
  164. package/dist/migrations/runner.js +130 -19
  165. package/dist/migrations/state.d.ts +60 -0
  166. package/dist/migrations/state.d.ts.map +1 -0
  167. package/dist/migrations/state.js +46 -0
  168. package/dist/naming/domains.d.ts +17 -0
  169. package/dist/naming/domains.d.ts.map +1 -1
  170. package/dist/naming/domains.js +62 -4
  171. package/dist/naming/environment.d.ts.map +1 -1
  172. package/dist/naming/environment.js +2 -1
  173. package/dist/naming/feature.d.ts +27 -5
  174. package/dist/naming/feature.d.ts.map +1 -1
  175. package/dist/naming/feature.js +36 -6
  176. package/dist/naming/limits.d.ts +47 -3
  177. package/dist/naming/limits.d.ts.map +1 -1
  178. package/dist/naming/limits.js +47 -3
  179. package/dist/naming/packageName.d.ts +17 -0
  180. package/dist/naming/packageName.d.ts.map +1 -0
  181. package/dist/naming/packageName.js +22 -0
  182. package/dist/naming/provisionScope.d.ts +6 -0
  183. package/dist/naming/provisionScope.d.ts.map +1 -1
  184. package/dist/naming/provisionScope.js +10 -4
  185. package/dist/naming/resourceNames.d.ts +21 -2
  186. package/dist/naming/resourceNames.d.ts.map +1 -1
  187. package/dist/naming/resourceNames.js +21 -3
  188. package/dist/openapi/document.d.ts +106 -0
  189. package/dist/openapi/document.d.ts.map +1 -0
  190. package/dist/openapi/document.js +314 -0
  191. package/dist/openapi/routeGroups.d.ts +8 -0
  192. package/dist/openapi/routeGroups.d.ts.map +1 -0
  193. package/dist/openapi/routeGroups.js +23 -0
  194. package/dist/seed/writeD1.d.ts +7 -1
  195. package/dist/seed/writeD1.d.ts.map +1 -1
  196. package/dist/seed/writeD1.js +9 -3
  197. package/dist/seed/writeKv.d.ts +2 -0
  198. package/dist/seed/writeKv.d.ts.map +1 -1
  199. package/dist/seed/writeKv.js +6 -2
  200. package/dist/text/comments.js +66 -4
  201. package/dist/text/literals.d.ts +43 -0
  202. package/dist/text/literals.d.ts.map +1 -0
  203. package/dist/text/literals.js +293 -0
  204. package/dist/version.generated.d.ts +1 -1
  205. package/dist/version.generated.d.ts.map +1 -1
  206. package/dist/version.generated.js +1 -1
  207. package/dist/worker/serviceLoopback.d.ts +36 -0
  208. package/dist/worker/serviceLoopback.d.ts.map +1 -0
  209. package/dist/worker/serviceLoopback.js +74 -0
  210. package/dist/workflow/dispatchRoute.d.ts.map +1 -1
  211. package/dist/workflow/dispatchRoute.js +12 -6
  212. package/dist/workflow/faults.d.ts +12 -1
  213. package/dist/workflow/faults.d.ts.map +1 -1
  214. package/dist/workflow/faults.js +24 -18
  215. package/dist/workflow/hostEnv.d.ts +1 -0
  216. package/dist/workflow/hostEnv.d.ts.map +1 -1
  217. package/dist/workflow/hostEnv.js +4 -2
  218. package/dist/workflow/loopback.d.ts.map +1 -1
  219. package/dist/workflow/loopback.js +2 -1
  220. package/package.json +4 -4
  221. package/src/access/access.ts +298 -0
  222. package/src/access/acting.ts +59 -0
  223. package/src/access/policyCheck.ts +77 -0
  224. package/src/access/usage.ts +141 -0
  225. package/src/access/visibility.ts +109 -0
  226. package/src/asyncapi/document.ts +164 -0
  227. package/src/audit/auditEvent.ts +4 -0
  228. package/src/capability/bindings.ts +159 -13
  229. package/src/capability/capability.ts +106 -29
  230. package/src/capability/composition.ts +2 -1
  231. package/src/capability/settings.ts +165 -4
  232. package/src/cli/command.ts +865 -0
  233. package/src/cli/commandCatalog.generated.ts +2723 -0
  234. package/src/cli/commandFacts.ts +220 -0
  235. package/src/controlPlane/capability.ts +25 -1
  236. package/src/controlPlane/context.ts +4 -0
  237. package/src/controlPlane/data/connection.ts +90 -0
  238. package/src/controlPlane/error/errors.ts +10 -3
  239. package/src/controlPlane/http/cors.ts +4 -4
  240. package/src/controlPlane/http/guard.ts +35 -2
  241. package/src/controlPlane/http/handlers.ts +41 -0
  242. package/src/controlPlane/http/readiness.ts +50 -0
  243. package/src/controlPlane/http/responses.ts +140 -2
  244. package/src/controlPlane/http/routes.ts +82 -10
  245. package/src/controlPlane/http/verify.ts +2 -0
  246. package/src/controlPlane/migrationState/migrationState.ts +200 -0
  247. package/src/controlPlane/migrations/0003_connection_principal.ts +37 -0
  248. package/src/controlPlane/scope/scope.ts +14 -2
  249. package/src/createBackend.ts +59 -8
  250. package/src/createEntrypoint.ts +9 -3
  251. package/src/entitlement/allowance.ts +85 -0
  252. package/src/entitlement/entitlement.ts +38 -0
  253. package/src/entitlement/meter.ts +69 -0
  254. package/src/entitlement/require.ts +1 -1
  255. package/src/error/cause.ts +18 -181
  256. package/src/error/payload.ts +270 -4
  257. package/src/error/pithyError.ts +76 -0
  258. package/src/error/unresolved.ts +853 -0
  259. package/src/error/wire.ts +40 -0
  260. package/src/http/authContext.ts +13 -1
  261. package/src/http/oidcWebhook.ts +3 -3
  262. package/src/http/routeContract.ts +1 -1
  263. package/src/http/routeSpec.ts +81 -0
  264. package/src/http/sameOrigin.ts +1 -1
  265. package/src/http/scopeGates.ts +34 -0
  266. package/src/http/signedWebhook.ts +3 -3
  267. package/src/http/socket.ts +55 -0
  268. package/src/http/subprotocol.ts +47 -0
  269. package/src/http/validation.ts +50 -8
  270. package/src/index.ts +1 -0
  271. package/src/migrations/bookkeeping.ts +39 -2
  272. package/src/migrations/capabilitySets.ts +87 -0
  273. package/src/migrations/groups.ts +295 -0
  274. package/src/migrations/migrateStep.ts +19 -0
  275. package/src/migrations/owner.ts +10 -6
  276. package/src/migrations/registry.ts +46 -2
  277. package/src/migrations/retained.ts +2 -2
  278. package/src/migrations/runner.ts +214 -22
  279. package/src/migrations/state.ts +94 -0
  280. package/src/naming/domains.ts +75 -16
  281. package/src/naming/environment.ts +2 -1
  282. package/src/naming/feature.ts +46 -7
  283. package/src/naming/limits.ts +35 -3
  284. package/src/naming/packageName.ts +20 -0
  285. package/src/naming/provisionScope.ts +21 -2
  286. package/src/naming/resourceNames.ts +52 -5
  287. package/src/openapi/document.ts +412 -0
  288. package/src/openapi/routeGroups.ts +25 -0
  289. package/src/seed/writeD1.ts +13 -4
  290. package/src/seed/writeKv.ts +6 -2
  291. package/src/text/comments.ts +56 -4
  292. package/src/text/literals.ts +294 -0
  293. package/src/version.generated.ts +1 -1
  294. package/src/worker/serviceLoopback.ts +105 -0
  295. package/src/workflow/dispatchRoute.ts +13 -6
  296. package/src/workflow/faults.ts +56 -27
  297. package/src/workflow/hostEnv.ts +9 -1
  298. package/src/workflow/loopback.ts +2 -1
@@ -0,0 +1,164 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ /**
4
+ * **What the catalog cannot say about a `pithy` command, written down once (#711).**
5
+ *
6
+ * `commandCatalog.generated.ts` is the parser's own account of every command: its arguments, its flags, which
7
+ * are required, which have defaults, which go together. Four facts are not in any parser, and each was the
8
+ * fault behind a line that did not run as written:
9
+ *
10
+ * - **Which commands act on one Worker**, and are refused `input/required` without `--worker` where a project
11
+ * has several. `packages/cli/src/ci/runnableCommands.test.ts` proves every entry by running it in a
12
+ * two-Worker project, and fails on a command that takes `--worker` and is not classified here.
13
+ * - **Which flag's default changes what the command acts on.** `pithy vector provision` with no `--env`
14
+ * provisions `dev`, so a line about staging that leaves it off sends the reader to the wrong environment.
15
+ * - **Which commands destroy something**, and are never a remedy for a smaller fault. `pithy feature destroy`
16
+ * was offered as the fix for one mis-shaped vector index.
17
+ * - **Which flag needs another beside it** that the parser does not enforce: `pithy provision --env` is refused
18
+ * without `--yes`, at run time.
19
+ *
20
+ * `command.ts` builds every command a line names from these and the catalog, and refuses one that breaks them.
21
+ * Nothing here imports anything, so a Worker that names a command pays for two tables and nothing more.
22
+ */
23
+ /**
24
+ * The commands that act on exactly one Worker, and refuse `input/required` without `--worker` when a project
25
+ * has several and the run cannot ask. Every line that names one names the Worker, by its `apps/` directory.
26
+ */
27
+ export declare const WORKER_SCOPED: readonly ["add", "dashboard connect", "email provision", "media provision", "payments provision", "storage provision", "support provision", "testers provision", "turnstile deprovision", "turnstile provision", "ui add", "ui sync", "vector provision", "vector reprocess", "vector reset", "worker sync"];
28
+ /** A command that acts on one Worker. */
29
+ export type WorkerScopedPath = (typeof WORKER_SCOPED)[number];
30
+ /**
31
+ * The commands that take `--worker` and do not need it: each fans out over every Worker, or falls back to the
32
+ * first that answers, and the flag narrows.
33
+ */
34
+ export declare const WORKER_NARROWS: readonly ["contract", "dashboard disconnect", "dashboard revoke-key", "dashboard rotate", "dashboard status", "doctor", "env", "init", "migrate", "secrets tables", "seed", "support deprovision", "upgrade"];
35
+ /**
36
+ * A command only a person runs, at a terminal, where the Worker is asked for. `pithy remove` refuses every run
37
+ * that cannot ask (`core/person_required`).
38
+ */
39
+ export declare const PERSON_ONLY: readonly ["remove"];
40
+ /** A flag that turns a Worker-scoped command into one that acts on no Worker: `pithy add --list` reads the catalog. */
41
+ export declare const NO_WORKER_MODES: Readonly<Record<string, readonly string[]>>;
42
+ /**
43
+ * **A flag whose default decides what the command acts on.** Left off a line, the command still runs — on the
44
+ * default, which is rarely the environment the line was about. Every `--env` with a default is one: `dev` for
45
+ * `vector provision`, `migrate` and `testers list`, `staging` for `payments reconcile`. A line names it, always.
46
+ */
47
+ export declare const MEANING_FLAGS: readonly ["--env"];
48
+ /**
49
+ * The commands whose `--env` decides nothing until another flag asks it to: `pithy remove` touches no database
50
+ * without `--drop`, and `pithy upgrade` migrates none without `--migrate`. Without that flag a line need not
51
+ * name the environment; with it, it must.
52
+ */
53
+ export declare const MEANING_ONLY_WITH: {
54
+ readonly remove: "--drop";
55
+ readonly upgrade: "--migrate";
56
+ };
57
+ /**
58
+ * **The commands that destroy something, by what they destroy.** None is ever built as a remedy: a line that
59
+ * names one says it is a person's decision and what it deletes (`command.ts`'s `personDecision`), and carries
60
+ * no `fix`. `packages/core/src/cli/command.test.ts` holds every command the catalog has to this list or to
61
+ * {@link NOT_DESTRUCTIVE}, so a new one cannot arrive unexamined.
62
+ */
63
+ export declare const DESTRUCTIVE_COMMANDS: {
64
+ readonly "dashboard disconnect": "the environment's dashboard connection and the key it signs with";
65
+ readonly "dashboard revoke-key": "a signing key the dashboard holds";
66
+ readonly "email deprovision": "the email Workers, and with --suppression the suppression database";
67
+ readonly "feature destroy": "the feature's worktree, its branch and every resource it provisioned";
68
+ readonly "media deprovision": "the media Worker, and with --storage its bucket";
69
+ readonly remove: "a capability's wiring";
70
+ readonly "secrets deprovision": "the secrets manager, and with --keys the store's keys";
71
+ readonly "secrets rm": "a stored secret";
72
+ readonly "storage deprovision": "the storage Worker, and with --storage its bucket";
73
+ readonly "support deprovision": "the support Workers, and with --storage its attachments";
74
+ readonly "testers deprovision": "the testers Worker";
75
+ readonly "token revoke": "an API token";
76
+ readonly "turnstile deprovision": "the Turnstile widget, whose sitekey every client embeds";
77
+ readonly "vector reset": "every vector in the index";
78
+ readonly "worker remove": "a Worker's directory";
79
+ };
80
+ /** A command that destroys something. */
81
+ export type DestructivePath = keyof typeof DESTRUCTIVE_COMMANDS;
82
+ /**
83
+ * **The flags that make a command destroy something**, on any command that declares them. Each is refused by
84
+ * the builder; a line that needs one is a person's decision.
85
+ */
86
+ export declare const DESTRUCTIVE_FLAGS: {
87
+ readonly "--destroy-retained": "a resource kept for recovery";
88
+ readonly "--drop": "a capability's tables";
89
+ readonly "--redo": "the data a seed wrote";
90
+ readonly "--rollback": "the schema a migration group applied";
91
+ };
92
+ /** A flag that makes a command destroy something. */
93
+ export type DestructiveFlag = keyof typeof DESTRUCTIVE_FLAGS;
94
+ /**
95
+ * The commands whose name reads as destructive and which are not, and why. A command named here is built like
96
+ * any other.
97
+ */
98
+ export declare const NOT_DESTRUCTIVE: Readonly<Record<string, string>>;
99
+ /**
100
+ * **A flag whose value is a person's confirmation**, never written into a line an agent reads: a phrase spelled
101
+ * in a remedy is a confirmation nobody gave. A person's decision names the flag and leaves the phrase to them.
102
+ */
103
+ export declare const CONFIRM_FLAGS: readonly ["--confirm", "--confirm-production", "--confirm-reset", "--confirm-rollback"];
104
+ /**
105
+ * When a command asks for a confirmation: always, when a flag is passed (`when`), or in every environment but the
106
+ * ones it trusts (`unlessEnv`) — `vector reset` asks nothing of `dev`, whose index is a laptop's.
107
+ */
108
+ export declare const CONFIRMATIONS: readonly {
109
+ path: string;
110
+ when?: string;
111
+ unlessEnv?: readonly string[];
112
+ flag: string;
113
+ }[];
114
+ /**
115
+ * **A flag whose value is a credential**, never written into a line: an error's action reaches logs, a terminal
116
+ * scrollback and a `--json` consumer, none of which should hold a key. A run named again carries the flag's name
117
+ * and leaves its value to whoever passed it.
118
+ */
119
+ export declare const CREDENTIAL_FLAGS: readonly ["--api-token", "--r2-access-key-id", "--r2-api-token", "--r2-secret-access-key"];
120
+ /**
121
+ * The environments every project treats as production. A project can name more in `seed.productionEnvironments`;
122
+ * a builder that has them passes them.
123
+ */
124
+ export declare const PRODUCTION_ENVIRONMENTS: readonly ["prod", "production"];
125
+ /**
126
+ * **What a production run of a command needs from a person**, by command: the confirmation it asks for, or `null`
127
+ * for one that asks none. A production provision or seed is never a remedy — a line names it as a person's
128
+ * decision either way, and names a confirmation only when the command declares it: `testers provision` and
129
+ * `vector provision` take no `--confirm`, and a line that told a person to pass one would be refused.
130
+ */
131
+ export declare const PRODUCTION_CONFIRMS: {
132
+ readonly provision: "--confirm";
133
+ readonly seed: "--confirm-production";
134
+ readonly "secrets provision": null;
135
+ readonly "testers provision": null;
136
+ readonly "vector provision": null;
137
+ };
138
+ /** A command whose production run is a person's decision. */
139
+ export type ProductionPath = keyof typeof PRODUCTION_CONFIRMS;
140
+ /**
141
+ * **A command that acts on every environment when its `--env` is left off (#711)**, production among them. `pithy
142
+ * testers provision` with no `--env` provisions every declared environment, so the bare line touches production as
143
+ * surely as `--env prod` does, and is a person's decision for the same reason. Each declares `--env` with no
144
+ * default; `command.test.ts` holds that against the catalog.
145
+ */
146
+ export declare const EVERY_ENVIRONMENT_WITHOUT_ENV: readonly ["testers provision"];
147
+ /**
148
+ * **A command that acts on every environment on every run (#711)**, production among them, with no `--env` to narrow
149
+ * it. `pithy secrets provision` deploys each declared environment's manager and mints its store entries, so every line
150
+ * naming it touches production and is a person's decision — never the fix for one binding, one database or one
151
+ * setting. None declares `--env`; `command.test.ts` holds that against the catalog.
152
+ */
153
+ export declare const EVERY_ENVIRONMENT_ALWAYS: readonly ["secrets provision"];
154
+ /**
155
+ * A flag a command refuses to run without, beside another, that the parser does not enforce. `pithy provision
156
+ * --env <env>` with no `--yes` is refused before it does anything; a dry run needs neither.
157
+ */
158
+ export declare const REQUIRED_BESIDE: readonly {
159
+ path: string;
160
+ with: string;
161
+ needs: string;
162
+ unless: string;
163
+ }[];
164
+ //# sourceMappingURL=commandFacts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commandFacts.d.ts","sourceRoot":"","sources":["../../src/cli/commandFacts.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;GAGG;AACH,eAAO,MAAM,aAAa,YACxB,KAAK,EACL,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,qBAAqB,EACrB,QAAQ,EACR,SAAS,EACT,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,aAAa,CACL,CAAC;AAEX,yCAAyC;AACzC,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9D;;;GAGG;AACH,eAAO,MAAM,cAAc,YACzB,UAAU,EACV,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,QAAQ,EACR,KAAK,EACL,MAAM,EACN,SAAS,EACT,gBAAgB,EAChB,MAAM,EACN,qBAAqB,EACrB,SAAS,CACD,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,WAAW,YAAI,QAAQ,CAAU,CAAC;AAE/C,uHAAuH;AACvH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAuB,CAAC;AAEhG;;;;GAIG;AACH,eAAO,MAAM,aAAa,YAAI,OAAO,CAAU,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;aAAK,MAAM,EAAE,QAAQ;aAAE,OAAO,EAAE,WAAW;CAAW,CAAC;AAErF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;aAC/B,sBAAsB,EAAE,kEAAkE;aAC1F,sBAAsB,EAAE,mCAAmC;aAC3D,mBAAmB,EAAE,oEAAoE;aACzF,iBAAiB,EAAE,sEAAsE;aACzF,mBAAmB,EAAE,iDAAiD;aACtE,MAAM,EAAE,uBAAuB;aAC/B,qBAAqB,EAAE,uDAAuD;aAC9E,YAAY,EAAE,iBAAiB;aAC/B,qBAAqB,EAAE,mDAAmD;aAC1E,qBAAqB,EAAE,yDAAyD;aAChF,qBAAqB,EAAE,oBAAoB;aAC3C,cAAc,EAAE,cAAc;aAC9B,uBAAuB,EAAE,yDAAyD;aAClF,cAAc,EAAE,2BAA2B;aAC3C,eAAe,EAAE,sBAAsB;CAC/B,CAAC;AAEX,yCAAyC;AACzC,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,oBAAoB,CAAC;AAEhE;;;GAGG;AACH,eAAO,MAAM,iBAAiB;aAC5B,oBAAoB,EAAE,8BAA8B;aACpD,QAAQ,EAAE,uBAAuB;aACjC,QAAQ,EAAE,uBAAuB;aACjC,YAAY,EAAE,sCAAsC;CAC5C,CAAC;AAEX,qDAAqD;AACrD,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,iBAAiB,CAAC;AAE7D;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAM5D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,YAAI,WAAW,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,oBAAoB,CAAU,CAAC;AAErH;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAIhH,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,YAC3B,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,CAChB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,uBAAuB,YAAI,MAAM,EAAE,YAAY,CAAU,CAAC;AAEvE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB;wBACnB,WAAW;mBAChB,sBAAsB;;;;CAI8B,CAAC;AAE7D,6DAA6D;AAC7D,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,mBAAmB,CAAC;AAE9D;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,gCAAqE,CAAC;AAEhH;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,gCAAqE,CAAC;AAE3G;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAEnG,CAAC"}
@@ -0,0 +1,216 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ //#region src/cli/commandFacts.ts
4
+ /**
5
+ * **What the catalog cannot say about a `pithy` command, written down once (#711).**
6
+ *
7
+ * `commandCatalog.generated.ts` is the parser's own account of every command: its arguments, its flags, which
8
+ * are required, which have defaults, which go together. Four facts are not in any parser, and each was the
9
+ * fault behind a line that did not run as written:
10
+ *
11
+ * - **Which commands act on one Worker**, and are refused `input/required` without `--worker` where a project
12
+ * has several. `packages/cli/src/ci/runnableCommands.test.ts` proves every entry by running it in a
13
+ * two-Worker project, and fails on a command that takes `--worker` and is not classified here.
14
+ * - **Which flag's default changes what the command acts on.** `pithy vector provision` with no `--env`
15
+ * provisions `dev`, so a line about staging that leaves it off sends the reader to the wrong environment.
16
+ * - **Which commands destroy something**, and are never a remedy for a smaller fault. `pithy feature destroy`
17
+ * was offered as the fix for one mis-shaped vector index.
18
+ * - **Which flag needs another beside it** that the parser does not enforce: `pithy provision --env` is refused
19
+ * without `--yes`, at run time.
20
+ *
21
+ * `command.ts` builds every command a line names from these and the catalog, and refuses one that breaks them.
22
+ * Nothing here imports anything, so a Worker that names a command pays for two tables and nothing more.
23
+ */
24
+ /**
25
+ * The commands that act on exactly one Worker, and refuse `input/required` without `--worker` when a project
26
+ * has several and the run cannot ask. Every line that names one names the Worker, by its `apps/` directory.
27
+ */
28
+ const WORKER_SCOPED = [
29
+ "add",
30
+ "dashboard connect",
31
+ "email provision",
32
+ "media provision",
33
+ "payments provision",
34
+ "storage provision",
35
+ "support provision",
36
+ "testers provision",
37
+ "turnstile deprovision",
38
+ "turnstile provision",
39
+ "ui add",
40
+ "ui sync",
41
+ "vector provision",
42
+ "vector reprocess",
43
+ "vector reset",
44
+ "worker sync"
45
+ ];
46
+ /**
47
+ * The commands that take `--worker` and do not need it: each fans out over every Worker, or falls back to the
48
+ * first that answers, and the flag narrows.
49
+ */
50
+ const WORKER_NARROWS = [
51
+ "contract",
52
+ "dashboard disconnect",
53
+ "dashboard revoke-key",
54
+ "dashboard rotate",
55
+ "dashboard status",
56
+ "doctor",
57
+ "env",
58
+ "init",
59
+ "migrate",
60
+ "secrets tables",
61
+ "seed",
62
+ "support deprovision",
63
+ "upgrade"
64
+ ];
65
+ /**
66
+ * A command only a person runs, at a terminal, where the Worker is asked for. `pithy remove` refuses every run
67
+ * that cannot ask (`core/person_required`).
68
+ */
69
+ const PERSON_ONLY = ["remove"];
70
+ /** A flag that turns a Worker-scoped command into one that acts on no Worker: `pithy add --list` reads the catalog. */
71
+ const NO_WORKER_MODES = { add: ["--list"] };
72
+ /**
73
+ * **A flag whose default decides what the command acts on.** Left off a line, the command still runs — on the
74
+ * default, which is rarely the environment the line was about. Every `--env` with a default is one: `dev` for
75
+ * `vector provision`, `migrate` and `testers list`, `staging` for `payments reconcile`. A line names it, always.
76
+ */
77
+ const MEANING_FLAGS = ["--env"];
78
+ /**
79
+ * The commands whose `--env` decides nothing until another flag asks it to: `pithy remove` touches no database
80
+ * without `--drop`, and `pithy upgrade` migrates none without `--migrate`. Without that flag a line need not
81
+ * name the environment; with it, it must.
82
+ */
83
+ const MEANING_ONLY_WITH = {
84
+ remove: "--drop",
85
+ upgrade: "--migrate"
86
+ };
87
+ /**
88
+ * **The commands that destroy something, by what they destroy.** None is ever built as a remedy: a line that
89
+ * names one says it is a person's decision and what it deletes (`command.ts`'s `personDecision`), and carries
90
+ * no `fix`. `packages/core/src/cli/command.test.ts` holds every command the catalog has to this list or to
91
+ * {@link NOT_DESTRUCTIVE}, so a new one cannot arrive unexamined.
92
+ */
93
+ const DESTRUCTIVE_COMMANDS = {
94
+ "dashboard disconnect": "the environment's dashboard connection and the key it signs with",
95
+ "dashboard revoke-key": "a signing key the dashboard holds",
96
+ "email deprovision": "the email Workers, and with --suppression the suppression database",
97
+ "feature destroy": "the feature's worktree, its branch and every resource it provisioned",
98
+ "media deprovision": "the media Worker, and with --storage its bucket",
99
+ remove: "a capability's wiring",
100
+ "secrets deprovision": "the secrets manager, and with --keys the store's keys",
101
+ "secrets rm": "a stored secret",
102
+ "storage deprovision": "the storage Worker, and with --storage its bucket",
103
+ "support deprovision": "the support Workers, and with --storage its attachments",
104
+ "testers deprovision": "the testers Worker",
105
+ "token revoke": "an API token",
106
+ "turnstile deprovision": "the Turnstile widget, whose sitekey every client embeds",
107
+ "vector reset": "every vector in the index",
108
+ "worker remove": "a Worker's directory"
109
+ };
110
+ /**
111
+ * **The flags that make a command destroy something**, on any command that declares them. Each is refused by
112
+ * the builder; a line that needs one is a person's decision.
113
+ */
114
+ const DESTRUCTIVE_FLAGS = {
115
+ "--destroy-retained": "a resource kept for recovery",
116
+ "--drop": "a capability's tables",
117
+ "--redo": "the data a seed wrote",
118
+ "--rollback": "the schema a migration group applied"
119
+ };
120
+ /**
121
+ * The commands whose name reads as destructive and which are not, and why. A command named here is built like
122
+ * any other.
123
+ */
124
+ const NOT_DESTRUCTIVE = {
125
+ "cloudflare disconnect": "revokes a sign-in and deletes no data, which `cloudflare connect` gives back",
126
+ "docs disconnect": "removes the docs server from an editor's config, which `docs connect` restores",
127
+ "feature prune": "forgets worktrees that are already gone",
128
+ "testers close": "stops a cohort accruing, and keeps its history",
129
+ "testers remove": "takes one tester off a roster, which `testers invite` reverses"
130
+ };
131
+ /**
132
+ * **A flag whose value is a person's confirmation**, never written into a line an agent reads: a phrase spelled
133
+ * in a remedy is a confirmation nobody gave. A person's decision names the flag and leaves the phrase to them.
134
+ */
135
+ const CONFIRM_FLAGS = [
136
+ "--confirm",
137
+ "--confirm-production",
138
+ "--confirm-reset",
139
+ "--confirm-rollback"
140
+ ];
141
+ /**
142
+ * When a command asks for a confirmation: always, when a flag is passed (`when`), or in every environment but the
143
+ * ones it trusts (`unlessEnv`) — `vector reset` asks nothing of `dev`, whose index is a laptop's.
144
+ */
145
+ const CONFIRMATIONS = [
146
+ {
147
+ path: "vector reset",
148
+ unlessEnv: ["dev"],
149
+ flag: "--confirm-reset"
150
+ },
151
+ {
152
+ path: "migrate",
153
+ when: "--rollback",
154
+ flag: "--confirm-rollback"
155
+ },
156
+ {
157
+ path: "seed",
158
+ when: "--redo",
159
+ flag: "--confirm-reset"
160
+ }
161
+ ];
162
+ /**
163
+ * **A flag whose value is a credential**, never written into a line: an error's action reaches logs, a terminal
164
+ * scrollback and a `--json` consumer, none of which should hold a key. A run named again carries the flag's name
165
+ * and leaves its value to whoever passed it.
166
+ */
167
+ const CREDENTIAL_FLAGS = [
168
+ "--api-token",
169
+ "--r2-access-key-id",
170
+ "--r2-api-token",
171
+ "--r2-secret-access-key"
172
+ ];
173
+ /**
174
+ * The environments every project treats as production. A project can name more in `seed.productionEnvironments`;
175
+ * a builder that has them passes them.
176
+ */
177
+ const PRODUCTION_ENVIRONMENTS = ["prod", "production"];
178
+ /**
179
+ * **What a production run of a command needs from a person**, by command: the confirmation it asks for, or `null`
180
+ * for one that asks none. A production provision or seed is never a remedy — a line names it as a person's
181
+ * decision either way, and names a confirmation only when the command declares it: `testers provision` and
182
+ * `vector provision` take no `--confirm`, and a line that told a person to pass one would be refused.
183
+ */
184
+ const PRODUCTION_CONFIRMS = {
185
+ provision: "--confirm",
186
+ seed: "--confirm-production",
187
+ "secrets provision": null,
188
+ "testers provision": null,
189
+ "vector provision": null
190
+ };
191
+ /**
192
+ * **A command that acts on every environment when its `--env` is left off (#711)**, production among them. `pithy
193
+ * testers provision` with no `--env` provisions every declared environment, so the bare line touches production as
194
+ * surely as `--env prod` does, and is a person's decision for the same reason. Each declares `--env` with no
195
+ * default; `command.test.ts` holds that against the catalog.
196
+ */
197
+ const EVERY_ENVIRONMENT_WITHOUT_ENV = ["testers provision"];
198
+ /**
199
+ * **A command that acts on every environment on every run (#711)**, production among them, with no `--env` to narrow
200
+ * it. `pithy secrets provision` deploys each declared environment's manager and mints its store entries, so every line
201
+ * naming it touches production and is a person's decision — never the fix for one binding, one database or one
202
+ * setting. None declares `--env`; `command.test.ts` holds that against the catalog.
203
+ */
204
+ const EVERY_ENVIRONMENT_ALWAYS = ["secrets provision"];
205
+ /**
206
+ * A flag a command refuses to run without, beside another, that the parser does not enforce. `pithy provision
207
+ * --env <env>` with no `--yes` is refused before it does anything; a dry run needs neither.
208
+ */
209
+ const REQUIRED_BESIDE = [{
210
+ path: "provision",
211
+ with: "--env",
212
+ needs: "--yes",
213
+ unless: "--dry-run"
214
+ }];
215
+ //#endregion
216
+ export { CONFIRMATIONS, CONFIRM_FLAGS, CREDENTIAL_FLAGS, DESTRUCTIVE_COMMANDS, DESTRUCTIVE_FLAGS, EVERY_ENVIRONMENT_ALWAYS, EVERY_ENVIRONMENT_WITHOUT_ENV, MEANING_FLAGS, MEANING_ONLY_WITH, NOT_DESTRUCTIVE, NO_WORKER_MODES, PERSON_ONLY, PRODUCTION_CONFIRMS, PRODUCTION_ENVIRONMENTS, REQUIRED_BESIDE, WORKER_NARROWS, WORKER_SCOPED };
@@ -1 +1 @@
1
- {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../../src/controlPlane/capability.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,UAAU,EAAuC,MAAM,0BAA0B,CAAC;AAChG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAc,MAAM,kBAAkB,CAAC;AAGvE,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAWnF,OAAO,EACL,wBAAwB,EAIzB,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,MAAM,MAAM,mBAAmB,GAAG,uBAAuB,CAAC;AAE1D,uEAAuE;AACvE,MAAM,WAAW,sBAAuB,SAAQ,UAAU,CAAC,eAAe,EAAE,kBAAkB,EAAE,cAAc,CAAC;IAC7G,gCAAgC;IAChC,kBAAkB,EAAE,kBAAkB,CAAC;CACxC;AAED,qGAAqG;AACrG,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,IAAI,sBAAsB,CAErG;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,sBAAsB,CAmKtF;AAED,4GAA4G;AAC5G,OAAO,EAAE,wBAAwB,EAAE,CAAC"}
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../../src/controlPlane/capability.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,UAAU,EAAuC,MAAM,0BAA0B,CAAC;AAChG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAc,MAAM,kBAAkB,CAAC;AAGvE,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAkBnF,OAAO,EACL,wBAAwB,EAIzB,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,MAAM,MAAM,mBAAmB,GAAG,uBAAuB,CAAC;AAE1D,uEAAuE;AACvE,MAAM,WAAW,sBAAuB,SAAQ,UAAU,CAAC,eAAe,EAAE,kBAAkB,EAAE,cAAc,CAAC;IAC7G,gCAAgC;IAChC,kBAAkB,EAAE,kBAAkB,CAAC;CACxC;AAED,qGAAqG;AACrG,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,IAAI,sBAAsB,CAErG;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,sBAAsB,CAoLtF;AAED,4GAA4G;AAC5G,OAAO,EAAE,wBAAwB,EAAE,CAAC"}
@@ -6,11 +6,13 @@ import "../worker/identity.js";
6
6
  import { ControlPlaneConfig } from "./config/config.js";
7
7
  import { ControlPlaneConnection } from "./data/connection.js";
8
8
  import { CONTROL_PLANE_CONNECTIONS_TABLE, controlPlaneTables } from "./data/tables.js";
9
- import { capabilityHealthSources } from "./discovery/health.js";
9
+ import { capabilityHealthSources, defineCapabilityHealth } from "./discovery/health.js";
10
10
  import { createControlPlaneVerifier } from "./http/guard.js";
11
+ import { MIGRATION_HEALTH_KEYS, composeMigrationDatabases, readMigrationHealth } from "./migrationState/migrationState.js";
11
12
  import { controlPlaneRouteDescriptors, registerControlPlaneRoutes } from "./http/routes.js";
12
13
  import { controlplane_0001_init } from "./migrations/0001_init.js";
13
14
  import { controlplane_0002_management_origin } from "./migrations/0002_management_origin.js";
15
+ import { controlplane_0003_connection_principal } from "./migrations/0003_connection_principal.js";
14
16
  import { d1ReplayGuard } from "./replay/d1Guard.js";
15
17
  import { CONTROL_PLANE_KV_BINDING, controlPlaneKvNamespaces, kvReplayGuard } from "./replay/kvGuard.js";
16
18
  //#region src/controlPlane/capability.ts
@@ -52,7 +54,8 @@ function controlplane(options = {}) {
52
54
  const config = ControlPlaneConfig.parse(options);
53
55
  const migrations = {
54
56
  "0001_init": controlplane_0001_init,
55
- "0002_management_origin": controlplane_0002_management_origin
57
+ "0002_management_origin": controlplane_0002_management_origin,
58
+ "0003_connection_principal": controlplane_0003_connection_principal
56
59
  };
57
60
  const requiredBindings = [{
58
61
  type: "d1",
@@ -83,6 +86,7 @@ function controlplane(options = {}) {
83
86
  });
84
87
  let composed = [];
85
88
  let health = /* @__PURE__ */ new Map();
89
+ let migrationDatabases = [];
86
90
  return {
87
91
  ...defineCapability({
88
92
  name: "controlplane",
@@ -98,6 +102,10 @@ function controlplane(options = {}) {
98
102
  } },
99
103
  kvNamespaces: usesKvReplay ? controlPlaneKvNamespaces(config.jtiTtlSeconds) : {},
100
104
  adminRoutes: controlPlaneRouteDescriptors(config.basePath),
105
+ health: defineCapabilityHealth({
106
+ keys: MIGRATION_HEALTH_KEYS,
107
+ read: (c) => readMigrationHealth(c.env, migrationDatabases)
108
+ }),
101
109
  compose: ({ capabilities }) => {
102
110
  composed = capabilities.map((cap) => ({
103
111
  name: cap.name,
@@ -109,6 +117,7 @@ function controlplane(options = {}) {
109
117
  config: { ...cap.manifestConfig?.values ?? {} }
110
118
  }));
111
119
  health = capabilityHealthSources(capabilities);
120
+ migrationDatabases = composeMigrationDatabases(capabilities);
112
121
  },
113
122
  middleware: [(app) => {
114
123
  app.use("*", async (c, next) => {
@@ -135,6 +144,7 @@ function controlplane(options = {}) {
135
144
  database,
136
145
  composedCapabilities: () => composed,
137
146
  composedHealth: () => health,
147
+ composedMigrations: () => migrationDatabases,
138
148
  now
139
149
  });
140
150
  }
@@ -24,6 +24,11 @@ export declare const ControlPlaneContext: z.ZodObject<{
24
24
  grantedScopes: z.ZodArray<z.ZodString>;
25
25
  keyId: z.ZodString;
26
26
  tokenId: z.ZodString;
27
+ actorKind: z.ZodNullable<z.ZodEnum<{
28
+ agent: "agent";
29
+ dashboard: "dashboard";
30
+ script: "script";
31
+ }>>;
27
32
  }, z.core.$strip>;
28
33
  export type ControlPlaneContext = z.output<typeof ControlPlaneContext>;
29
34
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/controlPlane/context.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;iBAyC7B,CAAC;AACJ,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/controlPlane/context.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;iBA4C7B,CAAC;AACJ,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
@@ -1,6 +1,7 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
3
  import { ControlPlaneScope } from "./scope/scope.js";
4
+ import { ControlPlaneActorKind } from "./data/connection.js";
4
5
  import { z } from "zod";
5
6
  //#region src/controlPlane/context.ts
6
7
  /**
@@ -25,7 +26,8 @@ const ControlPlaneContext = z.object({
25
26
  scope: ControlPlaneScope.describe("The single scope this token was minted for. One call, one operation — a token carrying the whole grant would make every call as dangerous as the most dangerous one."),
26
27
  grantedScopes: z.array(ControlPlaneScope).describe("Every scope the adopter granted this connection, read from their own row. The authority: a scope absent here is denied however the token is written."),
27
28
  keyId: z.string().describe("Which registered key verified this call. Recorded so a rotation can be traced through the trail, and so a key still in use is visible before it is expired."),
28
- tokenId: z.string().describe("The token's `jti`, already claimed in the replay set. Recorded to tie one audit event to one call.")
29
+ tokenId: z.string().describe("The token's `jti`, already claimed in the replay set. Recorded to tie one audit event to one call."),
30
+ actorKind: ControlPlaneActorKind.nullable().describe("What kind of client the connection is for — `agent`, `dashboard` or `script` — read from the adopter's own row, never from the token. The gate stamps it onto every control-plane audit row this call writes. Null for a connection registered before the kind was recorded (#721).")
29
31
  }).describe("The verified control-plane caller for one request. Never an AuthContext: a management client is not a user of the adopter's app.");
30
32
  //#endregion
31
33
  export { ControlPlaneContext };
@@ -37,6 +37,46 @@ export declare const RegisteredKey: z.ZodObject<{
37
37
  revokedAt: z.ZodNullable<z.ZodCodec<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodDate]>, z.ZodDate>>;
38
38
  }, z.core.$strip>;
39
39
  export type RegisteredKey = z.output<typeof RegisteredKey>;
40
+ /**
41
+ * What kind of client a connection is for (#721): `agent`, `dashboard` or `script`.
42
+ *
43
+ * The audit trail's `actorType: "control-plane"` names all three identically, and the questions asked
44
+ * after an incident are exactly the ones that tell them apart — was it a person at the dashboard, a
45
+ * script somebody wrote, or an agent running unattended. So the kind is recorded on the connection when
46
+ * it is registered and stamped from there onto every row its calls write.
47
+ *
48
+ * It follows the path, never a guess: the device-code flow is a dashboard, always, and a key the
49
+ * operator registered themselves is whichever of the other two they say, out loud, with `--kind`.
50
+ */
51
+ export declare const ControlPlaneActorKind: z.ZodEnum<{
52
+ agent: "agent";
53
+ dashboard: "dashboard";
54
+ script: "script";
55
+ }>;
56
+ export type ControlPlaneActorKind = z.output<typeof ControlPlaneActorKind>;
57
+ /**
58
+ * Who sanctioned a connection: the email address of the signed-in Cloudflare session that registered it.
59
+ *
60
+ * **A plain string, deliberately not a reference.** An adopter's `pithy_auth_users` are their customers,
61
+ * and the operator who registers a connection is their staff, so a join into the organization model would
62
+ * be empty for most of them. A string is readable by anybody, and matchable against a directory where the
63
+ * operator is in one.
64
+ *
65
+ * **Derived, never asserted.** No flag supplies it; the CLI reads it from `GET /user` under the session.
66
+ */
67
+ export declare const ConnectionPrincipal: z.ZodEmail;
68
+ export type ConnectionPrincipal = z.output<typeof ConnectionPrincipal>;
69
+ /** The longest purpose a connection may carry. One line on a review screen, with room to say what it does. */
70
+ export declare const MAX_CONNECTION_PURPOSE = 200;
71
+ /**
72
+ * What a connection is for, in the words of whoever registered it (#721).
73
+ *
74
+ * **Required at registration, and refused when absent**, because a review listing credentials by key id
75
+ * cannot support the decision it exists for. **Untrusted input**: a customer writes it and something else
76
+ * renders it, so it is validated on the way in, and again on every read of the row.
77
+ */
78
+ export declare const ConnectionPurpose: z.ZodString;
79
+ export type ConnectionPurpose = z.output<typeof ConnectionPurpose>;
40
80
  /**
41
81
  * One management-client connection — the row in `pithy_controlplane_connections`.
42
82
  *
@@ -52,6 +92,13 @@ export declare const ControlPlaneConnection: z.ZodObject<{
52
92
  workerUrl: z.ZodURL;
53
93
  basePath: z.ZodDefault<z.ZodString>;
54
94
  managementOrigin: z.ZodDefault<z.ZodNullable<z.ZodURL>>;
95
+ authorizedBy: z.ZodDefault<z.ZodNullable<z.ZodEmail>>;
96
+ actorKind: z.ZodDefault<z.ZodNullable<z.ZodEnum<{
97
+ agent: "agent";
98
+ dashboard: "dashboard";
99
+ script: "script";
100
+ }>>>;
101
+ purpose: z.ZodDefault<z.ZodNullable<z.ZodString>>;
55
102
  scopes: z.ZodCodec<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodArray<z.ZodString>>;
56
103
  keys: z.ZodCodec<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodObject<{
57
104
  keyId: z.ZodString;
@@ -1 +1 @@
1
- {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/data/connection.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;;;;GASG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB;;;;iBAgBoF,CAAC;AAClH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEjE;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;iBAoBoF,CAAC;AAC/G,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAE3D;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmDhC,CAAC;AACJ,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC7E,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/data/connection.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;;;;GASG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB;;;;iBAgBoF,CAAC;AAClH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEjE;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;iBAoBoF,CAAC;AAC/G,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAE3D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB;;;;EAI/B,CAAC;AACJ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE3E;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,YAK7B,CAAC;AACJ,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEvE,8GAA8G;AAC9G,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAiB1C;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,aAW3B,CAAC;AACJ,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAEnE;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkEhC,CAAC;AACJ,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC7E,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
@@ -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 };
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/error/errors.ts"],"names":[],"mappings":"AAGA,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,EAY1E;CACF;AAED;;;GAGG;AACH,qBAAa,kCAAmC,SAAQ,UAAU;IAChE,YAAY,IAAI,GAAE,qBAA0B,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAY1E;CACF;AAED,sEAAsE;AACtE,qBAAa,kCAAmC,SAAQ,UAAU;IAChE,YAAY,IAAI,GAAE,qBAA0B,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAY1E;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;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"}