@pithy-sh/core 0.1.2 → 0.1.3

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 (393) hide show
  1. package/dist/address/address.d.ts +57 -0
  2. package/dist/address/address.d.ts.map +1 -0
  3. package/dist/address/address.js +71 -0
  4. package/dist/audit/auditEvent.d.ts +89 -0
  5. package/dist/audit/auditEvent.d.ts.map +1 -0
  6. package/dist/audit/auditEvent.js +69 -0
  7. package/dist/audit/recorder.d.ts +18 -0
  8. package/dist/audit/recorder.d.ts.map +1 -0
  9. package/dist/audit/recorder.js +8 -0
  10. package/dist/capability/bindings.d.ts +62 -0
  11. package/dist/capability/bindings.d.ts.map +1 -0
  12. package/dist/capability/bindings.js +97 -0
  13. package/dist/capability/capability.d.ts +501 -0
  14. package/dist/capability/capability.d.ts.map +1 -0
  15. package/dist/capability/capability.js +16 -0
  16. package/dist/capability/client.d.ts +70 -0
  17. package/dist/capability/client.d.ts.map +1 -0
  18. package/dist/capability/client.js +86 -0
  19. package/dist/capability/compose.d.ts +25 -0
  20. package/dist/capability/compose.d.ts.map +1 -0
  21. package/dist/capability/compose.js +54 -0
  22. package/dist/capability/composition.d.ts +26 -0
  23. package/dist/capability/composition.d.ts.map +1 -0
  24. package/dist/capability/composition.js +84 -0
  25. package/dist/capability/config.d.ts +7 -0
  26. package/dist/capability/config.d.ts.map +1 -0
  27. package/dist/capability/config.js +14 -0
  28. package/dist/capability/devSecret.d.ts +32 -0
  29. package/dist/capability/devSecret.d.ts.map +1 -0
  30. package/dist/capability/devSecret.js +28 -0
  31. package/dist/capability/manifest.d.ts +298 -0
  32. package/dist/capability/manifest.d.ts.map +1 -0
  33. package/dist/capability/manifest.js +356 -0
  34. package/dist/capability/secretOrigin.d.ts +121 -0
  35. package/dist/capability/secretOrigin.d.ts.map +1 -0
  36. package/dist/capability/secretOrigin.js +134 -0
  37. package/dist/capability/settings.d.ts +119 -0
  38. package/dist/capability/settings.d.ts.map +1 -0
  39. package/dist/capability/settings.js +66 -0
  40. package/dist/capability/validateBindings.d.ts +4 -0
  41. package/dist/capability/validateBindings.d.ts.map +1 -0
  42. package/dist/capability/validateBindings.js +34 -0
  43. package/dist/capability/vanishingKey.d.ts +31 -0
  44. package/dist/capability/vanishingKey.d.ts.map +1 -0
  45. package/dist/capability/vanishingKey.js +79 -0
  46. package/dist/controlPlane/audit/actions.d.ts +70 -0
  47. package/dist/controlPlane/audit/actions.d.ts.map +1 -0
  48. package/dist/controlPlane/audit/actions.js +76 -0
  49. package/dist/controlPlane/capability.d.ts +47 -0
  50. package/dist/controlPlane/capability.d.ts.map +1 -0
  51. package/dist/controlPlane/capability.js +138 -0
  52. package/dist/controlPlane/config/config.d.ts +19 -0
  53. package/dist/controlPlane/config/config.d.ts.map +1 -0
  54. package/dist/controlPlane/config/config.js +85 -0
  55. package/dist/controlPlane/context.d.ts +27 -0
  56. package/dist/controlPlane/context.d.ts.map +1 -0
  57. package/dist/controlPlane/context.js +29 -0
  58. package/dist/controlPlane/data/connection.d.ts +79 -0
  59. package/dist/controlPlane/data/connection.d.ts.map +1 -0
  60. package/dist/controlPlane/data/connection.js +55 -0
  61. package/dist/controlPlane/data/keyLifecycle.d.ts +62 -0
  62. package/dist/controlPlane/data/keyLifecycle.d.ts.map +1 -0
  63. package/dist/controlPlane/data/keyLifecycle.js +126 -0
  64. package/dist/controlPlane/data/replay.d.ts +18 -0
  65. package/dist/controlPlane/data/replay.d.ts.map +1 -0
  66. package/dist/controlPlane/data/replay.js +20 -0
  67. package/dist/controlPlane/data/tables.d.ts +34 -0
  68. package/dist/controlPlane/data/tables.d.ts.map +1 -0
  69. package/dist/controlPlane/data/tables.js +37 -0
  70. package/dist/controlPlane/discovery/adminRoute.d.ts +313 -0
  71. package/dist/controlPlane/discovery/adminRoute.d.ts.map +1 -0
  72. package/dist/controlPlane/discovery/adminRoute.js +136 -0
  73. package/dist/controlPlane/discovery/configuration.d.ts +108 -0
  74. package/dist/controlPlane/discovery/configuration.d.ts.map +1 -0
  75. package/dist/controlPlane/discovery/configuration.js +187 -0
  76. package/dist/controlPlane/discovery/drift.d.ts +64 -0
  77. package/dist/controlPlane/discovery/drift.d.ts.map +1 -0
  78. package/dist/controlPlane/discovery/drift.js +58 -0
  79. package/dist/controlPlane/discovery/health.d.ts +99 -0
  80. package/dist/controlPlane/discovery/health.d.ts.map +1 -0
  81. package/dist/controlPlane/discovery/health.js +151 -0
  82. package/dist/controlPlane/discovery/healthSummary.d.ts +236 -0
  83. package/dist/controlPlane/discovery/healthSummary.d.ts.map +1 -0
  84. package/dist/controlPlane/discovery/healthSummary.js +278 -0
  85. package/dist/controlPlane/error/errors.d.ts +67 -0
  86. package/dist/controlPlane/error/errors.d.ts.map +1 -0
  87. package/dist/controlPlane/error/errors.js +79 -0
  88. package/dist/controlPlane/http/cors.d.ts +112 -0
  89. package/dist/controlPlane/http/cors.d.ts.map +1 -0
  90. package/dist/controlPlane/http/cors.js +192 -0
  91. package/dist/controlPlane/http/guard.d.ts +77 -0
  92. package/dist/controlPlane/http/guard.d.ts.map +1 -0
  93. package/dist/controlPlane/http/guard.js +142 -0
  94. package/dist/controlPlane/http/handlers.d.ts +179 -0
  95. package/dist/controlPlane/http/handlers.d.ts.map +1 -0
  96. package/dist/controlPlane/http/handlers.js +245 -0
  97. package/dist/controlPlane/http/responses.d.ts +99 -0
  98. package/dist/controlPlane/http/responses.d.ts.map +1 -0
  99. package/dist/controlPlane/http/responses.js +63 -0
  100. package/dist/controlPlane/http/routes.d.ts +40 -0
  101. package/dist/controlPlane/http/routes.d.ts.map +1 -0
  102. package/dist/controlPlane/http/routes.js +83 -0
  103. package/dist/controlPlane/http/schemas.d.ts +39 -0
  104. package/dist/controlPlane/http/schemas.d.ts.map +1 -0
  105. package/dist/controlPlane/http/schemas.js +31 -0
  106. package/dist/controlPlane/http/verify.d.ts +84 -0
  107. package/dist/controlPlane/http/verify.d.ts.map +1 -0
  108. package/dist/controlPlane/http/verify.js +65 -0
  109. package/dist/controlPlane/migrations/0001_init.d.ts +51 -0
  110. package/dist/controlPlane/migrations/0001_init.d.ts.map +1 -0
  111. package/dist/controlPlane/migrations/0001_init.js +65 -0
  112. package/dist/controlPlane/replay/d1Guard.d.ts +29 -0
  113. package/dist/controlPlane/replay/d1Guard.d.ts.map +1 -0
  114. package/dist/controlPlane/replay/d1Guard.js +39 -0
  115. package/dist/controlPlane/replay/guard.d.ts +52 -0
  116. package/dist/controlPlane/replay/guard.d.ts.map +1 -0
  117. package/dist/controlPlane/replay/guard.js +0 -0
  118. package/dist/controlPlane/replay/kvGuard.d.ts +99 -0
  119. package/dist/controlPlane/replay/kvGuard.d.ts.map +1 -0
  120. package/dist/controlPlane/replay/kvGuard.js +101 -0
  121. package/dist/controlPlane/scope/scope.d.ts +68 -0
  122. package/dist/controlPlane/scope/scope.d.ts.map +1 -0
  123. package/dist/controlPlane/scope/scope.js +63 -0
  124. package/dist/controlPlane/token/base64url.d.ts +10 -0
  125. package/dist/controlPlane/token/base64url.d.ts.map +1 -0
  126. package/dist/controlPlane/token/base64url.js +48 -0
  127. package/dist/controlPlane/token/claims.d.ts +83 -0
  128. package/dist/controlPlane/token/claims.d.ts.map +1 -0
  129. package/dist/controlPlane/token/claims.js +86 -0
  130. package/dist/controlPlane/token/digest.d.ts +44 -0
  131. package/dist/controlPlane/token/digest.d.ts.map +1 -0
  132. package/dist/controlPlane/token/digest.js +56 -0
  133. package/dist/controlPlane/token/jws.d.ts +52 -0
  134. package/dist/controlPlane/token/jws.d.ts.map +1 -0
  135. package/dist/controlPlane/token/jws.js +65 -0
  136. package/dist/controlPlane/token/mint.d.ts +56 -0
  137. package/dist/controlPlane/token/mint.d.ts.map +1 -0
  138. package/dist/controlPlane/token/mint.js +55 -0
  139. package/dist/controlPlane/wire.d.ts +122 -0
  140. package/dist/controlPlane/wire.d.ts.map +1 -0
  141. package/dist/controlPlane/wire.js +123 -0
  142. package/dist/createBackend.d.ts +58 -0
  143. package/dist/createBackend.d.ts.map +1 -0
  144. package/dist/createBackend.js +170 -0
  145. package/dist/createEntrypoint.d.ts +53 -0
  146. package/dist/createEntrypoint.d.ts.map +1 -0
  147. package/dist/createEntrypoint.js +52 -0
  148. package/dist/data/boundParameters.d.ts +83 -0
  149. package/dist/data/boundParameters.d.ts.map +1 -0
  150. package/dist/data/boundParameters.js +162 -0
  151. package/dist/data/codecs.d.ts +34 -0
  152. package/dist/data/codecs.d.ts.map +1 -0
  153. package/dist/data/codecs.js +135 -0
  154. package/dist/data/cursor.d.ts +81 -0
  155. package/dist/data/cursor.d.ts.map +1 -0
  156. package/dist/data/cursor.js +104 -0
  157. package/dist/data/databases.d.ts +55 -0
  158. package/dist/data/databases.d.ts.map +1 -0
  159. package/dist/data/databases.js +32 -0
  160. package/dist/data/db.d.ts +42 -0
  161. package/dist/data/db.d.ts.map +1 -0
  162. package/dist/data/db.js +24 -0
  163. package/dist/data/withD1Retry.d.ts +91 -0
  164. package/dist/data/withD1Retry.d.ts.map +1 -0
  165. package/dist/data/withD1Retry.js +152 -0
  166. package/dist/entitlement/entitlement.d.ts +118 -0
  167. package/dist/entitlement/entitlement.d.ts.map +1 -0
  168. package/dist/entitlement/entitlement.js +59 -0
  169. package/dist/entitlement/gateScan.d.ts +26 -0
  170. package/dist/entitlement/gateScan.d.ts.map +1 -0
  171. package/dist/entitlement/gateScan.js +96 -0
  172. package/dist/entitlement/require.d.ts +12 -0
  173. package/dist/entitlement/require.d.ts.map +1 -0
  174. package/dist/entitlement/require.js +123 -0
  175. package/dist/env/ambient.d.ts +52 -0
  176. package/dist/env/ambient.d.ts.map +1 -0
  177. package/dist/env/ambient.js +35 -0
  178. package/dist/env/ci.d.ts +36 -0
  179. package/dist/env/ci.d.ts.map +1 -0
  180. package/dist/env/ci.js +40 -0
  181. package/dist/env/stem.d.ts +23 -0
  182. package/dist/env/stem.d.ts.map +1 -0
  183. package/dist/env/stem.js +29 -0
  184. package/dist/error/cause.d.ts +143 -0
  185. package/dist/error/cause.d.ts.map +1 -0
  186. package/dist/error/cause.js +192 -0
  187. package/dist/error/client.d.ts +35 -0
  188. package/dist/error/client.d.ts.map +1 -0
  189. package/dist/error/client.js +38 -0
  190. package/dist/error/extend.d.ts +101 -0
  191. package/dist/error/extend.d.ts.map +1 -0
  192. package/dist/error/extend.js +76 -0
  193. package/dist/error/http.d.ts +1516 -0
  194. package/dist/error/http.d.ts.map +1 -0
  195. package/dist/error/http.js +72 -0
  196. package/dist/error/payload.d.ts +3034 -0
  197. package/dist/error/payload.d.ts.map +1 -0
  198. package/dist/error/payload.js +1110 -0
  199. package/dist/error/pithyError.d.ts +154 -0
  200. package/dist/error/pithyError.d.ts.map +1 -0
  201. package/dist/error/pithyError.js +197 -0
  202. package/dist/error/terminal.d.ts +28 -0
  203. package/dist/error/terminal.d.ts.map +1 -0
  204. package/dist/error/terminal.js +33 -0
  205. package/dist/http/authContext.d.ts +21 -0
  206. package/dist/http/authContext.d.ts.map +1 -0
  207. package/dist/http/authContext.js +23 -0
  208. package/dist/http/routeContract.d.ts +39 -0
  209. package/dist/http/routeContract.d.ts.map +1 -0
  210. package/dist/http/routeContract.js +82 -0
  211. package/dist/http/sameOrigin.d.ts +47 -0
  212. package/dist/http/sameOrigin.d.ts.map +1 -0
  213. package/dist/http/sameOrigin.js +24 -0
  214. package/dist/http/signedWebhook.d.ts +225 -0
  215. package/dist/http/signedWebhook.d.ts.map +1 -0
  216. package/dist/http/signedWebhook.js +247 -0
  217. package/dist/http/validation.d.ts +37 -0
  218. package/dist/http/validation.d.ts.map +1 -0
  219. package/dist/http/validation.js +14 -0
  220. package/dist/http/verification.d.ts +10 -0
  221. package/dist/http/verification.d.ts.map +1 -0
  222. package/dist/http/verification.js +17 -0
  223. package/dist/i18n/acceptLanguage.d.ts +22 -0
  224. package/dist/i18n/acceptLanguage.d.ts.map +1 -0
  225. package/dist/i18n/acceptLanguage.js +55 -0
  226. package/dist/i18n/catalog.d.ts +39 -0
  227. package/dist/i18n/catalog.d.ts.map +1 -0
  228. package/dist/i18n/catalog.js +57 -0
  229. package/dist/i18n/locale.d.ts +74 -0
  230. package/dist/i18n/locale.d.ts.map +1 -0
  231. package/dist/i18n/locale.js +109 -0
  232. package/dist/i18n/localeMarker.d.ts +29 -0
  233. package/dist/i18n/localeMarker.d.ts.map +1 -0
  234. package/dist/i18n/localeMarker.js +112 -0
  235. package/dist/i18n/match.d.ts +26 -0
  236. package/dist/i18n/match.d.ts.map +1 -0
  237. package/dist/i18n/match.js +88 -0
  238. package/dist/i18n/registry.d.ts +25 -0
  239. package/dist/i18n/registry.d.ts.map +1 -0
  240. package/dist/i18n/registry.js +51 -0
  241. package/dist/i18n/translator.d.ts +107 -0
  242. package/dist/i18n/translator.d.ts.map +1 -0
  243. package/dist/i18n/translator.js +80 -0
  244. package/dist/index.d.ts +32 -0
  245. package/dist/index.d.ts.map +1 -0
  246. package/dist/index.js +17 -0
  247. package/dist/kv/kv.d.ts +166 -0
  248. package/dist/kv/kv.d.ts.map +1 -0
  249. package/dist/kv/kv.js +261 -0
  250. package/dist/kv/namespaces.d.ts +58 -0
  251. package/dist/kv/namespaces.d.ts.map +1 -0
  252. package/dist/kv/namespaces.js +40 -0
  253. package/dist/logger/local.d.ts +41 -0
  254. package/dist/logger/local.d.ts.map +1 -0
  255. package/dist/logger/local.js +45 -0
  256. package/dist/logger/logger.d.ts +56 -0
  257. package/dist/logger/logger.d.ts.map +1 -0
  258. package/dist/logger/logger.js +83 -0
  259. package/dist/logger/record.d.ts +919 -0
  260. package/dist/logger/record.d.ts.map +1 -0
  261. package/dist/logger/record.js +79 -0
  262. package/dist/logger/worker.d.ts +74 -0
  263. package/dist/logger/worker.d.ts.map +1 -0
  264. package/dist/logger/worker.js +54 -0
  265. package/dist/migrations/batch.d.ts +10 -0
  266. package/dist/migrations/batch.d.ts.map +1 -0
  267. package/dist/migrations/batch.js +193 -0
  268. package/dist/migrations/bookkeeping.d.ts +24 -0
  269. package/dist/migrations/bookkeeping.d.ts.map +1 -0
  270. package/dist/migrations/bookkeeping.js +57 -0
  271. package/dist/migrations/owner.d.ts +41 -0
  272. package/dist/migrations/owner.d.ts.map +1 -0
  273. package/dist/migrations/owner.js +105 -0
  274. package/dist/migrations/registry.d.ts +36 -0
  275. package/dist/migrations/registry.d.ts.map +1 -0
  276. package/dist/migrations/registry.js +70 -0
  277. package/dist/migrations/runner.d.ts +67 -0
  278. package/dist/migrations/runner.d.ts.map +1 -0
  279. package/dist/migrations/runner.js +218 -0
  280. package/dist/naming/domains.d.ts +108 -0
  281. package/dist/naming/domains.d.ts.map +1 -0
  282. package/dist/naming/domains.js +156 -0
  283. package/dist/naming/environment.d.ts +118 -0
  284. package/dist/naming/environment.d.ts.map +1 -0
  285. package/dist/naming/environment.js +190 -0
  286. package/dist/naming/feature.d.ts +68 -0
  287. package/dist/naming/feature.d.ts.map +1 -0
  288. package/dist/naming/feature.js +106 -0
  289. package/dist/naming/limits.d.ts +229 -0
  290. package/dist/naming/limits.d.ts.map +1 -0
  291. package/dist/naming/limits.js +187 -0
  292. package/dist/naming/provisionScope.d.ts +91 -0
  293. package/dist/naming/provisionScope.d.ts.map +1 -0
  294. package/dist/naming/provisionScope.js +65 -0
  295. package/dist/naming/resource.d.ts +169 -0
  296. package/dist/naming/resource.d.ts.map +1 -0
  297. package/dist/naming/resource.js +220 -0
  298. package/dist/naming/resourceNames.d.ts +83 -0
  299. package/dist/naming/resourceNames.d.ts.map +1 -0
  300. package/dist/naming/resourceNames.js +102 -0
  301. package/dist/naming/segment.d.ts +29 -0
  302. package/dist/naming/segment.d.ts.map +1 -0
  303. package/dist/naming/segment.js +31 -0
  304. package/dist/projection/asRead.d.ts +72 -0
  305. package/dist/projection/asRead.d.ts.map +1 -0
  306. package/dist/projection/asRead.js +169 -0
  307. package/dist/projection/published.d.ts +95 -0
  308. package/dist/projection/published.d.ts.map +1 -0
  309. package/dist/projection/published.js +114 -0
  310. package/dist/schema/describedness.d.ts +55 -0
  311. package/dist/schema/describedness.d.ts.map +1 -0
  312. package/dist/schema/describedness.js +180 -0
  313. package/dist/seed/compose.d.ts +41 -0
  314. package/dist/seed/compose.d.ts.map +1 -0
  315. package/dist/seed/compose.js +51 -0
  316. package/dist/seed/devLogin.d.ts +50 -0
  317. package/dist/seed/devLogin.d.ts.map +1 -0
  318. package/dist/seed/devLogin.js +52 -0
  319. package/dist/seed/exampleIdentities.d.ts +58 -0
  320. package/dist/seed/exampleIdentities.d.ts.map +1 -0
  321. package/dist/seed/exampleIdentities.js +26 -0
  322. package/dist/seed/metadata.d.ts +20 -0
  323. package/dist/seed/metadata.d.ts.map +1 -0
  324. package/dist/seed/metadata.js +27 -0
  325. package/dist/seed/seed.d.ts +264 -0
  326. package/dist/seed/seed.d.ts.map +1 -0
  327. package/dist/seed/seed.js +37 -0
  328. package/dist/seed/seededRows.d.ts +26 -0
  329. package/dist/seed/seededRows.d.ts.map +1 -0
  330. package/dist/seed/seededRows.js +20 -0
  331. package/dist/seed/writeD1.d.ts +43 -0
  332. package/dist/seed/writeD1.d.ts.map +1 -0
  333. package/dist/seed/writeD1.js +73 -0
  334. package/dist/seed/writeKv.d.ts +29 -0
  335. package/dist/seed/writeKv.d.ts.map +1 -0
  336. package/dist/seed/writeKv.js +63 -0
  337. package/dist/semver/semver.d.ts +62 -0
  338. package/dist/semver/semver.d.ts.map +1 -0
  339. package/dist/semver/semver.js +137 -0
  340. package/dist/text/comments.d.ts +62 -0
  341. package/dist/text/comments.d.ts.map +1 -0
  342. package/dist/text/comments.js +161 -0
  343. package/dist/version.generated.d.ts +5 -0
  344. package/dist/version.generated.d.ts.map +1 -0
  345. package/dist/version.generated.js +7 -0
  346. package/dist/worker/health.d.ts +39 -0
  347. package/dist/worker/health.d.ts.map +1 -0
  348. package/dist/worker/health.js +41 -0
  349. package/dist/worker/identity.d.ts +191 -0
  350. package/dist/worker/identity.d.ts.map +1 -0
  351. package/dist/worker/identity.js +162 -0
  352. package/dist/workflow/bindings.d.ts +41 -0
  353. package/dist/workflow/bindings.d.ts.map +1 -0
  354. package/dist/workflow/bindings.js +53 -0
  355. package/dist/workflow/dispatch.d.ts +98 -0
  356. package/dist/workflow/dispatch.d.ts.map +1 -0
  357. package/dist/workflow/dispatch.js +148 -0
  358. package/dist/workflow/dispatchRoute.d.ts +80 -0
  359. package/dist/workflow/dispatchRoute.d.ts.map +1 -0
  360. package/dist/workflow/dispatchRoute.js +134 -0
  361. package/dist/workflow/faults.d.ts +97 -0
  362. package/dist/workflow/faults.d.ts.map +1 -0
  363. package/dist/workflow/faults.js +111 -0
  364. package/dist/workflow/host.d.ts +176 -0
  365. package/dist/workflow/host.d.ts.map +1 -0
  366. package/dist/workflow/host.js +116 -0
  367. package/dist/workflow/hostEntry.d.ts +50 -0
  368. package/dist/workflow/hostEntry.d.ts.map +1 -0
  369. package/dist/workflow/hostEntry.js +24 -0
  370. package/dist/workflow/hostEnv.d.ts +143 -0
  371. package/dist/workflow/hostEnv.d.ts.map +1 -0
  372. package/dist/workflow/hostEnv.js +170 -0
  373. package/dist/workflow/loopback.d.ts +52 -0
  374. package/dist/workflow/loopback.d.ts.map +1 -0
  375. package/dist/workflow/loopback.js +76 -0
  376. package/dist/workflow/naming.d.ts +79 -0
  377. package/dist/workflow/naming.d.ts.map +1 -0
  378. package/dist/workflow/naming.js +138 -0
  379. package/dist/workflow/register.d.ts +19 -0
  380. package/dist/workflow/register.d.ts.map +1 -0
  381. package/dist/workflow/register.js +40 -0
  382. package/dist/workflow/schemas.d.ts +44 -0
  383. package/dist/workflow/schemas.d.ts.map +1 -0
  384. package/dist/workflow/schemas.js +43 -0
  385. package/dist/workflow/spec.d.ts +81 -0
  386. package/dist/workflow/spec.d.ts.map +1 -0
  387. package/dist/workflow/spec.js +0 -0
  388. package/dist/workflow/stepMessage.d.ts +122 -0
  389. package/dist/workflow/stepMessage.d.ts.map +1 -0
  390. package/dist/workflow/stepMessage.js +152 -0
  391. package/package.json +20 -9
  392. package/src/capability/manifest.ts +21 -0
  393. package/src/version.generated.ts +1 -1
