@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,43 @@
1
+ import { z } from "zod";
2
+ //#region src/workflow/schemas.ts
3
+ /**
4
+ * The request and response contract of the host's dispatch route ({@link ./dispatchRoute.ts}).
5
+ *
6
+ * Declared here rather than on the route line for the reason every capability's `http/schemas.ts`
7
+ * exists (CLAUDE.md §HTTP): the route declares *that* it validates, this declares *what*, and the
8
+ * loopback dispatcher on the other end of the wire builds its body against the same object.
9
+ *
10
+ * **The path is here too, and that is deliberate.** An address is as much of the wire contract as a
11
+ * body is, and putting it beside the route would make the dispatcher import the route module to know
12
+ * where to POST — which is the module that imports the dispatcher to resolve a binding. One import
13
+ * cycle, for a template string neither end owns more than the other.
14
+ */
15
+ /** The reserved namespace the host's dispatch route lives under, beside `/__pithy/dev-login`. */
16
+ const WORKFLOW_DISPATCH_BASE = "/__pithy/workflows";
17
+ /** The registered path pattern. `:binding` is the host's own Workflow binding name. */
18
+ const WORKFLOW_DISPATCH_ROUTE = `${WORKFLOW_DISPATCH_BASE}/:binding`;
19
+ /** The concrete path for one binding — what the loopback dispatcher POSTs to. */
20
+ function workflowDispatchPath(binding) {
21
+ return `${WORKFLOW_DISPATCH_BASE}/${encodeURIComponent(binding)}`;
22
+ }
23
+ /** The path segment naming which of the host's own Workflow bindings to start an instance on. */
24
+ const WorkflowDispatchParams = z.object({ binding: z.string().min(1).max(64).regex(/^[A-Za-z_][A-Za-z0-9_]*$/, "A binding name is an identifier: letters, digits and underscores, not starting with a digit.").describe("The Workflow binding on this host's own env — `EMAIL_SENDER`, not a `<capability>/<job>` key. The loopback dispatcher stands in for exactly one binding, and a binding is what it knows itself by.") }).describe("The path parameters of the host dispatch route.");
25
+ /** The body: the instance id and the payload, exactly as `create({ id, params })` takes them. */
26
+ const WorkflowDispatchRequest = z.object({
27
+ id: z.string().min(1).max(128).optional().describe("The instance id to start under. Optional because the platform's own `create` allows omitting it — and relayed rather than minted here, because an id a dispatcher did not choose is an instance the caller's row cannot name (pithy-sh/pithy#342). Every Pithy dispatcher passes one."),
28
+ params: z.unknown().describe("The instance payload. Unconstrained on the wire and validated on arrival against the declaring spec's own schema, so a malformed payload fails with the field named rather than inside a running instance.")
29
+ }).describe("A request to start one instance of a Workflow this host hosts.");
30
+ /**
31
+ * The answer: which binding was started, under which id.
32
+ *
33
+ * A response object rather than an interface, for the reason every admin response is one (CLAUDE.md
34
+ * §HTTP): the caller is across a process boundary, and a TypeScript interface is erased before it can
35
+ * help. Nothing here carries a codec — an answer must parse back to exactly what went in.
36
+ */
37
+ const WorkflowDispatchResponse = z.object({
38
+ binding: z.string().describe("The binding an instance was started on — the one the request named."),
39
+ id: z.string().optional().describe("The instance id, when the request named one."),
40
+ started: z.literal(true).describe("Always true. The route answers 202 once Cloudflare has accepted the instance, never on completion.")
41
+ }).describe("What the host answers when it has accepted a dispatch.");
42
+ //#endregion
43
+ export { WORKFLOW_DISPATCH_BASE, WORKFLOW_DISPATCH_ROUTE, WorkflowDispatchParams, WorkflowDispatchRequest, WorkflowDispatchResponse, workflowDispatchPath };
@@ -0,0 +1,81 @@
1
+ import type { z } from "zod";
2
+ /**
3
+ * The durable-job seam. A capability declares the Cloudflare Workflows it owns as a map of
4
+ * job name → {@link WorkflowSpec}; `createBackend` collects every capability's map into one
5
+ * registry, derives each spec's binding so a missing one fails at boot, and serves a typed
6
+ * dispatcher on `c.var.workflows`.
7
+ *
8
+ * The spec is the single description of a job. The CLI reads it to write the host worker's
9
+ * `workflows` array and its cron triggers; the dispatcher reads it to validate params and find
10
+ * the binding; `naming.ts` reads it to resolve the per-environment script name. One declaration,
11
+ * no drift between the wrangler config, the provisioner, and the call site.
12
+ */
13
+ /**
14
+ * The minimal structural shape of a Cloudflare Workflow binding: enough to start an instance,
15
+ * and nothing more. Typed structurally rather than against `Workflow<P>` from
16
+ * `@cloudflare/workers-types` so core gains no runtime dependency and a test injects a plain
17
+ * object literal — the same posture `@pithy-sh/media` already takes for its AI binding.
18
+ */
19
+ export interface WorkflowBinding {
20
+ /** Start a new instance. `params` is the validated payload the Workflow receives as `event.payload`. */
21
+ create(options?: {
22
+ id?: string;
23
+ params?: unknown;
24
+ }): Promise<unknown>;
25
+ }
26
+ /**
27
+ * One durable job a capability registers. Keyed in {@link WorkflowSpecMap} by its job name, which
28
+ * is also the second segment of the `<capability>/<job>` dispatch key.
29
+ */
30
+ export interface WorkflowSpec<Params extends z.ZodType = z.ZodType> {
31
+ /**
32
+ * The binding name the Workflow is bound to in the Worker env (e.g. `MEDIA_IMAGE_TO_TEXT`).
33
+ * `createBackend` derives a `workflow` {@link BindingSpec} from it, so a job whose binding is
34
+ * absent surfaces as a startup failure rather than a silent no-op at dispatch time.
35
+ */
36
+ binding: string;
37
+ /**
38
+ * The instance parameters, validated **at dispatch** — before the binding is touched. A malformed
39
+ * trigger therefore fails at the call site with `core/invalid_workflow_params`, rather than inside
40
+ * a running instance where the only signal is a failed step and a retry budget burning down.
41
+ */
42
+ params: Params;
43
+ /**
44
+ * A cron expression. Present means the CLI writes a `triggers.crons` entry into the host worker's
45
+ * resolved `wrangler.jsonc` and `createEntrypoint` routes the `scheduled` event here. Absent means
46
+ * dispatch-only. A scheduled job stays manually triggerable either way — a backfill nobody can run
47
+ * on demand is untestable.
48
+ */
49
+ schedule?: string;
50
+ /**
51
+ * The exported `WorkflowEntrypoint` subclass in the host worker that runs this job — the
52
+ * `class_name` the CLI writes into the host's `workflows` array. Omit only for a job whose host
53
+ * config is hand-maintained.
54
+ */
55
+ className?: string;
56
+ /**
57
+ * Treat the derived binding as optional, so a project that has not provisioned the host worker
58
+ * still boots. Defaults to false. `@pithy-sh/media` sets it: its enrichment Workflows appear only
59
+ * once `pithy media provision` has run, and the app must serve every other route until then.
60
+ */
61
+ optional?: boolean;
62
+ }
63
+ /** A capability's durable jobs: job name → {@link WorkflowSpec}. The peer of `databases` and `kvNamespaces`. */
64
+ export type WorkflowSpecMap = Record<string, WorkflowSpec>;
65
+ /**
66
+ * A spec resolved against the capability that declared it — what the registry holds and the
67
+ * dispatcher looks up. `key` is the `<capability>/<job>` dispatch key.
68
+ */
69
+ export interface RegisteredWorkflow {
70
+ /** The dispatch key, `<capability>/<job>`. */
71
+ key: string;
72
+ /** The capability that declared the job — the first key segment and the script-name segment. */
73
+ capability: string;
74
+ /** The job name — the second key segment. */
75
+ job: string;
76
+ /** The spec as declared. */
77
+ spec: WorkflowSpec;
78
+ }
79
+ /** The project-wide registry: dispatch key → {@link RegisteredWorkflow}. */
80
+ export type WorkflowRegistry = Record<string, RegisteredWorkflow>;
81
+ //# sourceMappingURL=spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../src/workflow/spec.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B;;;;;;;;;;GAUG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,wGAAwG;IACxG,MAAM,CAAC,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACvE;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY,CAAC,MAAM,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO;IAChE;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,gHAAgH;AAChH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAE3D;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,gGAAgG;IAChG,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,4BAA4B;IAC5B,IAAI,EAAE,YAAY,CAAC;CACpB;AAED,4EAA4E;AAC5E,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC"}
File without changes
@@ -0,0 +1,122 @@
1
+ /**
2
+ * **The one statement of what a terminal Workflow step writes into its error text, and the one reader of it.**
3
+ *
4
+ * A step's error text is the whole channel. The engine records the throw's message and nothing else —
5
+ * no fields, no cause, no payload — so every operator-facing thing a `PithyError` carries across a
6
+ * durable boundary has to ride inside that one string. `classifiedSteps` used to write
7
+ * `${code}: ${message}`, which meant `action` — the remedy line every other `PithyError` reaching the
8
+ * CLI prints under the problem line — died at the step (pithy-sh/pithy#353).
9
+ *
10
+ * Both ends of that channel live here. {@link encodeWorkflowStepMessage} is called by
11
+ * `classifiedSteps`; {@link decodeWorkflowStepMessage} is called by `@pithy-sh/cloudflare`'s
12
+ * `kitSentence`. **Neither end restates the format.** Two packages that agree about a string by each
13
+ * writing it down is not agreement, it is a coincidence with a maintenance schedule — so the format is
14
+ * the thing being called, not a rule at two call sites, and `stepFailure.test.ts` pins the wire it
15
+ * produces to a hand-written literal so a change to either end has to be a change to both.
16
+ *
17
+ * ## The encoding, and why it is a separator rather than JSON
18
+ *
19
+ * `${code}: ${message}` — unchanged, byte for byte, from what #349 captured — then, when there is one,
20
+ * a separator and the action.
21
+ *
22
+ * A JSON payload was the other candidate, and it is the more obvious answer: unambiguous, extensible,
23
+ * no grammar to get wrong. It loses on the surface nobody controls. **A step's raw text is read by a
24
+ * human, in the Cloudflare dashboard, at three in the morning**, and that reader is the whole reason
25
+ * the message was ever put in the throw. `{"code":"secrets/already_exists","message":"Secret
26
+ * 'api-token' already exists.","action":"Use \`update\` to change an existing secret."}` is strictly
27
+ * worse to read than the two lines it would replace, and it would make every instance already recorded
28
+ * unreadable to the new reader and every instance recorded by the new writer unreadable to the old one.
29
+ * A separator costs a grammar and keeps the sentence.
30
+ *
31
+ * ## Why the separator is a newline
32
+ *
33
+ * A printable delimiter — ` | `, ` :: ` — is ambiguous, and nothing at the reader can resolve it: a
34
+ * message that happens to contain the delimiter splits in the wrong place and the operator reads half
35
+ * a sentence with the other half presented as the remedy. A newline is not ambiguous, because a
36
+ * promoted message may not contain one. That rule is older than this encoding — #349 declined a
37
+ * newline-carrying sentence precisely because it *would forge the CLI's action line* — and it is what
38
+ * makes the split total rather than best-effort. The second line stops being a forgery and becomes the
39
+ * field it always looked like.
40
+ *
41
+ * It also renders. The CLI prints a problem line then an action line, and the dashboard now shows the
42
+ * same two lines the operator's terminal does.
43
+ *
44
+ * **The forgery concern does not disappear; it is bounded, and it was always this size.** A step's text
45
+ * arrives from a Worker whose code we did not write, and the reader promotes it only when it carries a
46
+ * kit throw name and this code grammar. Anyone who can forge that can already forge the problem line.
47
+ * The action line is exactly as trustworthy as the sentence above it — no more, and no less.
48
+ *
49
+ * ## Captured, not assumed
50
+ *
51
+ * The engine embeds the throw's text in its step record raw — it does not JSON-quote it, and it does
52
+ * not escape a newline. Read off a real local Workflows engine (wrangler 4.115.0, 2026-08-14) by
53
+ * driving a Workflow that threw exactly this shape and fetching the instance from the dev session's
54
+ * own Local Explorer instance endpoint:
55
+ *
56
+ * ```text
57
+ * Step threw a NonRetryableError with message "NonRetryableError: secrets/already_exists: Secret
58
+ * 'api-token' already exists.
59
+ * Use `update` to change an existing secret."
60
+ * ```
61
+ *
62
+ * The same run with no action produced #349's captured text byte for byte, which is the compatibility
63
+ * claim stated as a measurement rather than a hope.
64
+ *
65
+ * **`detail` is not here and never will be.** It is the security boundary: client-safe text in
66
+ * `message`, throw-site context in `detail`, and a durable boundary is not a reason to move the line.
67
+ * `action` crosses because `action` is already operator-facing — the CLI prints it and `operatorError`
68
+ * includes it. This stops losing a field that was always meant for this reader.
69
+ */
70
+ /**
71
+ * The separator between the step's sentence and its action. One newline, stated once.
72
+ *
73
+ * Exported so a test can assert the wire rather than ask the code what it produces — and so the plant
74
+ * that proves the gate can fail is a one-character edit here.
75
+ */
76
+ export declare const WORKFLOW_STEP_SEPARATOR = "\n";
77
+ /**
78
+ * The most either half may run to before it stops being treated as one.
79
+ *
80
+ * The text comes from a Worker over an API, and what it says decides how many bytes land in a terminal,
81
+ * a log line, and an audit row. Over the bound a half is not truncated — it is declined, because half a
82
+ * sentence read as the reason is worse than a general one with the reason underneath it.
83
+ */
84
+ export declare const MAX_WORKFLOW_STEP_TEXT = 512;
85
+ /** What a terminal step's text carries across the boundary: the code, the sentence, and the remedy. */
86
+ export interface WorkflowStepMessage {
87
+ /** The `PithyError` code the step raised — `secrets/already_exists`. */
88
+ code: string;
89
+ /** The public sentence. `PithyError.payload.message`, written to be safe for a client. */
90
+ message: string;
91
+ /** The remedy, when the raising error stated one. The CLI's action line. */
92
+ action?: string;
93
+ }
94
+ /**
95
+ * Split a leading `<domain>/<reason>: ` off a text.
96
+ *
97
+ * Exported because the code grammar has exactly one statement and two readers: this encoding, and
98
+ * `@pithy-sh/cloudflare`'s handling of a bare `PithyError` throw, whose text is `payload.message` and
99
+ * carries no encoding at all. A second regex over there is how the two would drift.
100
+ */
101
+ export declare function splitWorkflowStepCode(text: string): {
102
+ code?: string;
103
+ rest: string;
104
+ };
105
+ /**
106
+ * The text a terminal step throws. The inverse of {@link decodeWorkflowStepMessage}, and tested as one.
107
+ *
108
+ * An action is appended only when there is one to append and it is a single line. An action carrying a
109
+ * break would encode a shape the reader declines, taking the sentence down with it — so the sentence
110
+ * is kept and the action dropped. Losing the remedy is a worse day; losing both is a worse one still.
111
+ */
112
+ export declare function encodeWorkflowStepMessage(fields: WorkflowStepMessage): string;
113
+ /**
114
+ * Read a terminal step's text back, or `null` when it is not this encoding.
115
+ *
116
+ * Strict on purpose. No code prefix, an empty sentence, a half over the bound, a stray `\r`, or a
117
+ * second separator means the text is not something {@link encodeWorkflowStepMessage} wrote, and text
118
+ * the kit did not write does not become an operator's sentence — it stays in `detail`, where the raw
119
+ * platform text belongs.
120
+ */
121
+ export declare function decodeWorkflowStepMessage(text: string): WorkflowStepMessage | null;
122
+ //# sourceMappingURL=stepMessage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stepMessage.d.ts","sourceRoot":"","sources":["../../src/workflow/stepMessage.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAc1C,uGAAuG;AACvG,MAAM,WAAW,mBAAmB;IAClC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,0FAA0F;IAC1F,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAInF;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAK7E;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAYlF"}
@@ -0,0 +1,152 @@
1
+ //#region src/workflow/stepMessage.ts
2
+ /**
3
+ * **The one statement of what a terminal Workflow step writes into its error text, and the one reader of it.**
4
+ *
5
+ * A step's error text is the whole channel. The engine records the throw's message and nothing else —
6
+ * no fields, no cause, no payload — so every operator-facing thing a `PithyError` carries across a
7
+ * durable boundary has to ride inside that one string. `classifiedSteps` used to write
8
+ * `${code}: ${message}`, which meant `action` — the remedy line every other `PithyError` reaching the
9
+ * CLI prints under the problem line — died at the step (pithy-sh/pithy#353).
10
+ *
11
+ * Both ends of that channel live here. {@link encodeWorkflowStepMessage} is called by
12
+ * `classifiedSteps`; {@link decodeWorkflowStepMessage} is called by `@pithy-sh/cloudflare`'s
13
+ * `kitSentence`. **Neither end restates the format.** Two packages that agree about a string by each
14
+ * writing it down is not agreement, it is a coincidence with a maintenance schedule — so the format is
15
+ * the thing being called, not a rule at two call sites, and `stepFailure.test.ts` pins the wire it
16
+ * produces to a hand-written literal so a change to either end has to be a change to both.
17
+ *
18
+ * ## The encoding, and why it is a separator rather than JSON
19
+ *
20
+ * `${code}: ${message}` — unchanged, byte for byte, from what #349 captured — then, when there is one,
21
+ * a separator and the action.
22
+ *
23
+ * A JSON payload was the other candidate, and it is the more obvious answer: unambiguous, extensible,
24
+ * no grammar to get wrong. It loses on the surface nobody controls. **A step's raw text is read by a
25
+ * human, in the Cloudflare dashboard, at three in the morning**, and that reader is the whole reason
26
+ * the message was ever put in the throw. `{"code":"secrets/already_exists","message":"Secret
27
+ * 'api-token' already exists.","action":"Use \`update\` to change an existing secret."}` is strictly
28
+ * worse to read than the two lines it would replace, and it would make every instance already recorded
29
+ * unreadable to the new reader and every instance recorded by the new writer unreadable to the old one.
30
+ * A separator costs a grammar and keeps the sentence.
31
+ *
32
+ * ## Why the separator is a newline
33
+ *
34
+ * A printable delimiter — ` | `, ` :: ` — is ambiguous, and nothing at the reader can resolve it: a
35
+ * message that happens to contain the delimiter splits in the wrong place and the operator reads half
36
+ * a sentence with the other half presented as the remedy. A newline is not ambiguous, because a
37
+ * promoted message may not contain one. That rule is older than this encoding — #349 declined a
38
+ * newline-carrying sentence precisely because it *would forge the CLI's action line* — and it is what
39
+ * makes the split total rather than best-effort. The second line stops being a forgery and becomes the
40
+ * field it always looked like.
41
+ *
42
+ * It also renders. The CLI prints a problem line then an action line, and the dashboard now shows the
43
+ * same two lines the operator's terminal does.
44
+ *
45
+ * **The forgery concern does not disappear; it is bounded, and it was always this size.** A step's text
46
+ * arrives from a Worker whose code we did not write, and the reader promotes it only when it carries a
47
+ * kit throw name and this code grammar. Anyone who can forge that can already forge the problem line.
48
+ * The action line is exactly as trustworthy as the sentence above it — no more, and no less.
49
+ *
50
+ * ## Captured, not assumed
51
+ *
52
+ * The engine embeds the throw's text in its step record raw — it does not JSON-quote it, and it does
53
+ * not escape a newline. Read off a real local Workflows engine (wrangler 4.115.0, 2026-08-14) by
54
+ * driving a Workflow that threw exactly this shape and fetching the instance from the dev session's
55
+ * own Local Explorer instance endpoint:
56
+ *
57
+ * ```text
58
+ * Step threw a NonRetryableError with message "NonRetryableError: secrets/already_exists: Secret
59
+ * 'api-token' already exists.
60
+ * Use `update` to change an existing secret."
61
+ * ```
62
+ *
63
+ * The same run with no action produced #349's captured text byte for byte, which is the compatibility
64
+ * claim stated as a measurement rather than a hope.
65
+ *
66
+ * **`detail` is not here and never will be.** It is the security boundary: client-safe text in
67
+ * `message`, throw-site context in `detail`, and a durable boundary is not a reason to move the line.
68
+ * `action` crosses because `action` is already operator-facing — the CLI prints it and `operatorError`
69
+ * includes it. This stops losing a field that was always meant for this reader.
70
+ */
71
+ /**
72
+ * The separator between the step's sentence and its action. One newline, stated once.
73
+ *
74
+ * Exported so a test can assert the wire rather than ask the code what it produces — and so the plant
75
+ * that proves the gate can fail is a one-character edit here.
76
+ */
77
+ const WORKFLOW_STEP_SEPARATOR = "\n";
78
+ /**
79
+ * The most either half may run to before it stops being treated as one.
80
+ *
81
+ * The text comes from a Worker over an API, and what it says decides how many bytes land in a terminal,
82
+ * a log line, and an audit row. Over the bound a half is not truncated — it is declined, because half a
83
+ * sentence read as the reason is worse than a general one with the reason underneath it.
84
+ */
85
+ const MAX_WORKFLOW_STEP_TEXT = 512;
86
+ /**
87
+ * Any line break. The separator is one specific break, so every other one — a bare `\r`, a second
88
+ * newline — is a shape this encoding never produces, and an unrecognized shape is declined.
89
+ */
90
+ const LINE_BREAK = /[\n\r]/;
91
+ /**
92
+ * The `domain/reason` grammar of every kit and adopter error code, mirroring `codeSegment` in
93
+ * ../error/payload. Anchored at the start, so it is the prefix or it is nothing.
94
+ */
95
+ const CODE_PREFIX = /^([a-z][a-z0-9]*(?:_[a-z0-9]+)*\/[a-z][a-z0-9]*(?:_[a-z0-9]+)*): /;
96
+ /**
97
+ * Split a leading `<domain>/<reason>: ` off a text.
98
+ *
99
+ * Exported because the code grammar has exactly one statement and two readers: this encoding, and
100
+ * `@pithy-sh/cloudflare`'s handling of a bare `PithyError` throw, whose text is `payload.message` and
101
+ * carries no encoding at all. A second regex over there is how the two would drift.
102
+ */
103
+ function splitWorkflowStepCode(text) {
104
+ const matched = CODE_PREFIX.exec(text);
105
+ if (matched === null) return { rest: text };
106
+ return {
107
+ code: matched[1],
108
+ rest: text.slice(matched[0].length)
109
+ };
110
+ }
111
+ /**
112
+ * The text a terminal step throws. The inverse of {@link decodeWorkflowStepMessage}, and tested as one.
113
+ *
114
+ * An action is appended only when there is one to append and it is a single line. An action carrying a
115
+ * break would encode a shape the reader declines, taking the sentence down with it — so the sentence
116
+ * is kept and the action dropped. Losing the remedy is a worse day; losing both is a worse one still.
117
+ */
118
+ function encodeWorkflowStepMessage(fields) {
119
+ const stated = `${fields.code}: ${fields.message}`;
120
+ const action = fields.action?.trim();
121
+ if (action === void 0 || action === "" || LINE_BREAK.test(action)) return stated;
122
+ return `${stated}
123
+ ${action}`;
124
+ }
125
+ /**
126
+ * Read a terminal step's text back, or `null` when it is not this encoding.
127
+ *
128
+ * Strict on purpose. No code prefix, an empty sentence, a half over the bound, a stray `\r`, or a
129
+ * second separator means the text is not something {@link encodeWorkflowStepMessage} wrote, and text
130
+ * the kit did not write does not become an operator's sentence — it stays in `detail`, where the raw
131
+ * platform text belongs.
132
+ */
133
+ function decodeWorkflowStepMessage(text) {
134
+ const { code, rest } = splitWorkflowStepCode(text.trim());
135
+ if (code === void 0) return null;
136
+ const cut = rest.indexOf("\n");
137
+ const message = (cut === -1 ? rest : rest.slice(0, cut)).trim();
138
+ const action = cut === -1 ? void 0 : rest.slice(cut + 1).trim();
139
+ if (message === "" || message.length > 512 || LINE_BREAK.test(message)) return null;
140
+ if (action === void 0) return {
141
+ code,
142
+ message
143
+ };
144
+ if (action === "" || action.length > 512 || LINE_BREAK.test(action)) return null;
145
+ return {
146
+ code,
147
+ message,
148
+ action
149
+ };
150
+ }
151
+ //#endregion
152
+ export { MAX_WORKFLOW_STEP_TEXT, WORKFLOW_STEP_SEPARATOR, decodeWorkflowStepMessage, encodeWorkflowStepMessage, splitWorkflowStepCode };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pithy-sh/core",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,19 +8,24 @@
8
8
  "directory": "packages/core"
