@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,501 @@
1
+ import type { ExecutionContext, ForwardableEmailMessage } from "@cloudflare/workers-types";
2
+ import type { Hono } from "hono";
3
+ import type { z } from "zod";
4
+ import type { AuditEmit } from "../audit/recorder";
5
+ import type { ControlPlaneContext } from "../controlPlane/context";
6
+ import type { AdminRoute } from "../controlPlane/discovery/adminRoute";
7
+ import type { CapabilityManifestConfig } from "../controlPlane/discovery/configuration";
8
+ import type { CapabilityHealth } from "../controlPlane/discovery/health";
9
+ import type { ControlPlaneVerifier } from "../controlPlane/http/guard";
10
+ import type { DatabaseSpecMap } from "../data/databases";
11
+ import type { EntitlementResolver } from "../entitlement/entitlement";
12
+ import type { AuthContext } from "../http/authContext";
13
+ import type { SameOriginGate } from "../http/sameOrigin";
14
+ import type { LocaleCatalogs } from "../i18n/catalog";
15
+ import type { LocaleContext } from "../i18n/locale";
16
+ import type { Translator } from "../i18n/translator";
17
+ import type { KvNamespaceSpecMap } from "../kv/namespaces";
18
+ import type { Logger } from "../logger/logger";
19
+ import type { SeedSet } from "../seed/seed";
20
+ import type { WorkflowSpecMap } from "../workflow/spec";
21
+ import { BindingSpec, type BindingSpecInput } from "./bindings";
22
+ import type { ClientProjection, ClientProjectionContext } from "./client";
23
+ import type { CapabilitySettings } from "./settings";
24
+ /** Hono `Variables` every capability's routes are typed against. `createBackend` seeds these per request. */
25
+ export interface PithyVars {
26
+ /** The authenticated identity, populated by `@pithy-sh/auth`; `null` until a strategy sets it. */
27
+ auth: AuthContext | null;
28
+ /**
29
+ * The resolved request locale, populated by `@pithy-sh/i18n`'s middleware; `null` in a Worker that
30
+ * does not compose it — which is what "nothing was negotiated" looks like, as distinct from "the
31
+ * default was chosen".
32
+ *
33
+ * Read {@link PithyVars.t} to render a message. This is here for the surfaces that need the tags
34
+ * themselves: `lang`/`dir` on a document, the locale stamped onto an email job's row.
35
+ */
36
+ locale: LocaleContext | null;
37
+ /**
38
+ * The translator seam (`c.var.t`) — every user-facing string a capability renders goes through it.
39
+ *
40
+ * **Zero-config, so nothing null-checks it**, exactly like {@link PithyVars.log}. With no i18n
41
+ * capability composed it is a translator over the baked English every composed capability
42
+ * contributed through {@link Capability.messages}, which is why a project that never opts in behaves
43
+ * byte for byte as it did before.
44
+ */
45
+ t: Translator;
46
+ /**
47
+ * The verified control-plane caller (`c.var.controlPlane`), populated only by the `control-plane`
48
+ * middleware; `null` on every other request. Read through `requireControlPlane(scope)`.
49
+ *
50
+ * Deliberately a second variable rather than a flavour of {@link auth}. A management client is not a
51
+ * user of the adopter's app — it holds no session and owns no user row — so if a control-plane call
52
+ * set `auth`, every `requireAuth()` in every capability would pass for it. That is a scope escalation
53
+ * across the whole tree, and separating the two seams is what makes it impossible rather than merely
54
+ * unlikely.
55
+ */
56
+ controlPlane: ControlPlaneContext | null;
57
+ /**
58
+ * The seam's verifier, published by the `controlplane()` capability's middleware and consumed by
59
+ * `requireControlPlane(scope)`; `null` when that capability is not composed.
60
+ *
61
+ * It exists so a capability contributing admin routes — `@pithy-sh/payments` is the first — can write
62
+ * `requireControlPlane(...)` at module scope without holding the adopter's seam config and without
63
+ * importing from a sibling package. `null` is what makes those routes **deny** in a Worker that never
64
+ * enabled the seam, rather than stand open because the thing meant to protect them is absent.
65
+ */
66
+ controlPlaneVerifier: ControlPlaneVerifier | null;
67
+ /**
68
+ * The same-origin CSRF gate, published **already bound** to this Worker's trusted origins by the
69
+ * capability that resolved them (`@pithy-sh/auth`, from its `baseURL` and `trustedOrigins`); `null`
70
+ * when none is composed. Read through `requireSameOrigin()`, which takes no argument.
71
+ *
72
+ * A bound gate rather than the origin list, and for the same reason {@link controlPlaneVerifier} is a
73
+ * verifier rather than the seam's config: an adopter's routes need the decision, not the material to
74
+ * rebuild it. Handing over the list is how a Worker ends up with two same-origin implementations,
75
+ * free to disagree — and the weaker one is then its real policy.
76
+ */
77
+ sameOrigin: SameOriginGate | null;
78
+ /**
79
+ * The audit recorder seam. Any capability records a security-relevant action with `c.var.emit(...)`
80
+ * (CLAUDE.md §Security). `@pithy-sh/audit` replaces the default with a D1-backed recorder; with no
81
+ * audit capability composed it is the no-op `noopEmit`. Non-fatal by contract — never throws — so
82
+ * an audited action is never broken by an audit write.
83
+ */
84
+ emit: AuditEmit;
85
+ /**
86
+ * The entitlement resolver seam — every entitlement the current caller holds. A paid route gates on
87
+ * it with `requireEntitlement("pro")`; `@pithy-sh/payments` replaces the default with a D1-backed
88
+ * resolver over its materialized read model.
89
+ *
90
+ * **The default denies**, which is the one place this seam deliberately differs from `emit`: a
91
+ * missing audit write cannot grant access, but a missing entitlement check can. With no provider
92
+ * composed it is {@link noEntitlementProvider} — holds nothing, so every gate 403s.
93
+ */
94
+ entitlements: EntitlementResolver;
95
+ /**
96
+ * The logger seam (`c.var.log`). `createBackend` binds a per-request logger carrying request
97
+ * correlation (`request`/`method`/`path`/`env`/`version`); capabilities log through it instead of
98
+ * `console`, and derive a namespaced sub-logger with `c.var.log.child("<capability>")`. Zero-config:
99
+ * a real logger is always present, so nothing null-checks it. Never wire it to a client surface — it
100
+ * carries `PithyError` `detail`, the inverse of the HTTP codec.
101
+ */
102
+ log: Logger;
103
+ /**
104
+ * Per-request D1 database registry. Loosely `unknown` on this base seam so the contract stays
105
+ * decoupled from any schema; `createBackend`'s return types it precisely as `DbRegistry`
106
+ * (`c.var.db.<database>`). Inside a capability, cast to `DbRegistry<YourDatabases>`.
107
+ */
108
+ db: unknown;
109
+ /**
110
+ * Per-request KV namespace registry. Loosely `unknown` here; `createBackend`'s return types it as
111
+ * the merged `KvRegistry` (`c.var.kv.<namespace>.<store>`). Inside a capability, cast to
112
+ * `KvRegistry<YourNamespaces>`.
113
+ */
114
+ kv: unknown;
115
+ /**
116
+ * The durable-job dispatcher — `c.var.workflows.trigger("media/image-to-text", { id })`. Loosely
117
+ * `unknown` on this base seam for the same reason as `db`/`kv`: the precise key and parameter
118
+ * types depend on which capabilities are composed, and `createBackend`'s return narrows it.
119
+ * Inside a capability, cast to `WorkflowDispatcher<YourParams>`.
120
+ */
121
+ workflows: unknown;
122
+ }
123
+ /** The Hono env. `Bindings` and `Variables` are the base seam; `createBackend` returns a precisely-typed env. */
124
+ export type PithyHonoEnv = {
125
+ Bindings: Record<string, unknown>;
126
+ Variables: PithyVars;
127
+ };
128
+ export type PithyMiddleware = (app: Hono<PithyHonoEnv>) => void;
129
+ /**
130
+ * The structural seam for one capability's secret-registry slice — secret name → its declaration.
131
+ * Core carries it on the {@link Capability} contract so a capability can declare which secrets it
132
+ * reads (CLAUDE.md §secrets: every secret is declared in a registry), without core depending on
133
+ * `@pithy-sh/secrets`. The concrete entry shape, the `defineSecretRegistry` authoring helper, the
134
+ * `secretsStore` reader, and the startup aggregation all live in `@pithy-sh/secrets`; core only
135
+ * needs the common axes (read, never interpreted here) so the seam stays a precise supertype of
136
+ * that package's `SecretRegistry`.
137
+ */
138
+ export interface SecretRegistryEntrySeam {
139
+ /** Storage backend (`d1` | `cf-secrets-store`). */
140
+ readonly backend: string;
141
+ /** Whether the value differs per environment or is identical everywhere. */
142
+ readonly scope: string;
143
+ /** Whether a future value-rotator may manage the secret. */
144
+ readonly rotatable: boolean;
145
+ /** How a decrypted value is interpreted (`text` | `json`). */
146
+ readonly valueType: string;
147
+ /**
148
+ * How a dev value for this secret may be minted (`random`), or absent when it may not be — because
149
+ * the value must match something outside the project (an OAuth app, a Stripe account). The
150
+ * capability that owns the secret decides; `pithy add` reads the same declaration off the manifest,
151
+ * which it can do without executing the package.
152
+ */
153
+ readonly devValue?: string;
154
+ }
155
+ /** A capability's secret-registry slice: secret name → {@link SecretRegistryEntrySeam}. */
156
+ export type SecretRegistrySeam = Record<string, SecretRegistryEntrySeam>;
157
+ /**
158
+ * The structural seam for one capability's token-profile slice — profile name → the scoped CF API
159
+ * token that capability's code needs. Declared next to the code that uses it (alongside
160
+ * {@link Capability.secretRegistry}), so a capability owns its token's least-privilege scope and where
161
+ * the minted value lands. Core carries only the structural axes (never interpreted here); the concrete
162
+ * `TokenProfile`, the permission catalog, `defineTokenProfile`, and the mint engine live in
163
+ * `@pithy-sh/cloudflare`/the CLI. `pithy token` aggregates every capability's slice into one registry.
164
+ */
165
+ export interface TokenProfileSeam {
166
+ /** The CF permissions the token grants, as short catalog keys (`d1:read`, `secrets:write`). */
167
+ readonly permissions: readonly string[];
168
+ /** The resource scope: `"account"` (the whole account, the default) or an explicit CF resource map. */
169
+ readonly resources?: "account" | Record<string, string>;
170
+ /** The secret-registry name the minted value is stored under — its backend decides the destination. */
171
+ readonly secret?: string;
172
+ /** A built-in destination override (`dev-vars` | `ephemeral` | `secrets-store`) for a tooling profile. */
173
+ readonly defaultStore?: string;
174
+ /** Why the profile exists / what consumes it — surfaced in `pithy token` help and docs. */
175
+ readonly description?: string;
176
+ }
177
+ /** A capability's token-profile slice: profile name → {@link TokenProfileSeam}. */
178
+ export type TokenProfileSeamMap = Record<string, TokenProfileSeam>;
179
+ /**
180
+ * One thing an **adopter** plugged into a capability — the capability's own name for something the kit
181
+ * did not ship and cannot enumerate. `@pithy-sh/auth` declares one per additional Better Auth plugin
182
+ * (`{ kind: "better-auth-plugin", id: "organization", tables: ["organization", "member", "invitation"] }`).
183
+ *
184
+ * It exists because an extension is otherwise **invisible**. A capability composed from a package has a
185
+ * name and a version the CLI can read off `package.json`; something an adopter passed into a
186
+ * capability's config has neither, and it can still add routes to the Worker and tables to the database.
187
+ * `pithy doctor` reports these the way it reports capabilities, from this one field, so a new extension
188
+ * point in any capability is a line in the report rather than a new branch in the CLI.
189
+ *
190
+ * Descriptive, never behavioral: nothing in the runtime reads it, and no command acts on it. A
191
+ * capability that lies here has told a diagnostic something untrue, which is why every field is
192
+ * something the capability has already resolved rather than something it intends.
193
+ */
194
+ export interface CapabilityExtension {
195
+ /** What kind of extension point this is, in the capability's own vocabulary (e.g. `better-auth-plugin`). */
196
+ readonly kind: string;
197
+ /** The extension's identity within that kind — what an adopter would go and delete. */
198
+ readonly id: string;
199
+ /** The database tables it introduced, if any, by the name the migration creates them under. */
200
+ readonly tables?: readonly string[];
201
+ }
202
+ /**
203
+ * Context handed to a capability's {@link Capability.compose} hook at worker startup: every composed
204
+ * capability (libraries + app), so a capability can perform cross-capability wiring it could not do
205
+ * at construction time (when it sees only itself). `@pithy-sh/secrets` uses it to aggregate every
206
+ * capability's {@link Capability.secretRegistry} slice into one combined registry for the shared
207
+ * per-invocation secrets accessor.
208
+ */
209
+ export interface CapabilityComposeContext {
210
+ /** Every capability composed into this backend, in composition order (libraries first, app last). */
211
+ capabilities: readonly Capability[];
212
+ }
213
+ /**
214
+ * An inbound-email handler. A Worker has a single `email()` entry, so the Pithy entrypoint
215
+ * (`createEntrypoint`) fans every incoming message out to each capability that declares one —
216
+ * used for bounce/complaint processing (`@pithy-sh/email`) and any other inbound-mail concern.
217
+ * `env` is the Worker's per-invocation bindings; the handler must consume, forward, or reject the
218
+ * message (an untouched message is dropped by the runtime).
219
+ *
220
+ * **`ForwardableEmailMessage` and `ExecutionContext` are imported rather than assumed ambient**, and
221
+ * that is the whole of #315's second half. This module is reachable from a client: a browser program
222
+ * that names a control-plane scope through a capability's guards lands here, and a browser program
223
+ * has no Workers globals. Read off the global scope, the two names resolved only for a consumer that
224
+ * had `@cloudflare/workers-types` in its `types` — so an adopter's DOM program failed on two errors
225
+ * in *our* source, with no way to fix them short of excluding the kit from typechecking. Imported by
226
+ * name they resolve from the package, which `@pithy-sh/core` now declares as a dependency rather than
227
+ * a devDependency for exactly this reason: a type this file names is a type its consumers must be
228
+ * able to get. `tooling/browser-scopes` compiles with `types: []` and keeps it that way.
229
+ */
230
+ export type CapabilityEmailHandler = (message: ForwardableEmailMessage, env: Record<string, unknown>, ctx: ExecutionContext) => void | Promise<void>;
231
+ /**
232
+ * The single composition contract. `core`, each capability, and the app all implement it,
233
+ * contributing any subset of {config, migrations, routes, middleware, workflows, databases,
234
+ * kvNamespaces, bindings}. Capabilities depend on core seams (e.g. AuthContext), never on each
235
+ * other's internals.
236
+ *
237
+ * `Databases`/`Namespaces` carry this capability's database and KV-namespace slices so
238
+ * `createBackend` can infer the project-wide merged types. A bare `Capability` annotation widens
239
+ * them; `defineCapability` infers the precise literals.
240
+ */
241
+ export interface Capability<Databases extends DatabaseSpecMap = DatabaseSpecMap, Namespaces extends KvNamespaceSpecMap = KvNamespaceSpecMap, Name extends string = string, Workflows extends WorkflowSpecMap = WorkflowSpecMap> {
242
+ /**
243
+ * The capability's identity: the `pithy add <name>` argument, the migration namespace, the
244
+ * `pithy_<name>_*` table prefix, the error-code domain, and the first segment of every workflow
245
+ * dispatch key. `defineCapability` captures it as a literal so those keys type precisely.
246
+ */
247
+ name: Name;
248
+ /**
249
+ * Other capabilities this one needs composed alongside it (by `name`) — the runtime mirror of the
250
+ * manifest's `peerCapabilities`. `createBackend` fails fast at assembly if a listed peer is absent,
251
+ * so a capability that reads another's seam (e.g. turnstile reading secrets) surfaces a missing
252
+ * dependency at startup rather than as a per-request error.
253
+ */
254
+ dependsOn?: readonly string[];
255
+ /** Validated env/config/secrets for this capability. */
256
+ config?: z.ZodType;
257
+ /**
258
+ * The user-facing strings this capability owns, keyed by locale then by `<domain>/<path>` —
259
+ * the peer of {@link Capability.migrations} and {@link Capability.seeds}, merged the same way.
260
+ *
261
+ * **A capability may only declare keys under its own `name`**, and `composeMessages` refuses
262
+ * anything else. That is the `pithy_<capability>_<table>` rule and the `auth/invalid_token` rule,
263
+ * for the third time and for the same reason: the domain segment is what makes two capabilities'
264
+ * contributions incapable of colliding. For an error the key *is* the code, so `KitErrorCode` is the
265
+ * checklist a locale has to cover and there is no second identifier to keep in sync.
266
+ *
267
+ * Kit packages contribute their **English**, which is what makes the i18n capability optional: with
268
+ * nothing composed, `c.var.t` is a translator over exactly this. Translations ship in
269
+ * `@pithy-sh/i18n`, so a typo fix or a new locale reaches every adopter as a package upgrade rather
270
+ * than as a merge into files they own. An adopter's own `app` capability contributes here too, under
271
+ * its own domain, exactly as a kit package does.
272
+ */
273
+ messages?: LocaleCatalogs;
274
+ /**
275
+ * The secrets this capability reads, as a registry slice (CLAUDE.md §secrets). Additive and
276
+ * optional. `@pithy-sh/secrets` aggregates every capability's slice into one combined registry at
277
+ * worker startup (via {@link Capability.compose}), so the shared per-invocation accessor resolves
278
+ * every declared secret in one batch — and no capability needs to know another's secrets.
279
+ */
280
+ secretRegistry?: SecretRegistrySeam;
281
+ /**
282
+ * The scoped CF API tokens this capability's code needs, as a token-profile slice (profile name →
283
+ * {@link TokenProfileSeam}). Additive and optional, and declared next to {@link Capability.secretRegistry}
284
+ * — the value of a minted token lands in the secret the profile names. `pithy token` aggregates every
285
+ * capability's slice with the built-in tooling profiles into one registry.
286
+ */
287
+ tokenProfiles?: TokenProfileSeamMap;
288
+ /**
289
+ * Extra CF permissions this capability needs the **CI system token** to hold, as short catalog keys
290
+ * (e.g. `email:routing` for email provisioning, `kv:write` for a module that seeds KV in CI). They
291
+ * union into the one `ci-system` token `pithy token mint ci-system` produces — so a new capability
292
+ * extends what CI can do without the adopter hand-editing token scopes. Additive and optional.
293
+ */
294
+ ciPermissions?: readonly string[];
295
+ /**
296
+ * The admin routes this capability contributes behind the `control-plane` strategy, described well
297
+ * enough for a management client to call them — full mounted path, required scope, and a one-line
298
+ * summary. Omit it, or leave it empty, when a capability has no management surface; that is the
299
+ * normal case.
300
+ *
301
+ * Federated the same way migrations, error codes, and audit actions are: a capability declares its
302
+ * own and `GET /control-plane/manifest` reports the union, so a management client composes both its
303
+ * navigation *and* its calls from what the Worker says about itself. Knowing a capability is
304
+ * installed is not enough to call it — `basePath` is configurable, so a client that hardcoded
305
+ * `/payments` breaks against an adopter who mounted it at `/billing`.
306
+ *
307
+ * **Build the paths from the capability's resolved config, never from its defaults**, or the
308
+ * declaration describes a Worker other than this one. `missingAdminRoutes` checks each entry against
309
+ * the router that actually mounted; a stale declaration is worse than none, because a client
310
+ * believes it.
311
+ */
312
+ adminRoutes?: readonly AdminRoute[];
313
+ /**
314
+ * The bounded health summary this capability contributes to its own manifest entry — a small, fixed
315
+ * set of scalars a management client can render beside a rail without a second round trip (#317).
316
+ * Omit it when a capability has nothing to say, which is the normal case.
317
+ *
318
+ * **Declared alongside the routes, and only through `defineCapabilityHealth`.** The type is branded,
319
+ * so an inline object literal does not compile: every declaration in the tree is parsed, which is what
320
+ * keeps the vocabulary closed, the values scalar, and each value's cost stated. See
321
+ * `controlPlane/discovery/healthSummary.ts` for why those three rules are in the type rather than in
322
+ * a comment.
323
+ *
324
+ * Each key is behind a scope this capability's own `adminRoutes` already require — never a new one,
325
+ * because the scopes an adopter is offered at connect are read off those routes, and a value behind
326
+ * anything else could never be granted. `capabilityHealthSources` refuses that at assembly.
327
+ */
328
+ health?: CapabilityHealth;
329
+ /**
330
+ * The configured facts this capability states into its own manifest entry — the decisions an adopter
331
+ * already made that a management client has to respect to call anything (#422). Omit it when nothing
332
+ * this capability is configured with changes how a client calls it, which is the normal case.
333
+ *
334
+ * **A third field, because the two obvious names are taken and neither is this.**
335
+ * {@link Capability.config} is the Zod type this capability validates its own env with — a schema, not
336
+ * a value, and it holds provider credentials. {@link Capability.settings} is `pithy doctor`'s seam,
337
+ * which reads local config *before* anything is deployed. This one is a value, resolved at assembly,
338
+ * on the wire, behind `manifest:read`.
339
+ *
340
+ * **Declared only through `defineManifestConfig`.** The type is branded, so an inline literal does not
341
+ * compile: every fact in the tree is checked against a declaration that travels with it, which is what
342
+ * keeps the values scalar and stops `manifestConfig: resolved` from ever being written.
343
+ *
344
+ * **Build it from the capability's resolved config, never from its defaults** — the same rule
345
+ * {@link Capability.adminRoutes} states, and here it is the only defense there is. Nothing downstream
346
+ * compares a fact against the capability's behavior, because the declaration and the value come from
347
+ * one object.
348
+ */
349
+ manifestConfig?: CapabilityManifestConfig;
350
+ /**
351
+ * How this capability checks that its own **settings work**, as opposed to being merely present — the
352
+ * seam `pithy doctor` runs for every capability every Worker composes (#411). Omit it when a capability
353
+ * has nothing worth checking, which is the normal case and is silent rather than a fault.
354
+ *
355
+ * Declared here, on the instance, and **never keyed off `pithy.manifest.json`**: `@pithy-sh/matchmaking`
356
+ * and `@pithy-sh/rating` are published capability packages that ship no manifest, so a manifest-keyed
357
+ * rule would skip both without saying so — the same trap the version stamper documents.
358
+ *
359
+ * Beside {@link Capability.health} and deliberately not part of it. That one is a bounded scalar summary
360
+ * a **deployed** Worker reports into `GET /control-plane/manifest` for a dashboard; this one reads local
361
+ * config **before** anything is deployed, which is where a wrong `fromAddress` or a `BASE_URL` from the
362
+ * other environment is cheapest to find. See `capability/settings.ts` for the two tiers and why an
363
+ * unreachable account is *skipped* rather than passed.
364
+ */
365
+ settings?: CapabilitySettings;
366
+ /**
367
+ * The npm version of the package that supplies this capability, or `null` where there is none.
368
+ *
369
+ * Every `@pithy-sh/*` capability sets it from its generated `PACKAGE_VERSION` constant
370
+ * (`scripts/stampVersions.ts`) — a Worker cannot read its own `package.json`, so the value has to be
371
+ * written into the source. **Nullable, and not merely optional**, because the adopter's own `app`
372
+ * capability has a name and no npm version at all; that is an ordinary permanent state, not a gap.
373
+ *
374
+ * `GET /control-plane/manifest` reports it **per capability, never aggregated**. The package name is
375
+ * the join key against a release feed, and a project composes some capabilities and not others — so
376
+ * only the intersection of what a project composes and what actually changed is worth reporting, and
377
+ * that intersection is computable only if both sides stay per-module. Aggregate them and a client
378
+ * tells someone they are "five versions behind" counting packages they never installed.
379
+ *
380
+ * Distinct from the Cloudflare version id the manifest reports beside it. That id is opaque and
381
+ * per-deploy: it says *which build*, which is what forensics needs and what `pithy deploy` verifies.
382
+ * This says *which features*, which is what an upgrade decision needs. Neither answers the other's
383
+ * question.
384
+ */
385
+ version?: string | null;
386
+ /**
387
+ * Optional startup hook, called once when {@link createBackend} assembles the backend, with every
388
+ * composed capability. Runs after binding and `dependsOn` validation, before middleware and routes
389
+ * mount. Lets a capability wire across capabilities at startup — `@pithy-sh/secrets` aggregates
390
+ * every {@link Capability.secretRegistry} slice here into one combined registry.
391
+ */
392
+ compose?: (context: CapabilityComposeContext) => void;
393
+ /** Mounts a Hono sub-router. */
394
+ routes?: (app: Hono<PithyHonoEnv>) => void;
395
+ /** Composable middleware (e.g. turnstile(), requireAuth()). */
396
+ middleware?: PithyMiddleware[];
397
+ /**
398
+ * Whether this capability fills the entitlement seam — replaces `c.var.entitlements` with a real
399
+ * resolver. `@pithy-sh/payments` declares it; nothing else does today.
400
+ *
401
+ * It exists so the **CLI** can answer a question no amount of runtime care can: a Worker whose routes
402
+ * call `requireEntitlement()` while composing no provider is not broken, it is silently paywalled
403
+ * shut. The seam already fails closed, so the runtime cannot tell that mistake from a legitimately
404
+ * unentitled user. `pithy doctor` and `pithy dev` compare the gates in a Worker's source against this
405
+ * flag and say so, which turns a fleet of production 403s into one line at startup.
406
+ */
407
+ providesEntitlements?: boolean;
408
+ /**
409
+ * This capability's client-safe projection — the **only** values of its config that may reach a
410
+ * browser bundle. Resolved at build time against a {@link ClientProjectionContext} (the environment),
411
+ * validated through {@link ClientProjection}, and inlined by the Vite plugin as `virtual:pithy/<name>`.
412
+ * A capability with no browser surface declares none, and the front end reads `{ enabled: false }`.
413
+ * Opt-in by construction: a new config field never ships to a browser unless it is projected here.
414
+ */
415
+ client?: (context: ClientProjectionContext) => ClientProjection;
416
+ /**
417
+ * Durable jobs this capability registers (job name → {@link WorkflowSpec}) — the peer of
418
+ * `databases` and `kvNamespaces`. `createBackend` merges every capability's map into one registry
419
+ * keyed `<capability>/<job>`, derives each job's Workflow binding so a missing one fails at boot,
420
+ * and serves the typed dispatcher on `c.var.workflows`. The CLI reads the same specs to write the
421
+ * host worker's `workflows` array and its cron triggers.
422
+ */
423
+ workflows?: Workflows;
424
+ /**
425
+ * Inbound-email handler. The entrypoint (`createEntrypoint`) fans every incoming message to each
426
+ * capability that declares one (e.g. `@pithy-sh/email`'s bounce/complaint handler).
427
+ */
428
+ email?: CapabilityEmailHandler;
429
+ /**
430
+ * Named D1 databases this capability contributes tables to (database name → {@link DatabaseSpec}).
431
+ * `createBackend` merges every capability's slices per database (via `composeDatabases`) and serves
432
+ * one typed `Kysely` per database on `c.var.db.<name>`. Multiple databases (app, analytics, …)
433
+ * coexist; no central schema file.
434
+ */
435
+ databases?: Databases;
436
+ /**
437
+ * Named KV namespaces this capability registers (namespace name → {@link KvNamespaceSpec}). Each
438
+ * namespace is a binding holding named typed stores; `createBackend` merges them and serves each
439
+ * store as a live `TypedKv` on `c.var.kv.<namespace>.<store>`. The peer of `databases`.
440
+ */
441
+ kvNamespaces?: Namespaces;
442
+ /**
443
+ * Seed sets this capability contributes to `pithy seed` (the peer of {@link Capability.databases}).
444
+ * Additive and optional. `composeSeeds` merges every capability's sets library-before-app by
445
+ * `order` and filters them by the target environment; the CLI writes them idempotently and
446
+ * non-destructively. App-shape fixtures are re-encoded and Zod-validated at write time.
447
+ */
448
+ seeds?: readonly SeedSet[];
449
+ /**
450
+ * What an adopter plugged into this capability — see {@link CapabilityExtension}. Additive and
451
+ * optional; the normal case is none. Resolved from this capability's own config at construction
452
+ * time, and read by `pithy doctor`.
453
+ */
454
+ extensions?: readonly CapabilityExtension[];
455
+ /** Bindings this capability needs in the env (normalized — `optional` is always set). */
456
+ requiredBindings: BindingSpec[];
457
+ }
458
+ /** Authoring shape: `requiredBindings` may omit `optional`; `defineCapability` normalizes them. */
459
+ export type CapabilityInput<Databases extends DatabaseSpecMap = Record<never, never>, Namespaces extends KvNamespaceSpecMap = Record<never, never>, Name extends string = string, Workflows extends WorkflowSpecMap = Record<never, never>> = Omit<Capability<Databases, Namespaces, Name, Workflows>, "requiredBindings"> & {
460
+ requiredBindings: BindingSpecInput[];
461
+ };
462
+ /**
463
+ * Author a capability. Parses each binding through `BindingSpec` — normalizing `optional`
464
+ * and validating at define time, so an invalid binding fails here (attributed to this
465
+ * capability) rather than deep in backend assembly. The `const` type params capture the precise
466
+ * `databases`/`kvNamespaces` literals so `createBackend` can infer the merged registries.
467
+ */
468
+ export declare function defineCapability<const Databases extends DatabaseSpecMap = Record<never, never>, const Namespaces extends KvNamespaceSpecMap = Record<never, never>, const Name extends string = string, const Workflows extends WorkflowSpecMap = Record<never, never>>(input: CapabilityInput<Databases, Namespaces, Name, Workflows>): Capability<Databases, Namespaces, Name, Workflows>;
469
+ /** Distribute a union into an intersection — merges each capability's slice into one combined map. */
470
+ type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
471
+ /** This capability's database specs (or `never` when it isn't a `Capability`). */
472
+ type DatabasesOf<C> = C extends Capability<infer D, KvNamespaceSpecMap, string, WorkflowSpecMap> ? D : never;
473
+ /** This capability's KV namespace specs (or `never` when it isn't a `Capability`). */
474
+ type NamespacesOf<C> = C extends Capability<DatabaseSpecMap, infer N, string, WorkflowSpecMap> ? N : never;
475
+ /**
476
+ * This capability's jobs as a dispatch-key map: `<capability>/<job>` → that job's parameter type
477
+ * (the schema's **input** side, since the caller supplies pre-parse values). Re-keying here is what
478
+ * lets `trigger` accept a flat, namespaced key while a capability still declares its jobs by bare
479
+ * name.
480
+ */
481
+ type WorkflowParamsOf<C> = C extends Capability<DatabaseSpecMap, KvNamespaceSpecMap, infer Name, infer W> ? {
482
+ [Job in keyof W & string as `${Name}/${Job}`]: z.input<W[Job]["params"]>;
483
+ } : never;
484
+ /**
485
+ * Merge a union of per-capability slices into one combined map, clamped to `Bound` so it is always
486
+ * usable: an empty capability set merges to `unknown`, which falls back to the empty map. The
487
+ * intersection unions same-named groups (table union per database, store union per namespace).
488
+ */
489
+ type MergeClamped<Slices, Bound> = UnionToIntersection<Slices> extends infer Merged ? (Merged extends Bound ? Merged : Record<never, never>) : never;
490
+ /** The project-wide databases: every capability's `databases` merged into one map. */
491
+ export type MergedDatabases<Caps extends readonly Capability[]> = MergeClamped<DatabasesOf<Caps[number]>, DatabaseSpecMap>;
492
+ /** The project-wide KV namespaces: every capability's `kvNamespaces` merged into one map. */
493
+ export type MergedKvNamespaces<Caps extends readonly Capability[]> = MergeClamped<NamespacesOf<Caps[number]>, KvNamespaceSpecMap>;
494
+ /**
495
+ * The project-wide workflow parameter map: dispatch key → parameter type, across every composed
496
+ * capability. `createBackend` uses it to type `c.var.workflows.trigger`, so an unregistered key or a
497
+ * payload that does not match the declaring capability's schema is a compile error, not a 500.
498
+ */
499
+ export type MergedWorkflowParams<Caps extends readonly Capability[]> = MergeClamped<WorkflowParamsOf<Caps[number]>, Record<string, unknown>>;
500
+ export {};
501
+ //# sourceMappingURL=capability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../../src/capability/capability.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { BindingSpec } from "./bindings.js";
2
+ //#region src/capability/capability.ts
3
+ /**
4
+ * Author a capability. Parses each binding through `BindingSpec` — normalizing `optional`
5
+ * and validating at define time, so an invalid binding fails here (attributed to this
6
+ * capability) rather than deep in backend assembly. The `const` type params capture the precise
7
+ * `databases`/`kvNamespaces` literals so `createBackend` can infer the merged registries.
8
+ */
9
+ function defineCapability(input) {
10
+ return {
11
+ ...input,
12
+ requiredBindings: input.requiredBindings.map((binding) => BindingSpec.parse(binding))
13
+ };
14
+ }
15
+ //#endregion
16
+ export { defineCapability };
@@ -0,0 +1,70 @@
1
+ import { z } from "zod";
2
+ import type { Capability } from "./capability";
3
+ /**
4
+ * A JSON value — the only thing that may cross into a browser bundle. Recursive, so an object or
5
+ * array of JSON values is one too. Declared as a type first because a Zod schema cannot infer its
6
+ * own recursion (CLAUDE.md §Zod: the const and the type share one name).
7
+ */
8
+ export type JsonValue = string | number | boolean | null | JsonValue[] | {
9
+ [key: string]: JsonValue;
10
+ };
11
+ /**
12
+ * The JSON value space, as a schema. `z.lazy` carries the recursion. The record branch is guarded by
13
+ * a plain-object check first: `z.record` alone accepts a `Date` (it has no own enumerable keys) and
14
+ * would quietly project it as `{}`. A non-finite number is rejected for the same reason — `JSON.stringify`
15
+ * turns `NaN` into `null`, which is a silent value change, not a projection.
16
+ *
17
+ * `refusesVanishingKey` is the third check of the same kind, and the one this schema was missing: a
18
+ * `__proto__` key written by a capability is dropped by `z.record` with no issue raised, so it never
19
+ * reaches the bundle and nothing says it was written. See `vanishingKey.ts`.
20
+ *
21
+ * It wraps the **whole value**, outside the union, and both halves of that matter. Whole value, because
22
+ * this is the recursion: every string, array and object in a projection is a `JsonValue`, so guarding it
23
+ * once covers a space nobody can enumerate, at a depth nobody has to predict. Non-objects pass the check
24
+ * by definition, so the cost is a `typeof` per node. Outside the union, because a refusal raised by one
25
+ * branch of a union is reported as the union's own — measured, the message for a key one level down was
26
+ * `Invalid input`, and out here it is the guard's own sentence at the key's own path.
27
+ *
28
+ * Below an array it is `Invalid union` again, with the guard's sentence nested in `issue.errors`. That is
29
+ * how this union reports every rejection it makes — a `Date` at the same depth reads the same way today —
30
+ * so it is the union's shape to fix, not this guard's, and it is written here so the next reader knows it
31
+ * was seen rather than missed.
32
+ */
33
+ export declare const JsonValue: z.ZodType<JsonValue>;
34
+ /**
35
+ * What a capability's client projection is resolved against. A projection is per build, not per
36
+ * request: the plugin inlines the result into the bundle, so the only axis it varies on is the
37
+ * environment being built for (a Turnstile sitekey differs between staging and production).
38
+ */
39
+ export declare const ClientProjectionContext: z.ZodObject<{
40
+ environment: z.ZodString;
41
+ }, z.core.$strip>;
42
+ export type ClientProjectionContext = z.output<typeof ClientProjectionContext>;
43
+ export declare const ClientProjection: z.ZodPipe<z.ZodCustom<{
44
+ [x: string]: unknown;
45
+ enabled: boolean;
46
+ }, {
47
+ [x: string]: unknown;
48
+ enabled: boolean;
49
+ }>, z.ZodType<{
50
+ [x: string]: JsonValue;
51
+ enabled: boolean;
52
+ }, {
53
+ [x: string]: unknown;
54
+ enabled: boolean;
55
+ }, z.core.$ZodTypeInternals<{
56
+ [x: string]: JsonValue;
57
+ enabled: boolean;
58
+ }, {
59
+ [x: string]: unknown;
60
+ enabled: boolean;
61
+ }>>>;
62
+ export type ClientProjection = z.output<typeof ClientProjection>;
63
+ /**
64
+ * Resolve one capability's client projection, validated. An absent capability, or one that declares no
65
+ * projection, is `{ enabled: false }` — never an error, because a front end is written against the
66
+ * capabilities it may have, not the ones it does. A declared projection is parsed through
67
+ * {@link ClientProjection}, so a non-JSON value is a build failure rather than a broken bundle.
68
+ */
69
+ export declare function resolveClientProjection(capability: Capability | undefined, context: ClientProjectionContext): ClientProjection;
70
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/capability/client.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAS/C;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAStG;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAciD,CAAC;AAE7F;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;iBASuD,CAAC;AAC5F,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAkB/E,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;IAYK,CAAC;AACnC,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEjE;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,OAAO,EAAE,uBAAuB,GAC/B,gBAAgB,CAYlB"}