@pithy-sh/core 0.1.2 → 0.1.4

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,57 @@
1
+ /**
2
+ * Email addresses: the one rule for deciding whether two strings are the same person.
3
+ *
4
+ * Four capabilities compare addresses. `auth` matches a sign-in address, `email` suppresses one,
5
+ * `support` links a sender by `From`, and `testers` invites one. Four rules is four chances to
6
+ * disagree, and a disagreement here does not present as anything about addresses — it presents as "the
7
+ * suppression list did not work", or as one customer with two support threads, or as an invitation
8
+ * nobody can accept because it was minted against `Ada@` and every session carries `ada@`.
9
+ *
10
+ * So the rule is written down once, here, and it is deliberately small.
11
+ *
12
+ * ## What it normalizes
13
+ *
14
+ * - **Surrounding whitespace.** Trimmed. An address pasted out of a spreadsheet carries it.
15
+ * - **Case, in both halves.** RFC 5321 says the local part is case-sensitive; no mail provider in
16
+ * practice treats it that way, and treating `Ada@` and `ada@` as two people splits one customer's
17
+ * history in half. The failure the other way — two genuinely distinct mailboxes differing only in
18
+ * case — does not exist in the wild.
19
+ *
20
+ * ## What it deliberately does not
21
+ *
22
+ * - **Subaddressing (`ada+shop@`) and dots in the local part.** Gmail collapses both. Most providers do
23
+ * not, and folding them would merge two real people on a self-hosted domain. Showing one customer as
24
+ * two is recoverable; showing two customers as one is not.
25
+ * - **Unicode normalization.** No NFC, no NFKC, no case folding beyond `toLowerCase`. NFKC in
26
+ * particular maps distinct codepoints onto ASCII, which is exactly how one address comes to match
27
+ * another that was never issued to the same person — the confusable-domain attack, performed by us,
28
+ * on our own comparison. An address whose bytes differ stays a different address.
29
+ * - **Validation.** {@link normalizeAddress} takes any string and returns its normal form. Whether a
30
+ * string *is* an address is a question for the boundary that accepted it — Zod, or {@link
31
+ * parseAddress} where the input is a mail header. A normalizer that also rejects is a normalizer
32
+ * whose callers stop calling it.
33
+ * - **IDN / punycode.** A unicode domain is not converted to its `xn--` form, or back. Both spellings
34
+ * are stable under this rule; a project that accepts one must accept only one, at its boundary.
35
+ */
36
+ /** The longest address accepted. RFC 5321 caps a path at 256 octets; anything longer is malformed. */
37
+ export declare const MAX_ADDRESS_LENGTH = 256;
38
+ /**
39
+ * One address, in the one form every comparison in the kit is against.
40
+ *
41
+ * Trimmed and lowercased, and nothing else. Total: every string has a normal form, including the ones
42
+ * that are not addresses. Use {@link parseAddress} where the input is attacker-supplied text that may
43
+ * not contain an address at all.
44
+ */
45
+ export declare function normalizeAddress(value: string): string;
46
+ /**
47
+ * Read one address out of a header-shaped string, or refuse.
48
+ *
49
+ * Unwraps `Ada Lovelace <ada@example.com>`, bounds the length, refuses anything that is not
50
+ * recognizably a single address, and returns it through {@link normalizeAddress}.
51
+ *
52
+ * Returns `undefined` rather than throwing. Inbound mail is attacker-controlled, so a malformed `From`
53
+ * is an expected input, not an exception — the caller decides whether that means "drop the message" or
54
+ * "store it with no sender", and both are reasonable.
55
+ */
56
+ export declare function parseAddress(value: string | null | undefined): string | undefined;
57
+ //# sourceMappingURL=address.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../../src/address/address.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,sGAAsG;AACtG,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAmBjF"}
@@ -0,0 +1,71 @@
1
+ //#region src/address/address.ts
2
+ /**
3
+ * Email addresses: the one rule for deciding whether two strings are the same person.
4
+ *
5
+ * Four capabilities compare addresses. `auth` matches a sign-in address, `email` suppresses one,
6
+ * `support` links a sender by `From`, and `testers` invites one. Four rules is four chances to
7
+ * disagree, and a disagreement here does not present as anything about addresses — it presents as "the
8
+ * suppression list did not work", or as one customer with two support threads, or as an invitation
9
+ * nobody can accept because it was minted against `Ada@` and every session carries `ada@`.
10
+ *
11
+ * So the rule is written down once, here, and it is deliberately small.
12
+ *
13
+ * ## What it normalizes
14
+ *
15
+ * - **Surrounding whitespace.** Trimmed. An address pasted out of a spreadsheet carries it.
16
+ * - **Case, in both halves.** RFC 5321 says the local part is case-sensitive; no mail provider in
17
+ * practice treats it that way, and treating `Ada@` and `ada@` as two people splits one customer's
18
+ * history in half. The failure the other way — two genuinely distinct mailboxes differing only in
19
+ * case — does not exist in the wild.
20
+ *
21
+ * ## What it deliberately does not
22
+ *
23
+ * - **Subaddressing (`ada+shop@`) and dots in the local part.** Gmail collapses both. Most providers do
24
+ * not, and folding them would merge two real people on a self-hosted domain. Showing one customer as
25
+ * two is recoverable; showing two customers as one is not.
26
+ * - **Unicode normalization.** No NFC, no NFKC, no case folding beyond `toLowerCase`. NFKC in
27
+ * particular maps distinct codepoints onto ASCII, which is exactly how one address comes to match
28
+ * another that was never issued to the same person — the confusable-domain attack, performed by us,
29
+ * on our own comparison. An address whose bytes differ stays a different address.
30
+ * - **Validation.** {@link normalizeAddress} takes any string and returns its normal form. Whether a
31
+ * string *is* an address is a question for the boundary that accepted it — Zod, or {@link
32
+ * parseAddress} where the input is a mail header. A normalizer that also rejects is a normalizer
33
+ * whose callers stop calling it.
34
+ * - **IDN / punycode.** A unicode domain is not converted to its `xn--` form, or back. Both spellings
35
+ * are stable under this rule; a project that accepts one must accept only one, at its boundary.
36
+ */
37
+ /** The longest address accepted. RFC 5321 caps a path at 256 octets; anything longer is malformed. */
38
+ const MAX_ADDRESS_LENGTH = 256;
39
+ /**
40
+ * One address, in the one form every comparison in the kit is against.
41
+ *
42
+ * Trimmed and lowercased, and nothing else. Total: every string has a normal form, including the ones
43
+ * that are not addresses. Use {@link parseAddress} where the input is attacker-supplied text that may
44
+ * not contain an address at all.
45
+ */
46
+ function normalizeAddress(value) {
47
+ return value.trim().toLowerCase();
48
+ }
49
+ /**
50
+ * Read one address out of a header-shaped string, or refuse.
51
+ *
52
+ * Unwraps `Ada Lovelace <ada@example.com>`, bounds the length, refuses anything that is not
53
+ * recognizably a single address, and returns it through {@link normalizeAddress}.
54
+ *
55
+ * Returns `undefined` rather than throwing. Inbound mail is attacker-controlled, so a malformed `From`
56
+ * is an expected input, not an exception — the caller decides whether that means "drop the message" or
57
+ * "store it with no sender", and both are reasonable.
58
+ */
59
+ function parseAddress(value) {
60
+ if (typeof value !== "string") return void 0;
61
+ let candidate = value.trim();
62
+ if (candidate.length === 0 || candidate.length > 256) return void 0;
63
+ const angled = /<([^<>]*)>\s*$/.exec(candidate);
64
+ if (angled?.[1] !== void 0) candidate = angled[1].trim();
65
+ const at = candidate.lastIndexOf("@");
66
+ if (at <= 0 || at === candidate.length - 1) return void 0;
67
+ if (!candidate.slice(at + 1).includes(".") || /[\s,;<>"]/.test(candidate)) return void 0;
68
+ return normalizeAddress(candidate);
69
+ }
70
+ //#endregion
71
+ export { MAX_ADDRESS_LENGTH, normalizeAddress, parseAddress };
@@ -0,0 +1,89 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * The action taxonomy is **federated, not centralized**: `action` is an open, namespace-validated
4
+ * `domain/reason` string, and each capability owns and exports its own action constants (`auth/*`,
5
+ * `entitlement/*`, `admin/*`) — added without touching core, the way migrations and table prefixes
6
+ * already federate. Core never holds a closed union of every event.
7
+ */
8
+ export declare const AuditAction: z.ZodString;
9
+ export type AuditAction = z.output<typeof AuditAction>;
10
+ /** The result of an audited action. A blocked authorization attempt is a first-class record. */
11
+ export declare const AuditOutcome: z.ZodEnum<{
12
+ denied: "denied";
13
+ failure: "failure";
14
+ success: "success";
15
+ }>;
16
+ export type AuditOutcome = z.output<typeof AuditOutcome>;
17
+ /** How serious the event is — orthogonal to outcome; drives dashboard filtering and alerting. */
18
+ export declare const AuditSeverity: z.ZodEnum<{
19
+ critical: "critical";
20
+ info: "info";
21
+ warning: "warning";
22
+ }>;
23
+ export type AuditSeverity = z.output<typeof AuditSeverity>;
24
+ /**
25
+ * What kind of principal acted. `anonymous` covers an unauthenticated request; `system` an internal job.
26
+ *
27
+ * `control-plane` is its own kind rather than a flavour of `service` because the question an adopter
28
+ * actually asks is "what did the management client do", separately from "what did my users do". A
29
+ * control-plane caller is not a user of their app at all — it holds no session and owns no user row —
30
+ * so folding it into `user` or `service` would make that question unanswerable from the trail.
31
+ */
32
+ export declare const AuditActorType: z.ZodEnum<{
33
+ anonymous: "anonymous";
34
+ "control-plane": "control-plane";
35
+ service: "service";
36
+ system: "system";
37
+ user: "user";
38
+ }>;
39
+ export type AuditActorType = z.output<typeof AuditActorType>;
40
+ /** Capability-specific structured detail attached to an event; Zod-validated on write and read. */
41
+ export declare const AuditMetadata: z.ZodRecord<z.ZodString, z.ZodUnknown>;
42
+ export type AuditMetadata = z.output<typeof AuditMetadata>;
43
+ /**
44
+ * One audit event as an emitter supplies it. `occurredAt` is optional — the recorder stamps it at
45
+ * write time when absent. The nullable correlation fields (`actorId`, `sessionId`, request fields,
46
+ * resource fields) are populated from request context where available; an emitter sets only what it
47
+ * knows. The recorder turns this into the stored `pithy_audit_events` row.
48
+ *
49
+ * `tenant` is the one field here that names a *dimension* of the trail rather than a detail of the
50
+ * action, and it is on this seam rather than on the recorder's origin for the reason the origin fields
51
+ * are not: the recorder cannot know it. `project`, `environment` and `worker` are constant across every
52
+ * row a multi-tenant Worker writes, so without this the trail cannot be read per customer at all — and
53
+ * it must be stamped here, at write time, because the tenant of an action is a fact *at the time of the
54
+ * action* while membership is a fact *now*. Deriving one from the other later moves a year of history
55
+ * between tenants every time somebody joins or leaves.
56
+ */
57
+ export declare const AuditEvent: z.ZodObject<{
58
+ action: z.ZodString;
59
+ outcome: z.ZodEnum<{
60
+ denied: "denied";
61
+ failure: "failure";
62
+ success: "success";
63
+ }>;
64
+ severity: z.ZodDefault<z.ZodEnum<{
65
+ critical: "critical";
66
+ info: "info";
67
+ warning: "warning";
68
+ }>>;
69
+ actorType: z.ZodEnum<{
70
+ anonymous: "anonymous";
71
+ "control-plane": "control-plane";
72
+ service: "service";
73
+ system: "system";
74
+ user: "user";
75
+ }>;
76
+ actorId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
77
+ sessionId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
78
+ resourceType: z.ZodOptional<z.ZodNullable<z.ZodString>>;
79
+ resourceId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
80
+ ip: z.ZodOptional<z.ZodNullable<z.ZodString>>;
81
+ userAgent: z.ZodOptional<z.ZodNullable<z.ZodString>>;
82
+ requestId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
83
+ tenant: z.ZodOptional<z.ZodNullable<z.ZodString>>;
84
+ occurredAt: z.ZodOptional<z.ZodDate>;
85
+ metadata: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
86
+ }, z.core.$strip>;
87
+ export type AuditEvent = z.output<typeof AuditEvent>;
88
+ export type AuditEventInput = z.input<typeof AuditEvent>;
89
+ //# sourceMappingURL=auditEvent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditEvent.d.ts","sourceRoot":"","sources":["../../src/audit/auditEvent.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAgBxB;;;;;GAKG;AACH,eAAO,MAAM,WAAW,aAM+F,CAAC;AACxH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAEvD,gGAAgG;AAChG,eAAO,MAAM,YAAY;;;;EAItB,CAAC;AACJ,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,YAAY,CAAC,CAAC;AAEzD,iGAAiG;AACjG,eAAO,MAAM,aAAa;;;;EAIvB,CAAC;AACJ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAE3D;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc;;;;;;EAIxB,CAAC;AACJ,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAE7D,mGAAmG;AACnG,eAAO,MAAM,aAAa,wCAIvB,CAAC;AACJ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwCiF,CAAC;AACzG,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AACrD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * The action taxonomy is **federated, not centralized**: `action` is an open, namespace-validated
4
+ * `domain/reason` string, and each capability owns and exports its own action constants (`auth/*`,
5
+ * `entitlement/*`, `admin/*`) — added without touching core, the way migrations and table prefixes
6
+ * already federate. Core never holds a closed union of every event.
7
+ */
8
+ const AuditAction = z.string().regex(/^[a-z][a-z0-9]*\/[a-z][a-z0-9_]*$/, "An audit action must be a namespaced `domain/reason` code: lowercase, the domain and reason separated by a single `/` (e.g. `auth/login`).").describe("A namespaced `domain/reason` action code (`auth/login`, `admin/config_changed`); the federated taxonomy.");
9
+ /** The result of an audited action. A blocked authorization attempt is a first-class record. */
10
+ const AuditOutcome = z.enum([
11
+ "success",
12
+ "failure",
13
+ "denied"
14
+ ]).describe("The result of the audited action: `success`, `failure` (it was attempted and errored), or `denied` (an authorization gate blocked it). `denied` is first-class — blocked attempts are recorded, not only successes.");
15
+ /** How serious the event is — orthogonal to outcome; drives dashboard filtering and alerting. */
16
+ const AuditSeverity = z.enum([
17
+ "info",
18
+ "warning",
19
+ "critical"
20
+ ]).describe("The event's severity, orthogonal to its outcome: `info` (routine), `warning` (notable), `critical` (alert-worthy). Drives dashboard filtering and alerting.");
21
+ /**
22
+ * What kind of principal acted. `anonymous` covers an unauthenticated request; `system` an internal job.
23
+ *
24
+ * `control-plane` is its own kind rather than a flavour of `service` because the question an adopter
25
+ * actually asks is "what did the management client do", separately from "what did my users do". A
26
+ * control-plane caller is not a user of their app at all — it holds no session and owns no user row —
27
+ * so folding it into `user` or `service` would make that question unanswerable from the trail.
28
+ */
29
+ const AuditActorType = z.enum([
30
+ "user",
31
+ "service",
32
+ "system",
33
+ "anonymous",
34
+ "control-plane"
35
+ ]).describe("The kind of principal that acted: `user` (an authenticated person), `service` (a service account or CI token), `system` (an internal job, no external actor), `anonymous` (an unauthenticated request), or `control-plane` (a management client calling in under the `control-plane` strategy — a principal outside the adopter's own user base, whose actions are answerable separately from their users').");
36
+ /** Capability-specific structured detail attached to an event; Zod-validated on write and read. */
37
+ const AuditMetadata = z.record(z.string(), z.unknown()).describe("Capability-specific structured detail (a JSON object), validated on write and read. Never put a secret, credential, or sensitive payload here — the trail is queryable and long-lived.");
38
+ /**
39
+ * One audit event as an emitter supplies it. `occurredAt` is optional — the recorder stamps it at
40
+ * write time when absent. The nullable correlation fields (`actorId`, `sessionId`, request fields,
41
+ * resource fields) are populated from request context where available; an emitter sets only what it
42
+ * knows. The recorder turns this into the stored `pithy_audit_events` row.
43
+ *
44
+ * `tenant` is the one field here that names a *dimension* of the trail rather than a detail of the
45
+ * action, and it is on this seam rather than on the recorder's origin for the reason the origin fields
46
+ * are not: the recorder cannot know it. `project`, `environment` and `worker` are constant across every
47
+ * row a multi-tenant Worker writes, so without this the trail cannot be read per customer at all — and
48
+ * it must be stamped here, at write time, because the tenant of an action is a fact *at the time of the
49
+ * action* while membership is a fact *now*. Deriving one from the other later moves a year of history
50
+ * between tenants every time somebody joins or leaves.
51
+ */
52
+ const AuditEvent = z.object({
53
+ action: AuditAction.describe("What happened, as a namespaced `domain/reason` action code."),
54
+ outcome: AuditOutcome.describe("Whether the action succeeded, failed, or was denied."),
55
+ severity: AuditSeverity.default("info").describe("How serious the event is; defaults to `info`."),
56
+ actorType: AuditActorType.describe("The kind of principal that acted."),
57
+ actorId: z.string().nullish().describe("The acting principal's stable id (user id, service/token name); null for `system`/`anonymous`."),
58
+ sessionId: z.string().nullish().describe("The session this action belongs to, tying a chain of actions together; null when none."),
59
+ resourceType: z.string().nullish().describe("The type of resource the action targeted (e.g. `user`, `secret`); null when not resource-scoped."),
60
+ resourceId: z.string().nullish().describe("The id of the resource the action targeted; null when not resource-scoped."),
61
+ ip: z.string().nullish().describe("The client IP the request came from, for correlation; null when unknown."),
62
+ userAgent: z.string().nullish().describe("The client user-agent string, for correlation; null when unknown."),
63
+ requestId: z.string().nullish().describe("The request correlation id, tying this event to a single request/trace; null when unknown."),
64
+ tenant: z.string().nullish().describe("Whose action it was — the id of the tenant the action was taken *for*, in the emitter's own tenancy model. Opaque here: compared, never interpreted. **The one dimension an emitter supplies.** The recorder stamps `project`, `environment` and `worker` from the Worker's own vars and no emitter can touch them, but no var can know which customer an action belonged to, so this one comes from the call site and is exactly as trustworthy as it — set it where the tenant is already resolved and authorized, never from an unvalidated request field. Optional and nullable: a single-tenant app has no such dimension and must not invent one, and null means *not tenant-scoped* (a CLI-originated action, a fleet-wide operator action) rather than unknown. It is not `actorId`: one person can act in two tenants, so who acted does not answer for whom."),
65
+ occurredAt: z.date().optional().describe("When the action occurred. Optional on emit — the recorder stamps the current time when absent."),
66
+ metadata: AuditMetadata.nullish().describe("Capability-specific structured detail; null when there is none.")
67
+ }).describe("One audit event as an emitter supplies it to `emit()` — the logical event before storage.");
68
+ //#endregion
69
+ export { AuditAction, AuditActorType, AuditEvent, AuditMetadata, AuditOutcome, AuditSeverity };
@@ -0,0 +1,18 @@
1
+ import type { AuditEventInput } from "./auditEvent";
2
+ /**
3
+ * The recorder seam. `emit()` on the request context (`c.var.emit`) takes one {@link AuditEventInput}
4
+ * and durably records it. `@pithy-sh/audit`'s middleware replaces the default with a real D1-backed
5
+ * recorder; with no audit capability installed the default is {@link noopEmit}, so an emitter can
6
+ * always call `emit()` without first checking whether auditing is on.
7
+ *
8
+ * `emit()` is **non-fatal by contract**: it never throws and never rejects, so an audited action is
9
+ * never broken by an audit write. The real recorder swallows and logs its own failures; the no-op
10
+ * simply resolves.
11
+ */
12
+ export type AuditEmit = (event: AuditEventInput) => Promise<void>;
13
+ /**
14
+ * The default recorder when no audit capability is composed: accept the event and drop it. Resolves
15
+ * without throwing, so calling `emit()` is always safe whether or not auditing is installed.
16
+ */
17
+ export declare const noopEmit: AuditEmit;
18
+ //# sourceMappingURL=recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/audit/recorder.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD;;;;;;;;;GASG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,SAA0B,CAAC"}
@@ -0,0 +1,8 @@
1
+ //#region src/audit/recorder.ts
2
+ /**
3
+ * The default recorder when no audit capability is composed: accept the event and drop it. Resolves
4
+ * without throwing, so calling `emit()` is always safe whether or not auditing is installed.
5
+ */
6
+ const noopEmit = async () => {};
7
+ //#endregion
8
+ export { noopEmit };
@@ -0,0 +1,62 @@
1
+ import { z } from "zod";
2
+ export declare const BindingType: z.ZodUnion<readonly [z.ZodLiteral<"d1">, z.ZodLiteral<"kv">, z.ZodLiteral<"r2">, z.ZodLiteral<"ai">, z.ZodLiteral<"vectorize">, z.ZodLiteral<"queue">, z.ZodLiteral<"ratelimit">, z.ZodLiteral<"email">, z.ZodLiteral<"secret">, z.ZodLiteral<"workflow">, z.ZodLiteral<"service">, z.ZodLiteral<"durable_object">]>;
3
+ export type BindingType = z.infer<typeof BindingType>;
4
+ /**
5
+ * Whether a provision command creates the **resource** behind this kind of binding, rather than the
6
+ * adopter standing it up themselves.
7
+ *
8
+ * The three are the ones whose resource exists only after `pithy <capability> provision`: a `secret` is a
9
+ * Secrets Store entry (a `.dev.vars` string in local dev), a `workflow` runs in a deployed host Worker,
10
+ * and a `vectorize` binding addresses a provisioned index. `pithy add` says so in a note, at the moment
11
+ * the adopter is thinking about the capability.
12
+ *
13
+ * **This is not the same question as "did anything write the stanza".** Collapsing the two is what left
14
+ * `workflow:EMAIL_SENDER` unwritten and every route answering 500 (#258): the entry is derivable offline
15
+ * even though the Workflow it names is not deployed yet, so {@link isWrittenBinding} writes it and this
16
+ * one still reports that provisioning is what makes it work. A binding can be in both sets, and the
17
+ * Workflow is.
18
+ *
19
+ * `service` is not here. Its entry is also written for the adopter — by `pithy feature`, out of the
20
+ * target Worker's env-scoped script name — but it is wiring between an app's own Workers rather than a
21
+ * capability's provisioned resource, and no shipped capability declares one.
22
+ */
23
+ export declare function isProvisionedBinding(type: BindingType): boolean;
24
+ /**
25
+ * Whether `pithy add` writes this kind's `wrangler.jsonc` entry, offline, at the moment it composes the
26
+ * capability.
27
+ *
28
+ * Together with {@link isProvisionedBinding} this is the whole answer to "where does this binding come
29
+ * from" — the invariant `capabilities/requiredBindings.test.ts` states. A kind in **neither** set is a
30
+ * binding a capability requires and nothing supplies: the composition refuses to assemble, the error
31
+ * names the binding, and no command anywhere fixes it. `ratelimit` was exactly that, which is why a
32
+ * scaffolded project composing `auth` answered 500 on every route including `/health` (#258).
33
+ *
34
+ * Membership turns on one question only: **is every field wrangler requires derivable offline?** A rate
35
+ * limiter's are — the stanza is a policy with no resource behind it. A Workflow's are, because the
36
+ * manifest binding states the job and the exported class, and the rest is the project-scoped naming rule.
37
+ * A Vectorize index's `index_name` is a provisioning output and is not, so an entry carrying only
38
+ * `binding` would fail wrangler's validator and stop `wrangler dev` and `wrangler deploy` both — worse
39
+ * than no entry. A `secret` has no `wrangler.jsonc` array at all.
40
+ *
41
+ * `service` is in neither, deliberately: `pithy feature` writes it out of the target Worker's env-scoped
42
+ * script name, and no shipped capability declares one.
43
+ */
44
+ export declare function isWrittenBinding(type: BindingType): boolean;
45
+ /**
46
+ * Declares a Cloudflare binding a capability requires in the Worker env. The authoring
47
+ * shape lets `optional` be omitted (defaults false); `createBackend` normalizes via parse.
48
+ */
49
+ export declare const BindingSpec: z.ZodObject<{
50
+ type: z.ZodUnion<readonly [z.ZodLiteral<"d1">, z.ZodLiteral<"kv">, z.ZodLiteral<"r2">, z.ZodLiteral<"ai">, z.ZodLiteral<"vectorize">, z.ZodLiteral<"queue">, z.ZodLiteral<"ratelimit">, z.ZodLiteral<"email">, z.ZodLiteral<"secret">, z.ZodLiteral<"workflow">, z.ZodLiteral<"service">, z.ZodLiteral<"durable_object">]>;
51
+ name: z.ZodString;
52
+ optional: z.ZodDefault<z.ZodBoolean>;
53
+ className: z.ZodOptional<z.ZodString>;
54
+ classModule: z.ZodOptional<z.ZodString>;
55
+ job: z.ZodOptional<z.ZodString>;
56
+ service: z.ZodOptional<z.ZodString>;
57
+ remote: z.ZodOptional<z.ZodBoolean>;
58
+ }, z.core.$strip>;
59
+ export type BindingSpec = z.infer<typeof BindingSpec>;
60
+ /** Authoring shape for a capability's `requiredBindings`: `optional` may be omitted. */
61
+ export type BindingSpecInput = z.input<typeof BindingSpec>;
62
+ //# sourceMappingURL=bindings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bindings.d.ts","sourceRoot":"","sources":["../../src/capability/bindings.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,WAAW,sTAmBuC,CAAC;AAChE,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAE/D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAU3D;AAqBD;;;GAGG;AACH,eAAO,MAAM,WAAW;;;;;;;;;iBAqFpB,CAAC;AACL,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD,wFAAwF;AACxF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC"}
@@ -0,0 +1,97 @@
1
+ import { NAME_SEGMENT } from "../naming/segment.js";
2
+ import { z } from "zod";
3
+ //#region src/capability/bindings.ts
4
+ const BindingType = z.union([
5
+ z.literal("d1").describe("D1 SQL database (SQLite at the edge)."),
6
+ z.literal("kv").describe("Workers KV — eventually-consistent key/value store."),
7
+ z.literal("r2").describe("R2 bucket — S3-compatible object storage."),
8
+ z.literal("ai").describe("Workers AI — run models on Cloudflare's GPU network."),
9
+ z.literal("vectorize").describe("Vectorize — vector DB for embeddings and similarity search."),
10
+ z.literal("queue").describe("Cloudflare Queue — async message producer/consumer."),
11
+ z.literal("ratelimit").describe("Workers Rate Limiting — per-key request limiting."),
12
+ z.literal("email").describe("Email Sending binding (Cloudflare Email Service)."),
13
+ z.literal("secret").describe("Secret from the Secrets Store, encrypted at rest."),
14
+ z.literal("workflow").describe("Cloudflare Workflow — durable, multi-step execution."),
15
+ z.literal("service").describe("Service binding — direct RPC to another Worker."),
16
+ z.literal("durable_object").describe("Durable Object — a single-threaded, stateful actor with its own storage. Backed by an exported DO class; the CLI wires the namespace binding and the class migration tag.")
17
+ ]).describe("Kind of Cloudflare resource a binding refers to.");
18
+ /**
19
+ * Whether a provision command creates the **resource** behind this kind of binding, rather than the
20
+ * adopter standing it up themselves.
21
+ *
22
+ * The three are the ones whose resource exists only after `pithy <capability> provision`: a `secret` is a
23
+ * Secrets Store entry (a `.dev.vars` string in local dev), a `workflow` runs in a deployed host Worker,
24
+ * and a `vectorize` binding addresses a provisioned index. `pithy add` says so in a note, at the moment
25
+ * the adopter is thinking about the capability.
26
+ *
27
+ * **This is not the same question as "did anything write the stanza".** Collapsing the two is what left
28
+ * `workflow:EMAIL_SENDER` unwritten and every route answering 500 (#258): the entry is derivable offline
29
+ * even though the Workflow it names is not deployed yet, so {@link isWrittenBinding} writes it and this
30
+ * one still reports that provisioning is what makes it work. A binding can be in both sets, and the
31
+ * Workflow is.
32
+ *
33
+ * `service` is not here. Its entry is also written for the adopter — by `pithy feature`, out of the
34
+ * target Worker's env-scoped script name — but it is wiring between an app's own Workers rather than a
35
+ * capability's provisioned resource, and no shipped capability declares one.
36
+ */
37
+ function isProvisionedBinding(type) {
38
+ return type === "secret" || type === "workflow" || type === "vectorize";
39
+ }
40
+ /**
41
+ * Whether `pithy add` writes this kind's `wrangler.jsonc` entry, offline, at the moment it composes the
42
+ * capability.
43
+ *
44
+ * Together with {@link isProvisionedBinding} this is the whole answer to "where does this binding come
45
+ * from" — the invariant `capabilities/requiredBindings.test.ts` states. A kind in **neither** set is a
46
+ * binding a capability requires and nothing supplies: the composition refuses to assemble, the error
47
+ * names the binding, and no command anywhere fixes it. `ratelimit` was exactly that, which is why a
48
+ * scaffolded project composing `auth` answered 500 on every route including `/health` (#258).
49
+ *
50
+ * Membership turns on one question only: **is every field wrangler requires derivable offline?** A rate
51
+ * limiter's are — the stanza is a policy with no resource behind it. A Workflow's are, because the
52
+ * manifest binding states the job and the exported class, and the rest is the project-scoped naming rule.
53
+ * A Vectorize index's `index_name` is a provisioning output and is not, so an entry carrying only
54
+ * `binding` would fail wrangler's validator and stop `wrangler dev` and `wrangler deploy` both — worse
55
+ * than no entry. A `secret` has no `wrangler.jsonc` array at all.
56
+ *
57
+ * `service` is in neither, deliberately: `pithy feature` writes it out of the target Worker's env-scoped
58
+ * script name, and no shipped capability declares one.
59
+ */
60
+ function isWrittenBinding(type) {
61
+ return type === "d1" || type === "kv" || type === "r2" || type === "ai" || type === "durable_object" || type === "ratelimit" || type === "workflow";
62
+ }
63
+ /**
64
+ * Declares a Cloudflare binding a capability requires in the Worker env. The authoring
65
+ * shape lets `optional` be omitted (defaults false); `createBackend` normalizes via parse.
66
+ */
67
+ const BindingSpec = z.object({
68
+ type: BindingType.describe("Resource kind this binding provides."),
69
+ name: z.string().min(1).describe("Binding name expected in the Worker env (e.g. \"DB\", \"SESSIONS\")."),
70
+ optional: z.boolean().default(false).describe("If true, createBackend won't fail when this binding is absent."),
71
+ className: z.string().min(1).regex(/^[A-Za-z_$][A-Za-z0-9_$]*$/, "A className is a JavaScript identifier: letters, digits, `_` and `$`, not leading a digit.").optional().describe("The exported class this binding is backed by. For a `durable_object` binding it is the DO class (e.g. \"MultiplayerSession\") the CLI writes into `durable_objects.bindings`, the DO class migration tag, and the `export { … }` line in the Worker entry. For a `workflow` binding it is the `WorkflowEntrypoint` subclass (e.g. \"EmailSendWorkflow\") the CLI writes as `class_name` — the same value the capability's own `WorkflowSpec.className` carries. Ignored for every other kind."),
72
+ classModule: z.string().min(1).regex(/^(@[a-z0-9~-][a-z0-9._~-]*\/)?[a-z0-9~-][a-z0-9._~-]*(\/[A-Za-z0-9_~-][A-Za-z0-9._~-]*)*$/, "A classModule is a bare module specifier: a package, optionally with a path into it.").optional().describe("The module the class is exported from (e.g. \"@pithy-sh/multiplayer/src/session/durableObject\") — what the CLI writes the Worker entry's `export { <className> } from \"<classModule>\";` against. Required for a `durable_object` binding, because wrangler resolves `class_name` against the entry `main` names and refuses the deploy when nothing there exports it. Its own module, never the package entry point, which `pithy.config.ts` loads in Node. Ignored for every other kind."),
73
+ job: z.string().min(1).regex(NAME_SEGMENT, "A job is one name segment: lowercase letters, digits, and single hyphens.").optional().describe("The job within the capability this Workflow runs (e.g. \"send\") — the `<job>` segment of the deployed `<project>-<env>-<capability>-<job>` name, and the second half of the `<capability>/<job>` dispatch key. Meaningful only for a `workflow` binding, where it is what lets `pithy add` name the Workflow offline instead of leaving the binding unwritten. Ignored for every other kind."),
74
+ service: z.string().min(1).optional().describe("The Worker this binding calls, named as it appears in `apps/<name>/` (e.g. \"api\"). Meaningful only for a `service` binding — the CLI resolves it to that Worker's environment-scoped script name when writing `services` into wrangler.jsonc, so worker-to-worker RPC targets the right deployment per environment. Ignored for every other kind."),
75
+ remote: z.boolean().optional().describe("Reach the real Cloudflare resource during local development instead of a local emulation. Set it for a binding that has none — Vectorize and Workers AI both lack local simulation — so `wrangler dev` and any Workflow host, which always runs locally, still work. Left unset rather than defaulting to false, so a spec that does not care emits no flag at all. Ignored in a deployed Worker.")
76
+ }).describe("Declares a Cloudflare binding a capability requires in the Worker env.").check((ctx) => {
77
+ if (ctx.value.type === "durable_object" && ctx.value.className === void 0) ctx.issues.push({
78
+ code: "custom",
79
+ input: ctx.value,
80
+ path: ["className"],
81
+ message: `Durable Object binding "${ctx.value.name}" needs a className — the exported DO class it is backed by.`
82
+ });
83
+ if (ctx.value.type === "durable_object" && ctx.value.classModule === void 0) ctx.issues.push({
84
+ code: "custom",
85
+ input: ctx.value,
86
+ path: ["classModule"],
87
+ message: `Durable Object binding "${ctx.value.name}" needs a classModule — the module its class is exported from.`
88
+ });
89
+ if (ctx.value.type === "service" && ctx.value.service === void 0) ctx.issues.push({
90
+ code: "custom",
91
+ input: ctx.value,
92
+ path: ["service"],
93
+ message: `Service binding "${ctx.value.name}" needs a service — the Worker it calls, as named in apps/.`
94
+ });
95
+ });
96
+ //#endregion
97
+ export { BindingSpec, BindingType, isProvisionedBinding, isWrittenBinding };