@pithy-sh/core 0.1.1 → 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,278 @@
1
+ import { ControlPlaneScope } from "../scope/scope.js";
2
+ import { z } from "zod";
3
+ //#region src/controlPlane/discovery/healthSummary.ts
4
+ /**
5
+ * The health vocabulary a manifest carries and a management client renders (#317, #350).
6
+ *
7
+ * **The count is not the expensive part. The round trip is.** A management client that wants to say
8
+ * "3 secrets need rotating" beside a rail already read the manifest; making it call again — once per
9
+ * capability it wants a number from, against a customer's production Worker, on every screen load —
10
+ * spends a credential per number nobody has asked for yet.
11
+ *
12
+ * The manifest is the right place because it already carries `version` per capability, and a version is
13
+ * a fact about a capability's *state* rather than about its routes. Nobody discovers anything from it;
14
+ * it is there because a management client needs it and a second call would be wasteful. This is the
15
+ * same argument, already accepted once.
16
+ *
17
+ * ## What keeps it from becoming a data API
18
+ *
19
+ * Three rules, and every one of them is in the type rather than in a comment:
20
+ *
21
+ * 1. **Scalars only.** {@link HealthSummaryValue} is `number | string` and nothing else, so a
22
+ * projection, a row, or a list does not compile — {@link HEALTH_SUMMARY_IS_SCALAR_ONLY} fails the
23
+ * build the moment somebody widens it.
24
+ * 2. **A closed vocabulary per capability**, declared alongside its routes. A produced key nobody
25
+ * declared is refused; the manifest never carries a number a client cannot name.
26
+ * 3. **Nothing that costs a query to produce.** {@link HealthValueCost} has `memory` and `indexed` and
27
+ * no third member, so a value that would need a table scan cannot be declared at all. A count that
28
+ * scans on every manifest read has moved the cost rather than removed it, and the manifest is the
29
+ * most frequently fetched thing this seam serves.
30
+ *
31
+ * ## A withheld number and a zero are different facts
32
+ *
33
+ * A count is less sensitive than the thing it counts, but "3 secrets need rotating" is still a fact
34
+ * about somebody's security posture. So a key inherits a scope the capability *already* gates a read
35
+ * with, and a caller without that scope gets no value at all rather than a zero.
36
+ *
37
+ * ## And a broken store is a fourth fact (#350)
38
+ *
39
+ * #317 got three states right and left the fourth to a reviewer, deliberately: a producer that throws
40
+ * is neither a withheld number nor a zero, and returning null for it would have made a sick store
41
+ * indistinguishable from one this caller may not look at. The reasoning was right. The behavior was
42
+ * that the throw propagated, the whole manifest read failed, and one sick capability blanked Overview
43
+ * for every capability beside it — with nothing on screen saying which one.
44
+ *
45
+ * So there are four, and they live on {@link CapabilityHealthReport}: `undeclared`, `withheld`,
46
+ * `reported`, `unavailable`. The state rides on the value rather than beside it, so a consumer reaches
47
+ * a number only by narrowing, and one that forgets the failure does not render a zero — it does not
48
+ * compile.
49
+ *
50
+ * **Staleness.** These numbers are as old as the manifest a client cached. They are right for a rail
51
+ * and must never be presented as live.
52
+ *
53
+ * ## Why this is not in `health.ts` (#430)
54
+ *
55
+ * It was, and that put the whole Workers data layer one type-only edge from a browser. `adminRoute.ts`
56
+ * imports `healthReport` and `HealthSummaryKey` to describe a manifest entry; every capability's
57
+ * control-plane scope declaration imports `AdminRoute` from `adminRoute.ts`; and `health.ts` imports
58
+ * `Capability` and `PithyHonoEnv`, which reach `data/db.ts` and `kv/kv.ts`. Eight modules a browser is
59
+ * meant to import were compiling `@cloudflare/workers-types`, `hono`, `kysely` and `kysely-d1` — 46 kit
60
+ * files to declare five strings — and `coverage.test.ts`'s type-only rule was satisfied throughout,
61
+ * because **the compiler follows a type-only edge exactly as it follows a value one**.
62
+ *
63
+ * So the seam is next door and this is the wire. This module's whole import list is `zod` and a scope,
64
+ * and the split is along a line nothing crosses: not one symbol here needs a `Context`, a `Capability`
65
+ * or an `InternalError`. `tooling/browser-scopes` compiles each scope declaration as a browser program
66
+ * and fails on anything but `zod`, so the line is held by a gate rather than by this paragraph.
67
+ */
68
+ /** A health key's name: one camelCase token, so it reads as a field and never as a path or an id. */
69
+ const HEALTH_KEY_PATTERN = /^[a-z][A-Za-z0-9]*$/;
70
+ /** What kind of scalar a key reports. */
71
+ const HealthValueKind = z.enum(["count", "state"]).describe("What kind of scalar this key reports: a `count` (a whole non-negative number) or a `state` (one member of a closed list). There is no third kind, because a third kind is how a summary becomes a projection.");
72
+ /**
73
+ * What producing one value costs on a manifest read.
74
+ *
75
+ * **There is deliberately no member for a scan.** That is the whole constraint expressed as a
76
+ * vocabulary: a capability whose number would need one cannot state its cost, so it cannot declare the
77
+ * key, so the manifest stays cheap by construction rather than by everybody remembering.
78
+ */
79
+ const HealthValueCost = z.enum(["memory", "indexed"]).describe("What this value costs to produce on a manifest read: `memory` for something already in the Worker's hands, `indexed` for a lookup an index answers and whose bound is a declaration rather than the adopter's data. No member names a scan, so a value that would need one cannot be declared.");
80
+ /**
81
+ * One value a summary may carry. A number or a member of a declared enum — never anything else.
82
+ *
83
+ * This is the rule the issue asked to be in the type: `number | string` has no room for a row, an id, a
84
+ * nested object, or a collection that grows with an adopter's data.
85
+ */
86
+ const HealthSummaryValue = z.union([z.number(), z.string()]).describe("One scalar: a number, or a member of the closed list its key declares. Nothing else is representable — no names, no ids, no rows, no nested objects.");
87
+ /** The compile-time half of "scalars only". Widen the value type and this line names the file. */
88
+ const HEALTH_SUMMARY_IS_SCALAR_ONLY = true;
89
+ /**
90
+ * What a count must be for its key to be nominal — a bound, in either direction or both.
91
+ *
92
+ * **Both are optional and at least one is required**, which is the whole of the shape. `atMost: 0` is
93
+ * `secretsDueForRotation`, where zero is the good answer; `atLeast: 1` is a count of things that must
94
+ * exist, where zero is the fault. A declaration carrying neither is a claim with no content, and one
95
+ * carrying an inverted pair is a claim nothing can satisfy — both would make every value on that key
96
+ * want attention forever, which is worse than declaring nothing.
97
+ *
98
+ * Inclusive at the edge. A cadence saying *no more than zero overdue* means zero is fine.
99
+ */
100
+ const HealthCountNominal = z.object({
101
+ atMost: z.number().int().nonnegative().optional().describe("The largest nominal value, inclusive. Above it the value wants attention."),
102
+ atLeast: z.number().int().nonnegative().optional().describe("The smallest nominal value, inclusive. Below it the value wants attention.")
103
+ }).describe("A count's nominal range: at least one bound, inclusive at its edge. Neither is a claim with no content; an inverted pair is one nothing can satisfy.");
104
+ /**
105
+ * What a key claims a nominal value is, or null where it makes no claim at all.
106
+ *
107
+ * **Null is the default and stays supported forever.** Some measures genuinely have no good or bad
108
+ * value — a count of things that simply exist — and a vocabulary that forced a claim would collect
109
+ * invented ones. What must never happen is a client reading null as *fine*; {@link standingOf} answers
110
+ * `unknowable` for it, and that is the point of this whole field.
111
+ */
112
+ const HealthNominal = z.union([HealthCountNominal, z.array(z.string().min(1))]).nullable().describe("What this key's nominal value is: a bound for a `count`, the nominal members for a `state`, or null where the capability makes no claim. Which shape applies is decided by `kind`.");
113
+ /**
114
+ * Whether a declared nominal fits the kind it was declared on.
115
+ *
116
+ * A free function rather than an inline predicate because the refine needs it before the object exists
117
+ * and because `states` is read from the same key — a `state` key's nominal must name members that key
118
+ * actually declares, or the claim is unverifiable: a producer can never send a value that matches it.
119
+ *
120
+ * Null is always suitable. That is the default, and a key that grades nothing is the common case.
121
+ */
122
+ function nominalSuitsKind(kind, nominal, states) {
123
+ if (nominal === null) return true;
124
+ if (kind === "count") {
125
+ if (Array.isArray(nominal)) return false;
126
+ const { atMost, atLeast } = nominal;
127
+ if (atMost === void 0 && atLeast === void 0) return false;
128
+ return atMost === void 0 || atLeast === void 0 || atLeast <= atMost;
129
+ }
130
+ if (!Array.isArray(nominal) || nominal.length === 0) return false;
131
+ return states === null ? true : nominal.every((member) => states.includes(member));
132
+ }
133
+ /**
134
+ * One key a capability may report, declared alongside its routes.
135
+ *
136
+ * `scope` is **not nullable**, unlike an admin route's. A route may need only a verified caller — the
137
+ * seam's `ping` does — but a number about somebody's posture never may, and an optional field here is a
138
+ * field somebody forgets.
139
+ */
140
+ const HealthSummaryKey = z.object({
141
+ key: z.string().regex(HEALTH_KEY_PATTERN, "A health key is one camelCase token — `secretsDueForRotation`.").describe("The key this value appears under in the capability's summary. One camelCase token."),
142
+ kind: HealthValueKind.describe("Whether the value is a count or a member of a closed list."),
143
+ states: z.array(z.string().min(1)).nullable().describe("Every value a `state` key may take, so a client can render each one it knows and nothing for one it does not. Null for a `count`, and required for a `state`: an enum with no members is a string field wearing a costume."),
144
+ scope: ControlPlaneScope.describe("The scope this value is behind — one the capability's own admin routes already require, never a new one. A caller without it gets no value rather than a zero."),
145
+ cost: HealthValueCost.describe("What producing this value costs on a manifest read."),
146
+ summary: z.string().min(1).describe("One line saying what the number means, for a client to render beside it without knowing the key."),
147
+ nominal: HealthNominal.default(null).describe("What a nominal value is for this key — a bound for a `count`, the nominal members for a `state`, or null where the capability makes no claim. A client reads null as `unknowable`, never as healthy.")
148
+ }).refine((key) => key.kind === "state" ? key.states !== null && key.states.length > 0 : key.states === null, {
149
+ message: "A `state` key declares a non-empty closed list; a `count` key declares none.",
150
+ path: ["states"]
151
+ }).refine((key) => nominalSuitsKind(key.kind, key.nominal, key.states), {
152
+ message: "A `count` key's nominal is a bound with at least one satisfiable side; a `state` key's is a non-empty list of members it declares.",
153
+ path: ["nominal"]
154
+ }).describe("One bounded scalar a capability contributes to its manifest entry: what it is called, what it may be, what it costs, and which scope it is behind.");
155
+ /**
156
+ * A capability's summary as the manifest carries it: declared key → scalar.
157
+ *
158
+ * A record rather than a closed object, because the vocabulary is federated the way scopes and audit
159
+ * actions are. **Parsing tolerates a key it has never heard of on purpose** — a client reading a newer
160
+ * Worker must render the unknown one as nothing rather than fail the whole manifest.
161
+ */
162
+ const HealthSummary = z.record(z.string(), HealthSummaryValue).describe("One capability's health summary: each declared key to its scalar. Unknown keys parse rather than throw, so a client of an older build renders what it knows and nothing for the rest.");
163
+ /**
164
+ * What one capability's summary is, for one caller. Four states, and the value carries which.
165
+ *
166
+ * A discriminated union rather than a nullable record with a flag beside it, and that is the whole
167
+ * point of #350. A flag is the same information and the opposite property: correct for whoever
168
+ * remembered to read it, and a zero for everybody else. Here the scalars are unreachable without
169
+ * narrowing on `state`, so forgetting the sick case is a type error rather than a screen that says
170
+ * everything is fine.
171
+ *
172
+ * - `undeclared` — the capability contributes no summary. Nothing to show, and nothing wrong.
173
+ * - `withheld` — it declares one, and this connection was not granted the scope it sits behind. Read
174
+ * `healthKeys` beside this and a client can say a number exists that it may not see.
175
+ * - `reported` — the values, each one named by a declaration that travels with it. Zero is one of these.
176
+ * - `unavailable` — producing the summary failed. Not zero, not withheld, and never both.
177
+ */
178
+ const CapabilityHealthReport = z.discriminatedUnion("state", [
179
+ z.object({ state: z.literal("undeclared").describe("This capability contributes no summary at all.") }).describe("A capability with nothing to report. Nothing to show, and nothing wrong."),
180
+ z.object({ state: z.literal("withheld").describe("A summary exists that this connection was not granted.") }).describe("A declared summary this caller may not see. Read `healthKeys` beside it to say a number exists rather than to say there is none."),
181
+ z.object({
182
+ state: z.literal("reported").describe("The summary was produced and this caller may see it."),
183
+ values: HealthSummary.describe("Each declared key this caller is entitled to, and its scalar. Zero is one.")
184
+ }).describe("The numbers, each one named by a declaration that travels beside it in `healthKeys`."),
185
+ z.object({ state: z.literal("unavailable").describe("Producing this capability's summary failed on this read.") }).describe("A summary that could not be produced. Deliberately empty: what the producer threw may name a row or a key, so nothing derived from it travels — there is nowhere to put it.")
186
+ ]).describe("What one capability's summary is, for one caller: nothing declared, declared and withheld, reported, or failed. The state is on the value, so a scalar is unreachable without narrowing.");
187
+ /**
188
+ * Read the four states off a manifest entry.
189
+ *
190
+ * **The failure flag is checked first and wins.** A Worker that sends both a failure and values is
191
+ * describing a producer that did not finish, and reading what it sent anyway is reading whatever the
192
+ * failure left behind.
193
+ *
194
+ * A Worker deployed before #350 sends no flag, which defaults to false, and lands on the three states
195
+ * it already had. A Worker deployed before #317 sends neither field and lands on `undeclared`.
196
+ */
197
+ function healthReport(entry) {
198
+ if (entry.healthUnavailable) return { state: "unavailable" };
199
+ if (entry.health) return {
200
+ state: "reported",
201
+ values: entry.health
202
+ };
203
+ return entry.healthKeys.length === 0 ? { state: "undeclared" } : { state: "withheld" };
204
+ }
205
+ /**
206
+ * Put a report back on the wire.
207
+ *
208
+ * The one place the two fields are written, so a handler cannot set the values and forget the flag.
209
+ * `undeclared` and `withheld` encode alike on purpose — `healthKeys` rides in the same entry and tells
210
+ * them apart, which is the arrangement #317 chose and this does not disturb.
211
+ */
212
+ function healthWire(report) {
213
+ return {
214
+ health: report.state === "reported" ? report.values : null,
215
+ healthUnavailable: report.state === "unavailable"
216
+ };
217
+ }
218
+ /**
219
+ * Pair a capability's reported values with their declarations, dropping any value nothing declares.
220
+ *
221
+ * This is how "an unknown summary key is renderable as nothing rather than as an error" is real rather
222
+ * than aspirational: a client renders what this returns, so a key from a Worker newer than its
223
+ * declaration simply is not in the list.
224
+ *
225
+ * **Only `reported` has values.** A withheld summary and a failed one both name nothing here, which is
226
+ * right for a list of numbers — and it is why a surface that must say *why* there is no number reads
227
+ * `state` rather than the length of this.
228
+ */
229
+ function namedHealthValues(descriptor) {
230
+ const health = descriptor.health;
231
+ if (health.state !== "reported") return [];
232
+ const named = [];
233
+ for (const key of descriptor.healthKeys) {
234
+ const value = health.values[key.key];
235
+ if (value !== void 0) named.push({
236
+ key,
237
+ value
238
+ });
239
+ }
240
+ return named;
241
+ }
242
+ /** Where {@link HealthSummaryValue} stands against the key that declared it. See {@link HealthStanding}. */
243
+ function standingOf(key, value) {
244
+ const nominal = key.nominal;
245
+ if (nominal == null) return "unknowable";
246
+ if (key.kind === "count") {
247
+ if (Array.isArray(nominal) || typeof value !== "number" || !Number.isInteger(value)) return "unknowable";
248
+ if (nominal.atMost !== void 0 && value > nominal.atMost) return "attention";
249
+ if (nominal.atLeast !== void 0 && value < nominal.atLeast) return "attention";
250
+ return "nominal";
251
+ }
252
+ if (!Array.isArray(nominal) || typeof value !== "string") return "unknowable";
253
+ return nominal.includes(value) ? "nominal" : "attention";
254
+ }
255
+ /**
256
+ * Every value this capability reported that wants somebody's attention, in declaration order.
257
+ *
258
+ * `namedHealthValues` one filter later, and here rather than in every client so the filter is written
259
+ * once. The three stateless reports answer empty: `undeclared`, `withheld` and `unavailable` are states
260
+ * of the *report* rather than of any value, and folding one of them into a list of graded measures is
261
+ * exactly the collapse #350 and #471 each exist to prevent — a withheld number is not a bad number, and
262
+ * a failed read is not a finding about the thing that failed to be read.
263
+ *
264
+ * A value standing at `unknowable` is not here either. The list is what wants attention, and a measure
265
+ * nobody grades cannot want it.
266
+ *
267
+ * **So an empty list is not a clean bill of health, and a client that renders it as one has rebuilt
268
+ * #471 one layer up.** Five situations answer `[]`: nothing declared, withheld, unavailable, everything
269
+ * nominal, and everything ungradeable. Three of those are *could not look* rather than *nothing is
270
+ * wrong*. A surface that wants to tell them apart has what it needs — the report's own state separates
271
+ * the first three, and mapping {@link namedHealthValues} through {@link standingOf} separates the last
272
+ * two — but it has to ask, and this function deliberately does not answer it.
273
+ */
274
+ function healthAttention(descriptor) {
275
+ return namedHealthValues(descriptor).filter((named) => standingOf(named.key, named.value) === "attention");
276
+ }
277
+ //#endregion
278
+ export { CapabilityHealthReport, HEALTH_SUMMARY_IS_SCALAR_ONLY, HealthCountNominal, HealthNominal, HealthSummary, HealthSummaryKey, HealthSummaryValue, HealthValueCost, HealthValueKind, healthAttention, healthReport, healthWire, namedHealthValues, standingOf };
@@ -0,0 +1,67 @@
1
+ import { PithyError } from "../../error/pithyError";
2
+ import type { MessageParams } from "../../i18n/catalog";
3
+ /**
4
+ * The `control-plane` strategy's throw sugar. The `controlplane/*` codes live in core's closed
5
+ * `KitErrorPayload` union (CLAUDE.md §Errors); these subclasses are the vehicles that set one.
6
+ *
7
+ * The security posture here is stricter than elsewhere in the tree. Public `message` and `action` are
8
+ * written for an operator reading a management client's logs, and say nothing a caller could use to
9
+ * probe the seam. Throw-site context — which verification step failed, which `kid` was presented,
10
+ * which environment the connection is bound to — goes in `detail`, which the HTTP codec strips.
11
+ *
12
+ * {@link ControlPlaneInvalidCredentialError} in particular is deliberately one error for every
13
+ * failing step. Distinguishing "unknown key" from "bad signature" from "replayed token" would turn
14
+ * the response into an oracle that tells an attacker exactly how far they got.
15
+ */
16
+ interface ControlPlaneErrorArgs {
17
+ message?: string;
18
+ action?: string;
19
+ detail?: string;
20
+ /**
21
+ * Values a translating client interpolates into its own wording for this code. Client-facing, so —
22
+ * unlike `action` and `detail` — these cross the boundary with `message`.
23
+ */
24
+ params?: MessageParams;
25
+ }
26
+ /**
27
+ * No connection is registered for this environment. The shipped default of a Worker that composes the
28
+ * seam and has never been connected — present, and denying everything.
29
+ */
30
+ export declare class ControlPlaneNotConnectedError extends PithyError {
31
+ constructor(args?: ControlPlaneErrorArgs, options?: {
32
+ cause?: unknown;
33
+ });
34
+ }
35
+ /**
36
+ * The credential failed verification. One error for every step — pass the step in `detail` so the log
37
+ * can say which, and the caller cannot.
38
+ */
39
+ export declare class ControlPlaneInvalidCredentialError extends PithyError {
40
+ constructor(args?: ControlPlaneErrorArgs, options?: {
41
+ cause?: unknown;
42
+ });
43
+ }
44
+ /** The credential verified, but nothing granted it this operation. */
45
+ export declare class ControlPlaneInsufficientScopeError extends PithyError {
46
+ constructor(args?: ControlPlaneErrorArgs, options?: {
47
+ cause?: unknown;
48
+ });
49
+ }
50
+ /** The named key is not registered on this connection. */
51
+ export declare class ControlPlaneKeyNotFoundError extends PithyError {
52
+ constructor(args?: ControlPlaneErrorArgs, options?: {
53
+ cause?: unknown;
54
+ });
55
+ }
56
+ /**
57
+ * A key operation conflicts with the connection's current state — a duplicate registration, or an
58
+ * expiry that would leave no live key. The second is the lockout case, and refusing it is the reason
59
+ * expiry is a separate call from registration.
60
+ */
61
+ export declare class ControlPlaneKeyConflictError extends PithyError {
62
+ constructor(args?: ControlPlaneErrorArgs, options?: {
63
+ cause?: unknown;
64
+ });
65
+ }
66
+ export {};
67
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,79 @@
1
+ import { PithyError } from "../../error/pithyError.js";
2
+ //#region src/controlPlane/error/errors.ts
3
+ /**
4
+ * No connection is registered for this environment. The shipped default of a Worker that composes the
5
+ * seam and has never been connected — present, and denying everything.
6
+ */
7
+ var ControlPlaneNotConnectedError = class extends PithyError {
8
+ constructor(args = {}, options) {
9
+ super({
10
+ code: "controlplane/not_connected",
11
+ status: 403,
12
+ message: args.message ?? "No management client is connected to this environment.",
13
+ action: args.action ?? "Run pithy dashboard connect --env <environment> to register one.",
14
+ detail: args.detail,
15
+ params: args.params
16
+ }, options);
17
+ }
18
+ };
19
+ /**
20
+ * The credential failed verification. One error for every step — pass the step in `detail` so the log
21
+ * can say which, and the caller cannot.
22
+ */
23
+ var ControlPlaneInvalidCredentialError = class extends PithyError {
24
+ constructor(args = {}, options) {
25
+ super({
26
+ code: "controlplane/invalid_credential",
27
+ status: 401,
28
+ message: args.message ?? "That credential is not valid here.",
29
+ action: args.action ?? "Rotate the connection's key, or re-run pithy dashboard connect --update.",
30
+ detail: args.detail,
31
+ params: args.params
32
+ }, options);
33
+ }
34
+ };
35
+ /** The credential verified, but nothing granted it this operation. */
36
+ var ControlPlaneInsufficientScopeError = class extends PithyError {
37
+ constructor(args = {}, options) {
38
+ super({
39
+ code: "controlplane/insufficient_scope",
40
+ status: 403,
41
+ message: args.message ?? "This connection is not scoped for that operation.",
42
+ action: args.action ?? "Re-run pithy dashboard connect --update and grant the scope this call needs.",
43
+ detail: args.detail,
44
+ params: args.params
45
+ }, options);
46
+ }
47
+ };
48
+ /** The named key is not registered on this connection. */
49
+ var ControlPlaneKeyNotFoundError = class extends PithyError {
50
+ constructor(args = {}, options) {
51
+ super({
52
+ code: "controlplane/key_not_found",
53
+ status: 404,
54
+ message: args.message ?? "No registered key answers to that key id.",
55
+ action: args.action ?? "Read GET /control-plane/keys for the keys this connection currently trusts.",
56
+ detail: args.detail,
57
+ params: args.params
58
+ }, options);
59
+ }
60
+ };
61
+ /**
62
+ * A key operation conflicts with the connection's current state — a duplicate registration, or an
63
+ * expiry that would leave no live key. The second is the lockout case, and refusing it is the reason
64
+ * expiry is a separate call from registration.
65
+ */
66
+ var ControlPlaneKeyConflictError = class extends PithyError {
67
+ constructor(args = {}, options) {
68
+ super({
69
+ code: "controlplane/key_conflict",
70
+ status: 409,
71
+ message: args.message ?? "That key operation conflicts with the connection's current state.",
72
+ action: args.action ?? "Register the replacement key and prove it with a ping before expiring this one.",
73
+ detail: args.detail,
74
+ params: args.params
75
+ }, options);
76
+ }
77
+ };
78
+ //#endregion
79
+ export { ControlPlaneInsufficientScopeError, ControlPlaneInvalidCredentialError, ControlPlaneKeyConflictError, ControlPlaneKeyNotFoundError, ControlPlaneNotConnectedError };
@@ -0,0 +1,112 @@
1
+ import type { Hono, MiddlewareHandler } from "hono";
2
+ import type { PithyHonoEnv } from "../../capability/capability";
3
+ import type { AdminRoute } from "../discovery/adminRoute";
4
+ /**
5
+ * Whether this request may use the **local dev** allowance: a loopback origin, in the dev environment.
6
+ *
7
+ * A console an adopter runs against a local Worker sits on `http://localhost:<port>`, on a port the dev
8
+ * port allocator picked. Nobody can write that into `allowedOrigins` and have it stay true across
9
+ * checkouts, so in dev the seam simply allows this machine.
10
+ *
11
+ * **Two guards: `ENVIRONMENT` is `dev`, and the hostname is loopback.** Take the first for what it is
12
+ * — a var the adopter stamps, and `pithy init` writes `dev` into the top-level `wrangler.jsonc` stanza
13
+ * (`cli/src/project/workerScaffold.ts`) that a bare `pithy deploy` publishes. So this is not a claim
14
+ * that the allowance cannot appear on a deployed Worker.
15
+ *
16
+ * It is a claim about what the allowance is *worth*, and that holds wherever it appears. The origins it
17
+ * admits name the caller's **own machine**. No ambient authority crosses, because
18
+ * `Access-Control-Allow-Credentials` is never set on this surface and the token is an explicit header.
19
+ * And every admin route still demands a verified control-plane token. So the most this permits is a
20
+ * local page reading a reply it could have fetched directly, which is not a capability anyone gains.
21
+ *
22
+ * **Do not reach for `<STEM>_ORIGIN` here.** It looks like the precise version of this and it does not
23
+ * work: `pithy dev` publishes those into each child *process*, and the host environment does not cross
24
+ * into workerd — `cli/src/dev/env.ts:157-165`. Only capability *hosts* are forwarded as `--var`
25
+ * (`hostVarArgs`), deliberately (#410), and a UI worker is not one. So a Worker's `env` never carries
26
+ * the console's address, and a version of this that read one allowed exactly the origins no browser
27
+ * calls while reading as though it did more.
28
+ *
29
+ * It is a per-request read rather than part of {@link allowedOriginSet} because in Workers there is no
30
+ * `env` until a request arrives.
31
+ */
32
+ export declare function devLoopbackAllows(env: Record<string, unknown>, origin: string): boolean;
33
+ /**
34
+ * One origin, normalized the way a browser spells it, or `null` when the value is not one.
35
+ *
36
+ * Applied to both ends deliberately. `issuer` is a `z.url()` that predates this module and may legally
37
+ * carry a path or a trailing slash, and an `Access-Control-Allow-Origin` carrying either matches no
38
+ * browser `Origin` — so it is normalized rather than trusted. The incoming header is normalized for the
39
+ * same reason from the other direction: it is not ours, and comparing raw strings would turn a spelling
40
+ * difference into a refusal nobody can diagnose.
41
+ */
42
+ export declare function originOf(value: string | null | undefined): string | null;
43
+ /**
44
+ * The effective allow-list: `[issuer, ...allowedOrigins]`, normalized, then deduped.
45
+ *
46
+ * Additive in that order and never replacing, which is the property the whole shape rests on: an
47
+ * adopter who adds their own console cannot silently drop the dashboard that was already working, and
48
+ * a replacing default would have done exactly that the first time someone wrote a single entry.
49
+ * Dedupe happens **after** normalization, so `https://app.pithy.sh` and `https://app.pithy.sh/` are one
50
+ * entry rather than two.
51
+ */
52
+ export declare function allowedOriginSet(config: {
53
+ issuer: string;
54
+ allowedOrigins: readonly string[];
55
+ }): ReadonlySet<string>;
56
+ /** One path's precomputed answer. Built once at composition; nothing here is derived per request. */
57
+ export interface CorsSurfaceEntry {
58
+ /** The fully mounted path, exactly as the descriptor declares it — `:segment` params included. */
59
+ path: string;
60
+ /** `Access-Control-Allow-Methods`: every method declared on this path, plus `OPTIONS`. */
61
+ allowMethods: string;
62
+ /** `Access-Control-Allow-Headers`: the token header, plus `content-type` where a body is plausible. */
63
+ allowHeaders: string;
64
+ }
65
+ /**
66
+ * Fold every composed capability's `adminRoutes` into one entry per distinct path.
67
+ *
68
+ * **The descriptors are the surface.** They already exist, a management client already navigates by
69
+ * them, and `routeContract.test.ts` already proves they agree with the mounted router — so deriving
70
+ * CORS from the same table means a capability that adds an admin route gets its preflight for free and
71
+ * there is no second list to drift. The alternative considered and rejected was an app-wide
72
+ * `app.use("*", …)`, which would attach dashboard origins to the adopter's own API — a different
73
+ * surface, with different origins, that is not the kit's decision to make.
74
+ *
75
+ * **`content-type` keys on the method, not on whether the route takes a body.** {@link AdminRoute}
76
+ * carries no body flag, and adding one is worse than the proxy it would replace: that type is read
77
+ * across a version boundary by the management client, so a new field must be `.optional()` and an
78
+ * absent optional says less than the method already does.
79
+ */
80
+ export declare function corsSurface(capabilities: readonly {
81
+ adminRoutes?: readonly AdminRoute[];
82
+ }[]): CorsSurfaceEntry[];
83
+ /**
84
+ * The per-path middleware: answer the preflight, and mark the real response readable.
85
+ *
86
+ * Both halves are here rather than in an `app.options(…)` of their own, because a preflight that is
87
+ * allowed and a response that cannot be read is the same failure as no preflight at all — the browser
88
+ * blocks a `GET` whose response carries no `Access-Control-Allow-Origin`, `204` or not.
89
+ */
90
+ export declare function corsMiddleware(entry: CorsSurfaceEntry, origins: ReadonlySet<string>, maxAgeSeconds: number): MiddlewareHandler<PithyHonoEnv>;
91
+ /**
92
+ * Mount one `app.use(path, …)` per entry.
93
+ *
94
+ * **Called from the capability's `middleware` hook, never its `routes` hook, and that is load-bearing.**
95
+ * `createBackend` runs every capability's `middleware` hook before **any** capability's `routes` hook
96
+ * (`createBackend.ts:262-267`), which is what makes this independent of the order an adopter happens to
97
+ * list their capabilities in.
98
+ *
99
+ * From `routes` it looks like it works and does not. The preflight still answers — an `OPTIONS` has no
100
+ * route handler to lose to, so this `use` is the only thing that matches it — but a capability composed
101
+ * *before* the seam has already registered its terminal handler, and a terminal handler never calls
102
+ * `next()`, so the middleware after it never runs. The real response then carries no
103
+ * `Access-Control-Allow-Origin` and the browser blocks a `200` the caller was entitled to read: a
104
+ * preflight that passes and a read that fails, which is a worse failure than the one this fixes because
105
+ * it looks configured. `cors.test.ts` §"the registration slot" pins it by composing the seam last.
106
+ *
107
+ * Exact paths, never a wildcard: `app.use` on a literal path does not match subpaths, so "nothing
108
+ * outside the control-plane surface gains a CORS header" is structural rather than a check that could
109
+ * be got wrong.
110
+ */
111
+ export declare function registerControlPlaneCors(app: Hono<PithyHonoEnv>, surface: readonly CorsSurfaceEntry[], origins: ReadonlySet<string>, maxAgeSeconds: number): void;
112
+ //# sourceMappingURL=cors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/cors.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAmC1D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAOvF;AAKD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAUxE;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CAOnH;AAED,qGAAqG;AACrG,MAAM,WAAW,gBAAgB;IAC/B,kGAAkG;IAClG,IAAI,EAAE,MAAM,CAAC;IACb,0FAA0F;IAC1F,YAAY,EAAE,MAAM,CAAC;IACrB,uGAAuG;IACvG,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,SAAS;IAAE,WAAW,CAAC,EAAE,SAAS,UAAU,EAAE,CAAA;CAAE,EAAE,GAAG,gBAAgB,EAAE,CAoBhH;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,aAAa,EAAE,MAAM,GACpB,iBAAiB,CAAC,YAAY,CAAC,CAmCjC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,IAAI,CAAC,YAAY,CAAC,EACvB,OAAO,EAAE,SAAS,gBAAgB,EAAE,EACpC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,aAAa,EAAE,MAAM,GACpB,IAAI,CAEN"}