9
9
  },
10
10
  "files": [
11
+ "dist",
11
12
  "src",
12
13
  "pithy.manifest.json",
13
- "!src/**/*.test.*"
14
+ "!src/**/*.test.*",
15
+ "!dist/**/*.test.*"
14
16
  ],
15
17
  "type": "module",
16
18
  "engines": {
17
19
  "node": ">=22"
18
20
  },
19
21
  "exports": {
20
- "./src/*": "./src/*.ts"
22
+ "./src/*": {
23
+ "types": "./dist/*.d.ts",
24
+ "default": "./dist/*.js"
25
+ }
21
26
  },
22
27
  "scripts": {
23
- "build": "tsc -p tsconfig.json --noEmit false --outDir dist",
28
+ "build": "tsdown && tsc -p tsconfig.build.json",
24
29
  "typecheck": "tsc -p tsconfig.json",
25
30
  "test": "vitest run",
26
31
  "test:node": "vitest run --project=node",
@@ -31,17 +36,23 @@
31
36
  "dependencies": {
32
37
  "@cloudflare/workers-types": "^5.20260729.1",
33
38
  "@hono/zod-validator": "^0.9.0",
34
- "hono": "^4.13.2",
35
- "kysely": "^0.29.0",
36
- "kysely-d1": "^0.4.0",
37
- "zod": "^4.0.0"
39
+ "kysely-d1": "^0.4.0"
38
40
  },
39
41
  "devDependencies": {
40
42
  "@cloudflare/vitest-plugin": "^1.0.0",
41
43
  "@pithy-sh/tsconfig": "workspace:*",
42
44
  "@vitest/coverage-v8": "^4.1.0",
45
+ "hono": "^4.13.2",
46
+ "kysely": "^0.29.0",
47
+ "tsdown": "^0.23.0",
43
48
  "typescript": "^7.0.2",
44
49
  "vitest": "^4.1.0",
45
- "wrangler": "^4.115.0"
50
+ "wrangler": "^4.115.0",
51
+ "zod": "^4.4.0"
52
+ },
53
+ "peerDependencies": {
54
+ "hono": "^4.13.2",
55
+ "kysely": "^0.29.0",
56
+ "zod": "^4.4.0"
46
57
  }
47
58
  }