@@ -0,0 +1,119 @@
1
+ import { z } from "zod";
2
+ import type { HostEnvReport } from "../workflow/hostEnv";
3
+ /**
4
+ * How a capability checks that its own settings **work** — the seam `pithy doctor` runs (#411).
5
+ *
6
+ * Everything doctor asked before this was a question about *presence*: is the option key written, is the
7
+ * binding declared, is the ledger level. So a project could be entirely green while `fromAddress` named a
8
+ * domain nobody onboarded, the signing key was never created, `BASE_URL` was staging's URL in production's
9
+ * config, and no mail arrived. Presence is not the same question as correctness, and only the capability
10
+ * knows the second one.
11
+ *
12
+ * ## It hangs off the capability, never off the manifest
13
+ *
14
+ * The declaration sits on the {@link import("./capability").Capability} object, beside `health`, because
15
+ * `pithy.manifest.json` looks like the obvious signal and is the wrong one: `@pithy-sh/matchmaking` and
16
+ * `@pithy-sh/rating` are published capability packages that ship no manifest, and a manifest-keyed rule
17
+ * skips both in silence. The CLI already holds every composed instance (`project/workerScope.ts`), so
18
+ * discovery costs it nothing and misses nothing.
19
+ *
20
+ * A capability with nothing worth checking declares nothing. That is ordinary, silent, and not a fault.
21
+ *
22
+ * ## Two tiers, because they cost different things
23
+ *
24
+ * - **local** — does the value parse, is it the right shape, is it right for this environment. Free,
25
+ * offline, and always run. It validates through the very Zod object the capability's host Worker
26
+ * validates at boot ({@link hostEnvFindings} is the bridge), so the check an operator runs and the
27
+ * check the host runs cannot come to two answers.
28
+ * - **account** — is the domain a zone here, does the secret exist, is the database there. One Cloudflare
29
+ * call, so it is opt-in and it is skipped whenever the account cannot be reached.
30
+ *
31
+ * Both are faults. A local finding fails `pithy doctor`'s exit; an account finding does too, **but only
32
+ * when the account was reached** — an unreachable account is reported as *skipped*, never as a pass, and
33
+ * gates nothing. Three answers, and a boolean can hold two of them.
34
+ *
35
+ * ## Nothing here writes
36
+ *
37
+ * A check reports. `pithy upgrade`, `pithy <capability> provision` and the commands each finding names are
38
+ * what change anything, which is why every finding carries the action that resolves it.
39
+ */
40
+ /** One setting that does not work, and the one thing an operator does about it. */
41
+ export declare const SettingsFinding: z.ZodObject<{
42
+ setting: z.ZodString;
43
+ environment: z.ZodNullable<z.ZodString>;
44
+ problem: z.ZodString;
45
+ action: z.ZodString;
46
+ }, z.core.$strip>;
47
+ export type SettingsFinding = z.infer<typeof SettingsFinding>;
48
+ /** One environment the project declares, and what this Worker's own config says about it. */
49
+ export interface SettingsEnvironment {
50
+ /** The environment id — `dev`, `staging`, `prod`. Verbatim, never `production`. */
51
+ name: string;
52
+ /**
53
+ * The origin this Worker answers on in that environment, or `null` where its config names none.
54
+ *
55
+ * Supplied by the CLI rather than resolved by the capability: which hostname an environment serves is
56
+ * the adopter's declaration to make, and `project/domains.ts` is the one reader of it.
57
+ */
58
+ origin: string | null;
59
+ }
60
+ /** What a check is told about the project it is checking. Both tiers get it; the account tier gets more. */
61
+ export interface SettingsCheckContext {
62
+ /** The root config's `name` — the leading segment of every resource this project provisions. */
63
+ project: string;
64
+ /** The Worker whose `pithy.config.ts` composed this capability. */
65
+ worker: string;
66
+ /** Every environment the project declares, in declaration order. */
67
+ environments: readonly SettingsEnvironment[];
68
+ }
69
+ /**
70
+ * The account questions a check may ask — a closed vocabulary, on purpose.
71
+ *
72
+ * Closed for the reason `CapabilityHealth` is: handing a capability a raw Cloudflare client would make
73
+ * every capability a place a network call can be invented, and would put `@pithy-sh/cloudflare` in the
74
+ * dependency list of packages that need none of it. Three questions cover what the first checks ask; a
75
+ * fourth lands here, once, when a capability actually needs it.
76
+ *
77
+ * Every method may throw. A throw is the account failing to answer, and the runner reports that
78
+ * capability's account tier as unchecked rather than as a pass.
79
+ */
80
+ export interface SettingsAccountReader {
81
+ /** Every D1 database name this account holds. */
82
+ d1Databases(): Promise<readonly string[]>;
83
+ /** Whether this account holds a Cloudflare zone covering the hostname — the prerequisite for onboarding it. */
84
+ zone(hostname: string): Promise<boolean>;
85
+ /** Whether a declared secret has a value in that environment. The name is the registry's, not a binding's. */
86
+ secret(request: {
87
+ name: string;
88
+ environment: string;
89
+ }): Promise<boolean>;
90
+ }
91
+ /** What the account tier is told: everything the local tier gets, plus the account it may ask. */
92
+ export interface SettingsAccountContext extends SettingsCheckContext {
93
+ /** The account, as the closed set of questions above. */
94
+ account: SettingsAccountReader;
95
+ }
96
+ /**
97
+ * A capability's settings check, as it hangs off the capability.
98
+ *
99
+ * `local` is required — a capability that declares this seam declares at least the free half of it. A
100
+ * check that would only ever reach the account is a check that says nothing offline, and offline is where
101
+ * most of these faults are cheapest to find.
102
+ */
103
+ export interface CapabilitySettings {
104
+ /** The free half. Pure, offline, and always run. */
105
+ local(context: SettingsCheckContext): SettingsFinding[] | Promise<SettingsFinding[]>;
106
+ /** The half that costs a Cloudflare call. Omitted where a capability has nothing to ask the account. */
107
+ account?(context: SettingsAccountContext): Promise<SettingsFinding[]>;
108
+ }
109
+ /**
110
+ * Turn a host env's own parse report into findings — the bridge that makes "one schema, two readers" real.
111
+ *
112
+ * A capability's local tier builds the env its host *would* be handed, runs {@link
113
+ * import("../workflow/hostEnv").checkHostEnv} against its own declaration, and hands the report here. The
114
+ * problem line is Zod's own message and the action line is {@link hostEnvProviderSentence} — the same
115
+ * words the host writes into its log before it refuses to start. Two readers of one declaration, and no
116
+ * second wording to drift.
117
+ */
118
+ export declare function hostEnvFindings(report: HostEnvReport<unknown>, environment: string | null): SettingsFinding[];
119
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/capability/settings.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,mFAAmF;AACnF,eAAO,MAAM,eAAe;;;;;iBA0B+D,CAAC;AAC5F,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,6FAA6F;AAC7F,MAAM,WAAW,mBAAmB;IAClC,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,4GAA4G;AAC5G,MAAM,WAAW,oBAAoB;IACnC,gGAAgG;IAChG,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,YAAY,EAAE,SAAS,mBAAmB,EAAE,CAAC;CAC9C;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,qBAAqB;IACpC,iDAAiD;IACjD,WAAW,IAAI,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IAC1C,+GAA+G;IAC/G,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzC,8GAA8G;IAC9G,MAAM,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAED,kGAAkG;AAClG,MAAM,WAAW,sBAAuB,SAAQ,oBAAoB;IAClE,yDAAyD;IACzD,OAAO,EAAE,qBAAqB,CAAC;CAChC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,oDAAoD;IACpD,KAAK,CAAC,OAAO,EAAE,oBAAoB,GAAG,eAAe,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IACrF,wGAAwG;IACxG,OAAO,CAAC,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;CACvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,eAAe,EAAE,CAO7G"}
@@ -0,0 +1,66 @@
1
+ import { hostEnvProviderSentence } from "../workflow/hostEnv.js";
2
+ import { z } from "zod";
3
+ //#region src/capability/settings.ts
4
+ /**
5
+ * How a capability checks that its own settings **work** — the seam `pithy doctor` runs (#411).
6
+ *
7
+ * Everything doctor asked before this was a question about *presence*: is the option key written, is the
8
+ * binding declared, is the ledger level. So a project could be entirely green while `fromAddress` named a
9
+ * domain nobody onboarded, the signing key was never created, `BASE_URL` was staging's URL in production's
10
+ * config, and no mail arrived. Presence is not the same question as correctness, and only the capability
11
+ * knows the second one.
12
+ *
13
+ * ## It hangs off the capability, never off the manifest
14
+ *
15
+ * The declaration sits on the {@link import("./capability").Capability} object, beside `health`, because
16
+ * `pithy.manifest.json` looks like the obvious signal and is the wrong one: `@pithy-sh/matchmaking` and
17
+ * `@pithy-sh/rating` are published capability packages that ship no manifest, and a manifest-keyed rule
18
+ * skips both in silence. The CLI already holds every composed instance (`project/workerScope.ts`), so
19
+ * discovery costs it nothing and misses nothing.
20
+ *
21
+ * A capability with nothing worth checking declares nothing. That is ordinary, silent, and not a fault.
22
+ *
23
+ * ## Two tiers, because they cost different things
24
+ *
25
+ * - **local** — does the value parse, is it the right shape, is it right for this environment. Free,
26
+ * offline, and always run. It validates through the very Zod object the capability's host Worker
27
+ * validates at boot ({@link hostEnvFindings} is the bridge), so the check an operator runs and the
28
+ * check the host runs cannot come to two answers.
29
+ * - **account** — is the domain a zone here, does the secret exist, is the database there. One Cloudflare
30
+ * call, so it is opt-in and it is skipped whenever the account cannot be reached.
31
+ *
32
+ * Both are faults. A local finding fails `pithy doctor`'s exit; an account finding does too, **but only
33
+ * when the account was reached** — an unreachable account is reported as *skipped*, never as a pass, and
34
+ * gates nothing. Three answers, and a boolean can hold two of them.
35
+ *
36
+ * ## Nothing here writes
37
+ *
38
+ * A check reports. `pithy upgrade`, `pithy <capability> provision` and the commands each finding names are
39
+ * what change anything, which is why every finding carries the action that resolves it.
40
+ */
41
+ /** One setting that does not work, and the one thing an operator does about it. */
42
+ const SettingsFinding = z.object({
43
+ setting: z.string().min(1).describe("What is wrong — the env field, config key, or account resource, spelled as the operator would find it. It leads the line, so it is the name they search for."),
44
+ environment: z.string().min(1).nullable().describe("The environment this is about, or `null` where the setting is the same in all of them. A per-environment fault is reported once per environment, because that is how many edits it takes."),
45
+ problem: z.string().min(1).describe("Why it does not work, in one sentence. The problem line, in the same voice every PithyError uses."),
46
+ action: z.string().min(1).describe("What resolves it: the `pithy` command, the `pithy.config.ts` key, or the one-time account action. Never optional — a finding nobody can act on is a complaint.")
47
+ }).describe("One capability setting that does not work, with the action that resolves it.");
48
+ /**
49
+ * Turn a host env's own parse report into findings — the bridge that makes "one schema, two readers" real.
50
+ *
51
+ * A capability's local tier builds the env its host *would* be handed, runs {@link
52
+ * import("../workflow/hostEnv").checkHostEnv} against its own declaration, and hands the report here. The
53
+ * problem line is Zod's own message and the action line is {@link hostEnvProviderSentence} — the same
54
+ * words the host writes into its log before it refuses to start. Two readers of one declaration, and no
55
+ * second wording to drift.
56
+ */
57
+ function hostEnvFindings(report, environment) {
58
+ return report.problems.map((problem) => ({
59
+ setting: problem.field,
60
+ environment,
61
+ problem: problem.reason,
62
+ action: hostEnvProviderSentence(problem.provider)
63
+ }));
64
+ }
65
+ //#endregion
66
+ export { SettingsFinding, hostEnvFindings };
@@ -0,0 +1,4 @@
1
+ import { type BindingSpec } from "./bindings";
2
+ /** Throw a typed error if any non-optional binding is absent from `env`. */
3
+ export declare function validateBindings(env: Record<string, unknown>, required: BindingSpec[]): void;
4
+ //# sourceMappingURL=validateBindings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateBindings.d.ts","sourceRoot":"","sources":["../../src/capability/validateBindings.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,WAAW,EAAwB,MAAM,YAAY,CAAC;AA2BpE,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,IAAI,CAU5F"}
@@ -0,0 +1,34 @@
1
+ import { isProvisionedBinding } from "./bindings.js";
2
+ import { InternalError } from "../error/pithyError.js";
3
+ //#region src/capability/validateBindings.ts
4
+ /** How a missing binding is named in both halves of the error: `kv:SESSIONS`. */
5
+ function label(binding) {
6
+ return `${binding.type}:${binding.name}`;
7
+ }
8
+ /**
9
+ * What to do about the bindings that are missing — and there are two answers, not one.
10
+ *
11
+ * A `kv` or `d1` binding is a line the adopter adds to `wrangler.jsonc`. A `secret`, `workflow`, or
12
+ * `vectorize` binding is not: its entry carries a provisioned value, so the old single line
13
+ * ("Add the binding(s) to wrangler.jsonc, then redeploy.") sent anyone missing a Secrets Store entry
14
+ * to a file that entry never appears in. Each list names only its own bindings, so a mixed failure
15
+ * says which of them is which instead of leaving the reader to sort it out.
16
+ */
17
+ function bindingAction(missing) {
18
+ const written = missing.filter((binding) => !isProvisionedBinding(binding.type)).map(label);
19
+ const provisioned = missing.filter((binding) => isProvisionedBinding(binding.type)).map(label);
20
+ const sentences = [];
21
+ if (written.length > 0) sentences.push(`Add ${written.join(", ")} to wrangler.jsonc, then redeploy.`);
22
+ if (provisioned.length > 0) sentences.push(`Provision ${provisioned.join(", ")} — a provision command creates those, or .dev.vars in dev.`);
23
+ return sentences.join(" ");
24
+ }
25
+ /** Throw a typed error if any non-optional binding is absent from `env`. */
26
+ function validateBindings(env, required) {
27
+ const missing = required.filter((b) => !b.optional && env[b.name] == null);
28
+ if (missing.length > 0) throw new InternalError({
29
+ message: `Missing required bindings: ${missing.map(label).join(", ")}`,
30
+ action: bindingAction(missing)
31
+ });
32
+ }
33
+ //#endregion
34
+ export { validateBindings };
@@ -0,0 +1,31 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Whether a value states no key that would vanish during parsing.
4
+ *
5
+ * Non-objects pass: they hold no keys, and the schema behind this guard is what refuses them for being the
6
+ * wrong type. `Object.hasOwn` and not `in`, because every object inherits `__proto__` and only an own one
7
+ * is data somebody wrote.
8
+ */
9
+ export declare function statesNoVanishingKey(value: unknown): boolean;
10
+ /**
11
+ * A schema held to keys that survive being read.
12
+ *
13
+ * Wraps rather than replaces: the schema behind it keeps its own key and value rules, and this only
14
+ * guarantees they are given every key the payload wrote. See {@link VANISHING_KEY} for why that is not
15
+ * already true.
16
+ *
17
+ * `subject` names what wrote the record, because the reader of the error is the person who has to go and
18
+ * change it — a capability author for a manifest, an adopter for a projection.
19
+ *
20
+ * Typed on the wrapped schema's own input rather than on `unknown`, so a guard is transparent to whatever
21
+ * it is composed into. Widening every wrapped schema to `unknown` would make the guard's altitude a
22
+ * typing question — it could only go where nothing downstream needed the input type — and altitude is the
23
+ * one thing about this guard that should be decided on the exposure.
24
+ */
25
+ export declare function refusesVanishingKey<Output, Input>(schema: z.ZodType<Output, Input>, subject: string): z.ZodPipe<z.ZodCustom<Input, Input>, z.ZodType<Output, Input>>;
26
+ /**
27
+ * A record a manifest may state. The manifest's wording of {@link refusesVanishingKey}, kept in one place
28
+ * so its two call sites cannot drift into two sentences for one rule.
29
+ */
30
+ export declare function manifestRecord<Output, Input>(record: z.ZodType<Output, Input>): z.ZodPipe<z.ZodCustom<Input, Input>, z.ZodType<Output, Input>>;
31
+ //# sourceMappingURL=vanishingKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vanishingKey.d.ts","sourceRoot":"","sources":["../../src/capability/vanishingKey.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA0CxB;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAG5D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,KAAK,EAC/C,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,EAChC,OAAO,EAAE,MAAM,GACd,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAMhE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,KAAK,EAC1C,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,GAC/B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAEhE"}
@@ -0,0 +1,79 @@
1
+ import { z } from "zod";
2
+ //#region src/capability/vanishingKey.ts
3
+ /**
4
+ * The one key a parsed object loses on the way through a schema, and the guard that refuses it.
5
+ *
6
+ * `JSON.parse` gives `__proto__` an own property, because it must — the alternative is JSON that can set
7
+ * the prototype of every object built from it. Zod then skips that key while projecting an object or a
8
+ * record, for exactly the same reason: assigning it onto the `{}` it builds into would run the setter on
9
+ * `Object.prototype` instead of creating a property. Neither decision is wrong. Together they mean a key
10
+ * enters the parse, matches no rule, raises no issue, and is not in the result.
11
+ *
12
+ * That is the shape worth naming: **not a value rewritten, a key that was never reported at all.** A key
13
+ * schema would have refused `__proto__` on its first character; it never runs, because the skip happens
14
+ * before the key type does. So this does not add a rule. It gets the rule that is already written back in
15
+ * front of the data.
16
+ *
17
+ * **`Object.create(null)` does not close this, and #331 left that question open.** The idea is sound on
18
+ * its face — a null-prototype target has no `__proto__` setter to run, so the assignment would create a
19
+ * property and the key would survive — and it is wrong here for a reason that is worth writing down once.
20
+ * Zod's skip is a literal `key === "__proto__"` comparison made *before* any assignment
21
+ * (`zod/v4/core/schemas` at the object and record branches), so the prototype of the target has no bearing
22
+ * on it, and neither does the prototype of the input: handing `z.record` a value built with
23
+ * `Object.assign(Object.create(null), parsed)` still returns without the key. Measured, not assumed. The
24
+ * class cannot be closed by changing what the object is; it can only be closed in front of the schema,
25
+ * which is what this is.
26
+ *
27
+ * **Refuse, not degrade.** The surrounding design degrades an unrecognized *issuer* to `other` so a client
28
+ * built today can read a manifest written tomorrow, and that is right for a value. It is wrong here twice
29
+ * over. `__proto__` is not a name a future issuer will be called; it is a mistake or an attack. And
30
+ * degrading a key is a merge — the defect the issuer-key rule was written to close, where two unknown keys
31
+ * rewritten to one overwrite each other's requirements in silence. Refusing is the only answer that leaves
32
+ * nothing to detect after the fact: a payload that will not parse is reported by every client that reads
33
+ * it, and `pithy doctor` already names the package that shipped it.
34
+ *
35
+ * Applied at the schema, not at a call site, because the exposure belongs to the *shape* — any record read
36
+ * from outside this process has it — and a rule that lives at one call site is how this codebase has
37
+ * repeatedly fixed one field and left its siblings. `vanishingKey.test.ts` walks each guarded root and
38
+ * attacks every record it finds, so a record added later without this guard fails on the commit that adds
39
+ * it.
40
+ */
41
+ const VANISHING_KEY = "__proto__";
42
+ /**
43
+ * Whether a value states no key that would vanish during parsing.
44
+ *
45
+ * Non-objects pass: they hold no keys, and the schema behind this guard is what refuses them for being the
46
+ * wrong type. `Object.hasOwn` and not `in`, because every object inherits `__proto__` and only an own one
47
+ * is data somebody wrote.
48
+ */
49
+ function statesNoVanishingKey(value) {
50
+ if (typeof value !== "object" || value === null) return true;
51
+ return !Object.hasOwn(value, VANISHING_KEY);
52
+ }
53
+ /**
54
+ * A schema held to keys that survive being read.
55
+ *
56
+ * Wraps rather than replaces: the schema behind it keeps its own key and value rules, and this only
57
+ * guarantees they are given every key the payload wrote. See {@link VANISHING_KEY} for why that is not
58
+ * already true.
59
+ *
60
+ * `subject` names what wrote the record, because the reader of the error is the person who has to go and
61
+ * change it — a capability author for a manifest, an adopter for a projection.
62
+ *
63
+ * Typed on the wrapped schema's own input rather than on `unknown`, so a guard is transparent to whatever
64
+ * it is composed into. Widening every wrapped schema to `unknown` would make the guard's altitude a
65
+ * typing question — it could only go where nothing downstream needed the input type — and altitude is the
66
+ * one thing about this guard that should be decided on the exposure.
67
+ */
68
+ function refusesVanishingKey(schema, subject) {
69
+ return z.custom(statesNoVanishingKey, { error: `${subject} may not state a "${VANISHING_KEY}" key. It is the one name a parsed object loses without a word, so whatever it keyed would be gone with it.` }).pipe(schema);
70
+ }
71
+ /**
72
+ * A record a manifest may state. The manifest's wording of {@link refusesVanishingKey}, kept in one place
73
+ * so its two call sites cannot drift into two sentences for one rule.
74
+ */
75
+ function manifestRecord(record) {
76
+ return refusesVanishingKey(record, "A manifest record");
77
+ }
78
+ //#endregion
79
+ export { manifestRecord, refusesVanishingKey, statesNoVanishingKey };
@@ -0,0 +1,70 @@
1
+ import type { AuditEventInput } from "../../audit/auditEvent";
2
+ import type { AuditEmit } from "../../audit/recorder";
3
+ import type { Logger } from "../../logger/logger";
4
+ /**
5
+ * The audit action codes the `control-plane` seam emits, as `domain/reason` strings under the
6
+ * `controlplane` domain.
7
+ *
8
+ * **The domain is one word on purpose.** `AuditAction`'s pattern allows no hyphen, so
9
+ * `control-plane/call_allowed` is not a valid code at all. The route-strategy literal stays
10
+ * `control-plane`; every namespace token — capability, migrations, table prefix, error codes, these
11
+ * actions — is `controlplane`. The audit *actor kind* is the hyphenated `"control-plane"`, because
12
+ * that is an enum member and not a namespace. (None of this is Cloudflare's control plane; that is the
13
+ * outbound provisioning API behind `@pithy-sh/cloudflare`.)
14
+ *
15
+ * These are declared as a plain `as const` map rather than through `@pithy-sh/audit`'s
16
+ * `defineAuditActions`, because audit already depends on core — importing it back would be a cycle.
17
+ * `actions.test.ts` asserts every value against core's `AuditAction` pattern instead, so the map is
18
+ * held to the same contract the helper would have enforced.
19
+ *
20
+ * Emission goes through core's `emit` seam (`c.var.emit`), a no-op when the audit capability is
21
+ * absent, so the seam never imports audit at runtime either (principle 4).
22
+ *
23
+ * **Four of these are emitted by a route; three are emitted by the CLI** (#294). The connection
24
+ * lifecycle — registered, updated, removed — is written by `pithy dashboard` opening the adopter's D1
25
+ * directly, because those operations never reach their Worker: a first connect has no key to sign with
26
+ * and the Worker may not be deployed, an update re-points an address the Worker never reads, and a
27
+ * disconnect withdraws trust, which must not depend on a working connection (docs/CONTROL-PLANE.md §15).
28
+ * So there is no route in a position to record them, and the write records itself instead — in the same
29
+ * D1, from `connectionRegistry`. The `actorType` is what tells the two writers apart: a route records
30
+ * `control-plane`, meaning the management client called in and proved it, while a CLI-side event carries
31
+ * the adopter's own operator and no session at all.
32
+ *
33
+ * A declared code that nothing emits is a surface the trail promises and never delivers, which is what
34
+ * these three were until #294. `packages/cli/src/ci/auditActions.test.ts` fails the build on one.
35
+ */
36
+ export declare const ControlPlaneAuditActions: {
37
+ /** A verified, in-scope management call was admitted. The trail of what the dashboard actually did. */
38
+ readonly callAllowed: "controlplane/call_allowed";
39
+ /** A management call was refused — no connection, bad credential, or an ungranted scope. Outcome `denied`. */
40
+ readonly callDenied: "controlplane/call_denied";
41
+ /** A new public key was registered on a connection, opening a rotation overlap. */
42
+ readonly keyRegistered: "controlplane/key_registered";
43
+ /** A superseded public key was given an end date and stopped being accepted. */
44
+ readonly keyExpired: "controlplane/key_expired";
45
+ /** A management client was connected to this environment — a new connection, or one started over. */
46
+ readonly connectionRegistered: "controlplane/connection_registered";
47
+ /** An existing connection changed — its granted scopes, the Worker URL it points at, or the keys it trusts. */
48
+ readonly connectionUpdated: "controlplane/connection_updated";
49
+ /** A connection was removed. The seam returns to its shipped state: connected to nothing, denying everything. */
50
+ readonly connectionRemoved: "controlplane/connection_removed";
51
+ };
52
+ /** One of the control-plane audit action codes. */
53
+ export type ControlPlaneAuditAction = (typeof ControlPlaneAuditActions)[keyof typeof ControlPlaneAuditActions];
54
+ /**
55
+ * Emit an audit event and swallow any failure.
56
+ *
57
+ * **Every denial emits an event, and that is exactly why this cannot throw.** By the time the seam
58
+ * records a call, the security-relevant outcome is already decided — the 401 or 403 is going out
59
+ * whatever happens next. An audit write that threw would convert a correct denial into a 500: it would
60
+ * hand the caller a different response for a *failing* store than for a healthy one, and turn a
61
+ * transient D1 problem into an availability bug on the admin surface. The record is evidence of the
62
+ * decision, never part of making it.
63
+ *
64
+ * The real recorder is non-fatal by contract already ({@link AuditEmit}), so this is belt and braces —
65
+ * but the gate is a security boundary and does not get to assume its collaborators behave. The failure
66
+ * is logged when a logger is at hand, so a store that has stopped accepting writes is visible rather
67
+ * than silent.
68
+ */
69
+ export declare function safeEmit(emit: AuditEmit, event: AuditEventInput, log?: Logger): Promise<void>;
70
+ //# sourceMappingURL=actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/audit/actions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,wBAAwB;IACnC,uGAAuG;aACvG,WAAW,EAAE,2BAA2B;IACxC,8GAA8G;aAC9G,UAAU,EAAE,0BAA0B;IACtC,mFAAmF;aACnF,aAAa,EAAE,6BAA6B;IAC5C,gFAAgF;aAChF,UAAU,EAAE,0BAA0B;IACtC,qGAAqG;aACrG,oBAAoB,EAAE,oCAAoC;IAC1D,+GAA+G;aAC/G,iBAAiB,EAAE,iCAAiC;IACpD,iHAAiH;aACjH,iBAAiB,EAAE,iCAAiC;CAC5C,CAAC;AAEX,mDAAmD;AACnD,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,OAAO,wBAAwB,CAAC,CAAC;AAE/G;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMnG"}
@@ -0,0 +1,76 @@
1
+ //#region src/controlPlane/audit/actions.ts
2
+ /**
3
+ * The audit action codes the `control-plane` seam emits, as `domain/reason` strings under the
4
+ * `controlplane` domain.
5
+ *
6
+ * **The domain is one word on purpose.** `AuditAction`'s pattern allows no hyphen, so
7
+ * `control-plane/call_allowed` is not a valid code at all. The route-strategy literal stays
8
+ * `control-plane`; every namespace token — capability, migrations, table prefix, error codes, these
9
+ * actions — is `controlplane`. The audit *actor kind* is the hyphenated `"control-plane"`, because
10
+ * that is an enum member and not a namespace. (None of this is Cloudflare's control plane; that is the
11
+ * outbound provisioning API behind `@pithy-sh/cloudflare`.)
12
+ *
13
+ * These are declared as a plain `as const` map rather than through `@pithy-sh/audit`'s
14
+ * `defineAuditActions`, because audit already depends on core — importing it back would be a cycle.
15
+ * `actions.test.ts` asserts every value against core's `AuditAction` pattern instead, so the map is
16
+ * held to the same contract the helper would have enforced.
17
+ *
18
+ * Emission goes through core's `emit` seam (`c.var.emit`), a no-op when the audit capability is
19
+ * absent, so the seam never imports audit at runtime either (principle 4).
20
+ *
21
+ * **Four of these are emitted by a route; three are emitted by the CLI** (#294). The connection
22
+ * lifecycle — registered, updated, removed — is written by `pithy dashboard` opening the adopter's D1
23
+ * directly, because those operations never reach their Worker: a first connect has no key to sign with
24
+ * and the Worker may not be deployed, an update re-points an address the Worker never reads, and a
25
+ * disconnect withdraws trust, which must not depend on a working connection (docs/CONTROL-PLANE.md §15).
26
+ * So there is no route in a position to record them, and the write records itself instead — in the same
27
+ * D1, from `connectionRegistry`. The `actorType` is what tells the two writers apart: a route records
28
+ * `control-plane`, meaning the management client called in and proved it, while a CLI-side event carries
29
+ * the adopter's own operator and no session at all.
30
+ *
31
+ * A declared code that nothing emits is a surface the trail promises and never delivers, which is what
32
+ * these three were until #294. `packages/cli/src/ci/auditActions.test.ts` fails the build on one.
33
+ */
34
+ const ControlPlaneAuditActions = {
35
+ /** A verified, in-scope management call was admitted. The trail of what the dashboard actually did. */
36
+ callAllowed: "controlplane/call_allowed",
37
+ /** A management call was refused — no connection, bad credential, or an ungranted scope. Outcome `denied`. */
38
+ callDenied: "controlplane/call_denied",
39
+ /** A new public key was registered on a connection, opening a rotation overlap. */
40
+ keyRegistered: "controlplane/key_registered",
41
+ /** A superseded public key was given an end date and stopped being accepted. */
42
+ keyExpired: "controlplane/key_expired",
43
+ /** A management client was connected to this environment — a new connection, or one started over. */
44
+ connectionRegistered: "controlplane/connection_registered",
45
+ /** An existing connection changed — its granted scopes, the Worker URL it points at, or the keys it trusts. */
46
+ connectionUpdated: "controlplane/connection_updated",
47
+ /** A connection was removed. The seam returns to its shipped state: connected to nothing, denying everything. */
48
+ connectionRemoved: "controlplane/connection_removed"
49
+ };
50
+ /**
51
+ * Emit an audit event and swallow any failure.
52
+ *
53
+ * **Every denial emits an event, and that is exactly why this cannot throw.** By the time the seam
54
+ * records a call, the security-relevant outcome is already decided — the 401 or 403 is going out
55
+ * whatever happens next. An audit write that threw would convert a correct denial into a 500: it would
56
+ * hand the caller a different response for a *failing* store than for a healthy one, and turn a
57
+ * transient D1 problem into an availability bug on the admin surface. The record is evidence of the
58
+ * decision, never part of making it.
59
+ *
60
+ * The real recorder is non-fatal by contract already ({@link AuditEmit}), so this is belt and braces —
61
+ * but the gate is a security boundary and does not get to assume its collaborators behave. The failure
62
+ * is logged when a logger is at hand, so a store that has stopped accepting writes is visible rather
63
+ * than silent.
64
+ */
65
+ async function safeEmit(emit, event, log) {
66
+ try {
67
+ await emit(event);
68
+ } catch (error) {
69
+ log?.warn("control-plane audit event dropped", {
70
+ action: event.action,
71
+ error
72
+ });
73
+ }
74
+ }
75
+ //#endregion
76
+ export { ControlPlaneAuditActions, safeEmit };
@@ -0,0 +1,47 @@
1
+ import { type Capability } from "../capability/capability";
2
+ import type { DatabaseSpecMap } from "../data/databases";
3
+ import type { KvNamespaceSpecMap } from "../kv/namespaces";
4
+ import { ControlPlaneConfig, type ControlPlaneConfigInput } from "./config/config";
5
+ import { CONTROL_PLANE_KV_BINDING } from "./replay/kvGuard";
6
+ /**
7
+ * Where the control-plane registration sorts in the app database. Composed key:
8
+ * `1100_controlplane_0001_init`.
9
+ *
10
+ * Taken from `NEXT_FREE_ORDER` in `packages/cli/src/migrations/orders.test.ts`, which is the one place
11
+ * an order may be allocated, and registered in that file's `DECLARED` table. Core used to be skipped by
12
+ * that scanner on the reasoning that it owns the ceiling rather than an order; that stopped being true
13
+ * here, and the skip was removed with this change. Stable forever — renumbering would rename the
14
+ * composed key and make Kysely re-run an applied migration.
15
+ */
16
+ export declare const CONTROLPLANE_MIGRATION_ORDER = 1100;
17
+ export type ControlPlaneOptions = ControlPlaneConfigInput;
18
+ /** The control-plane capability, with its resolved config attached. */
19
+ export interface ControlPlaneCapability extends Capability<DatabaseSpecMap, KvNamespaceSpecMap, "controlplane"> {
20
+ /** The resolved seam config. */
21
+ controlPlaneConfig: ControlPlaneConfig;
22
+ }
23
+ /** Narrow a composed capability to this one — the CLI and tests use it to find the seam's config. */
24
+ export declare function isControlPlaneCapability(capability: Capability): capability is ControlPlaneCapability;
25
+ /**
26
+ * The `control-plane` seam: inbound, adopter-authenticated M2M admin access to this Worker.
27
+ *
28
+ * **Not Cloudflare's control plane.** That is the outbound REST API `@pithy-sh/cloudflare` calls to
29
+ * provision D1, KV, and Workers, and it carries `cloudflare/*` codes. This is the inverse — a
30
+ * management client calling *in*, authenticated by a key the adopter registered. See
31
+ * `docs/CONTROL-PLANE.md`, whose first section exists entirely to keep the two apart.
32
+ *
33
+ * **Composing it grants nobody anything.** The capability ships present-and-denying: with no connection
34
+ * registered, every route it guards answers `controlplane/not_connected`, and there is no flag that
35
+ * changes that. `pithy dashboard connect` is the deliberate second step, and revoking is a row the
36
+ * adopter deletes without asking anyone.
37
+ *
38
+ * It lives in `@pithy-sh/core` rather than its own package because every capability contributing admin
39
+ * routes imports `requireControlPlane`, and a capability may depend on a core seam but never on a
40
+ * sibling package (principle 4). MIT with the rest of core, and never gated by tier: this is the code
41
+ * that runs in the adopter's own Worker, so restricting it would make "build your own client against
42
+ * your own Worker" untrue.
43
+ */
44
+ export declare function controlplane(options?: ControlPlaneOptions): ControlPlaneCapability;
45
+ /** Re-exported so a Worker's wrangler config and this capability cannot disagree about the binding name. */
46
+ export { CONTROL_PLANE_KV_BINDING };
47
+ //# sourceMappingURL=capability.d.ts.map
@@ -0,0 +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;AAUnF,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,CAwJtF;AAED,4GAA4G;AAC5G,OAAO,EAAE,wBAAwB,EAAE,CAAC"}