@@ -458,6 +458,15 @@ export const ConfigOption = z
458
458
  .describe(
459
459
  "The values this option accepts, when they are a closed set. Three things follow from stating them, and none of them can be had without: the prompt is a select rather than free text, `--set` refuses a value outside them instead of writing it into the config, and a refusal can name what is legal — which is the whole of what a caller needs in order to answer a required option. Held to the same printable-string rule as a default, because a choice becomes the value written into the adopter's TypeScript.",
460
460
  ),
461
+ // The key is a choice, so it is held to what a rendered value may be. **The value is not**: it is an
462
+ // error's action line and reaches no generated source, so the printable rule that governs every
463
+ // other string here would be the wrong constraint — it forbids a double quote, and the sentence has
464
+ // to be able to say `billingSubject: "user"`.
465
+ choicesNeedingCode: manifestRecord(z.record(PrintableString, z.string().min(1)))
466
+ .optional()
467
+ .describe(
468
+ "Choices `pithy add` must refuse, each mapped to the sentence telling the adopter what to do instead — a value whose composition needs a seam only they can write. `pithy add` renders JSON into `pithy.config.ts`; it cannot render a function, so a choice whose validity depends on one is a choice it can write and the kit will then refuse to load. `payments`' `billingSubject: \"organization\"` is the one: it requires a `resolveSubject` saying which organization a caller acts for, deliberately has no default because a capability that guessed would key a company's plan to whoever signed in first, and so a config carrying the choice without the seam is refused at assembly — bricking every later command in the project, since they all begin by loading the config (#483). Refusing the choice up front costs the adopter one hand-edit; writing it costs them the project.",
469
+ ),
461
470
  constant: ConfigConstant.optional().describe(
462
471
  "A constant the scaffolded pithy.config.ts defines, rendered *unquoted* in place of `default` when the target config declares it. The one that exists is `publicOrigin` — `PUBLIC_ORIGIN`, this Worker's address for the environment it composes in. An option whose value is an origin must name it rather than state a URL, because a URL written down is production's URL written into staging: it is what mailed staging's testers magic links into production and unsubscribed them there (#256). `default` is still required *for such an option* and is what a config with no such constant gets, so an older project is never handed an identifier it does not define — the one place the absent-default rule does not reach, and it is checked rather than trusted.",
463
472
  ),
@@ -485,6 +494,18 @@ export const ConfigOption = z
485
494
  message: `A config option's default must be one of its choices, and ${JSON.stringify(option.default)} is not — ${option.key} offers ${JSON.stringify(option.choices)}.`,
486
495
  });
487
496
  }
497
+ // A choice that cannot be chosen has to be a choice. Without this, a typo names a value nothing
498
+ // offers, the refusal never fires, and the config it was meant to prevent is written as before.
499
+ for (const choice of Object.keys(option.choicesNeedingCode ?? {})) {
500
+ if (!option.choices?.includes(choice)) {
501
+ ctx.issues.push({
502
+ code: "custom",
503
+ input: choice,
504
+ path: ["choicesNeedingCode", choice],
505
+ message: `A choice needing code must be one this option offers, and ${JSON.stringify(choice)} is not — ${option.key} offers ${JSON.stringify(option.choices ?? [])}.`,
506
+ });
507
+ }
508
+ }
488
509
  if (option.constant !== undefined && option.default === undefined) {
489
510
  ctx.issues.push({
490
511
  code: "custom",
@@ -13,4 +13,4 @@
13
13
  export const PACKAGE_NAME = "@pithy-sh/core";
14
14
 
15
15
  /** This package's version, stamped from its own package.json at generation time. */
16
- export const PACKAGE_VERSION = "0.1.1";
16
+ export const PACKAGE_VERSION = "0.1.3";