@pithy-sh/core 0.9.0 → 0.11.0

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 (298) hide show
  1. package/dist/access/access.d.ts +172 -0
  2. package/dist/access/access.d.ts.map +1 -0
  3. package/dist/access/access.js +147 -0
  4. package/dist/access/acting.d.ts +49 -0
  5. package/dist/access/acting.d.ts.map +1 -0
  6. package/dist/access/acting.js +21 -0
  7. package/dist/access/policyCheck.d.ts +33 -0
  8. package/dist/access/policyCheck.d.ts.map +1 -0
  9. package/dist/access/policyCheck.js +48 -0
  10. package/dist/access/usage.d.ts +83 -0
  11. package/dist/access/usage.d.ts.map +1 -0
  12. package/dist/access/usage.js +104 -0
  13. package/dist/access/visibility.d.ts +66 -0
  14. package/dist/access/visibility.d.ts.map +1 -0
  15. package/dist/access/visibility.js +86 -0
  16. package/dist/asyncapi/document.d.ts +46 -0
  17. package/dist/asyncapi/document.d.ts.map +1 -0
  18. package/dist/asyncapi/document.js +115 -0
  19. package/dist/audit/auditEvent.d.ts +5 -0
  20. package/dist/audit/auditEvent.d.ts.map +1 -1
  21. package/dist/audit/auditEvent.js +2 -0
  22. package/dist/capability/bindings.d.ts +47 -2
  23. package/dist/capability/bindings.d.ts.map +1 -1
  24. package/dist/capability/bindings.js +117 -7
  25. package/dist/capability/capability.d.ts +105 -28
  26. package/dist/capability/capability.d.ts.map +1 -1
  27. package/dist/capability/composition.d.ts.map +1 -1
  28. package/dist/capability/composition.js +5 -1
  29. package/dist/capability/manifest.d.ts +2 -1
  30. package/dist/capability/manifest.d.ts.map +1 -1
  31. package/dist/capability/manifest.js +1 -1
  32. package/dist/capability/settings.d.ts +96 -4
  33. package/dist/capability/settings.d.ts.map +1 -1
  34. package/dist/capability/settings.js +85 -4
  35. package/dist/cli/command.d.ts +364 -0
  36. package/dist/cli/command.d.ts.map +1 -0
  37. package/dist/cli/command.js +418 -0
  38. package/dist/cli/commandCatalog.generated.d.ts +2437 -0
  39. package/dist/cli/commandCatalog.generated.d.ts.map +1 -0
  40. package/dist/cli/commandCatalog.generated.js +2564 -0
  41. package/dist/cli/commandFacts.d.ts +164 -0
  42. package/dist/cli/commandFacts.d.ts.map +1 -0
  43. package/dist/cli/commandFacts.js +216 -0
  44. package/dist/controlPlane/capability.d.ts.map +1 -1
  45. package/dist/controlPlane/capability.js +12 -2
  46. package/dist/controlPlane/context.d.ts +5 -0
  47. package/dist/controlPlane/context.d.ts.map +1 -1
  48. package/dist/controlPlane/context.js +3 -1
  49. package/dist/controlPlane/data/connection.d.ts +47 -0
  50. package/dist/controlPlane/data/connection.d.ts.map +1 -1
  51. package/dist/controlPlane/data/connection.js +55 -1
  52. package/dist/controlPlane/error/errors.d.ts.map +1 -1
  53. package/dist/controlPlane/error/errors.js +4 -3
  54. package/dist/controlPlane/http/cors.d.ts +4 -4
  55. package/dist/controlPlane/http/cors.js +4 -4
  56. package/dist/controlPlane/http/guard.d.ts +11 -0
  57. package/dist/controlPlane/http/guard.d.ts.map +1 -1
  58. package/dist/controlPlane/http/guard.js +28 -2
  59. package/dist/controlPlane/http/handlers.d.ts +60 -0
  60. package/dist/controlPlane/http/handlers.d.ts.map +1 -1
  61. package/dist/controlPlane/http/handlers.js +31 -2
  62. package/dist/controlPlane/http/readiness.d.ts +33 -0
  63. package/dist/controlPlane/http/readiness.d.ts.map +1 -0
  64. package/dist/controlPlane/http/readiness.js +39 -0
  65. package/dist/controlPlane/http/responses.d.ts +147 -0
  66. package/dist/controlPlane/http/responses.d.ts.map +1 -1
  67. package/dist/controlPlane/http/responses.js +61 -4
  68. package/dist/controlPlane/http/routes.d.ts +2 -1
  69. package/dist/controlPlane/http/routes.d.ts.map +1 -1
  70. package/dist/controlPlane/http/routes.js +50 -9
  71. package/dist/controlPlane/http/verify.d.ts.map +1 -1
  72. package/dist/controlPlane/http/verify.js +2 -1
  73. package/dist/controlPlane/migrationState/migrationState.d.ts +102 -0
  74. package/dist/controlPlane/migrationState/migrationState.d.ts.map +1 -0
  75. package/dist/controlPlane/migrationState/migrationState.js +142 -0
  76. package/dist/controlPlane/migrations/0003_connection_principal.d.ts +21 -0
  77. package/dist/controlPlane/migrations/0003_connection_principal.d.ts.map +1 -0
  78. package/dist/controlPlane/migrations/0003_connection_principal.js +33 -0
  79. package/dist/controlPlane/scope/scope.d.ts +13 -2
  80. package/dist/controlPlane/scope/scope.d.ts.map +1 -1
  81. package/dist/controlPlane/scope/scope.js +14 -3
  82. package/dist/createBackend.d.ts +7 -0
  83. package/dist/createBackend.d.ts.map +1 -1
  84. package/dist/createBackend.js +41 -6
  85. package/dist/createEntrypoint.d.ts.map +1 -1
  86. package/dist/createEntrypoint.js +5 -3
  87. package/dist/entitlement/allowance.d.ts +25 -0
  88. package/dist/entitlement/allowance.d.ts.map +1 -0
  89. package/dist/entitlement/allowance.js +80 -0
  90. package/dist/entitlement/entitlement.d.ts +41 -0
  91. package/dist/entitlement/entitlement.d.ts.map +1 -1
  92. package/dist/entitlement/meter.d.ts +57 -0
  93. package/dist/entitlement/meter.d.ts.map +1 -0
  94. package/dist/entitlement/meter.js +13 -0
  95. package/dist/entitlement/require.js +1 -1
  96. package/dist/error/cause.d.ts +16 -116
  97. package/dist/error/cause.d.ts.map +1 -1
  98. package/dist/error/cause.js +19 -153
  99. package/dist/error/http.d.ts +184 -0
  100. package/dist/error/http.d.ts.map +1 -1
  101. package/dist/error/payload.d.ts +368 -0
  102. package/dist/error/payload.d.ts.map +1 -1
  103. package/dist/error/payload.js +126 -4
  104. package/dist/error/pithyError.d.ts +44 -0
  105. package/dist/error/pithyError.d.ts.map +1 -1
  106. package/dist/error/pithyError.js +56 -1
  107. package/dist/error/unresolved.d.ts +265 -0
  108. package/dist/error/unresolved.d.ts.map +1 -0
  109. package/dist/error/unresolved.js +599 -0
  110. package/dist/error/wire.d.ts +20 -0
  111. package/dist/error/wire.d.ts.map +1 -0
  112. package/dist/error/wire.js +19 -0
  113. package/dist/http/authContext.d.ts +7 -0
  114. package/dist/http/authContext.d.ts.map +1 -1
  115. package/dist/http/authContext.js +8 -1
  116. package/dist/http/oidcWebhook.d.ts +3 -3
  117. package/dist/http/oidcWebhook.js +3 -3
  118. package/dist/http/routeContract.js +1 -1
  119. package/dist/http/routeSpec.d.ts +66 -0
  120. package/dist/http/routeSpec.d.ts.map +1 -0
  121. package/dist/http/routeSpec.js +40 -0
  122. package/dist/http/sameOrigin.d.ts +1 -1
  123. package/dist/http/sameOrigin.js +1 -1
  124. package/dist/http/scopeGates.d.ts +20 -0
  125. package/dist/http/scopeGates.d.ts.map +1 -0
  126. package/dist/http/scopeGates.js +36 -0
  127. package/dist/http/signedWebhook.d.ts +3 -3
  128. package/dist/http/signedWebhook.js +3 -3
  129. package/dist/http/socket.d.ts +52 -0
  130. package/dist/http/socket.d.ts.map +1 -0
  131. package/dist/http/socket.js +2 -0
  132. package/dist/http/subprotocol.d.ts +29 -0
  133. package/dist/http/subprotocol.d.ts.map +1 -0
  134. package/dist/http/subprotocol.js +37 -0
  135. package/dist/http/validation.d.ts +40 -8
  136. package/dist/http/validation.d.ts.map +1 -1
  137. package/dist/http/validation.js +25 -1
  138. package/dist/index.d.ts +1 -1
  139. package/dist/index.d.ts.map +1 -1
  140. package/dist/index.js +4 -4
  141. package/dist/logger/record.d.ts +107 -0
  142. package/dist/logger/record.d.ts.map +1 -1
  143. package/dist/migrations/bookkeeping.d.ts +21 -0
  144. package/dist/migrations/bookkeeping.d.ts.map +1 -1
  145. package/dist/migrations/bookkeeping.js +32 -3
  146. package/dist/migrations/capabilitySets.d.ts +23 -0
  147. package/dist/migrations/capabilitySets.d.ts.map +1 -0
  148. package/dist/migrations/capabilitySets.js +74 -0
  149. package/dist/migrations/groups.d.ts +140 -0
  150. package/dist/migrations/groups.d.ts.map +1 -0
  151. package/dist/migrations/groups.js +191 -0
  152. package/dist/migrations/migrateStep.d.ts +13 -0
  153. package/dist/migrations/migrateStep.d.ts.map +1 -0
  154. package/dist/migrations/migrateStep.js +20 -0
  155. package/dist/migrations/owner.d.ts +7 -0
  156. package/dist/migrations/owner.d.ts.map +1 -1
  157. package/dist/migrations/owner.js +11 -7
  158. package/dist/migrations/registry.d.ts +26 -0
  159. package/dist/migrations/registry.d.ts.map +1 -1
  160. package/dist/migrations/registry.js +38 -7
  161. package/dist/migrations/retained.js +2 -2
  162. package/dist/migrations/runner.d.ts +76 -5
  163. package/dist/migrations/runner.d.ts.map +1 -1
  164. package/dist/migrations/runner.js +130 -19
  165. package/dist/migrations/state.d.ts +60 -0
  166. package/dist/migrations/state.d.ts.map +1 -0
  167. package/dist/migrations/state.js +46 -0
  168. package/dist/naming/domains.d.ts +17 -0
  169. package/dist/naming/domains.d.ts.map +1 -1
  170. package/dist/naming/domains.js +62 -4
  171. package/dist/naming/environment.d.ts.map +1 -1
  172. package/dist/naming/environment.js +2 -1
  173. package/dist/naming/feature.d.ts +27 -5
  174. package/dist/naming/feature.d.ts.map +1 -1
  175. package/dist/naming/feature.js +36 -6
  176. package/dist/naming/limits.d.ts +47 -3
  177. package/dist/naming/limits.d.ts.map +1 -1
  178. package/dist/naming/limits.js +47 -3
  179. package/dist/naming/packageName.d.ts +17 -0
  180. package/dist/naming/packageName.d.ts.map +1 -0
  181. package/dist/naming/packageName.js +22 -0
  182. package/dist/naming/provisionScope.d.ts +6 -0
  183. package/dist/naming/provisionScope.d.ts.map +1 -1
  184. package/dist/naming/provisionScope.js +10 -4
  185. package/dist/naming/resourceNames.d.ts +21 -2
  186. package/dist/naming/resourceNames.d.ts.map +1 -1
  187. package/dist/naming/resourceNames.js +21 -3
  188. package/dist/openapi/document.d.ts +106 -0
  189. package/dist/openapi/document.d.ts.map +1 -0
  190. package/dist/openapi/document.js +314 -0
  191. package/dist/openapi/routeGroups.d.ts +8 -0
  192. package/dist/openapi/routeGroups.d.ts.map +1 -0
  193. package/dist/openapi/routeGroups.js +23 -0
  194. package/dist/seed/writeD1.d.ts +7 -1
  195. package/dist/seed/writeD1.d.ts.map +1 -1
  196. package/dist/seed/writeD1.js +9 -3
  197. package/dist/seed/writeKv.d.ts +2 -0
  198. package/dist/seed/writeKv.d.ts.map +1 -1
  199. package/dist/seed/writeKv.js +6 -2
  200. package/dist/text/comments.js +66 -4
  201. package/dist/text/literals.d.ts +43 -0
  202. package/dist/text/literals.d.ts.map +1 -0
  203. package/dist/text/literals.js +293 -0
  204. package/dist/version.generated.d.ts +1 -1
  205. package/dist/version.generated.d.ts.map +1 -1
  206. package/dist/version.generated.js +1 -1
  207. package/dist/worker/serviceLoopback.d.ts +36 -0
  208. package/dist/worker/serviceLoopback.d.ts.map +1 -0
  209. package/dist/worker/serviceLoopback.js +74 -0
  210. package/dist/workflow/dispatchRoute.d.ts.map +1 -1
  211. package/dist/workflow/dispatchRoute.js +12 -6
  212. package/dist/workflow/faults.d.ts +12 -1
  213. package/dist/workflow/faults.d.ts.map +1 -1
  214. package/dist/workflow/faults.js +24 -18
  215. package/dist/workflow/hostEnv.d.ts +1 -0
  216. package/dist/workflow/hostEnv.d.ts.map +1 -1
  217. package/dist/workflow/hostEnv.js +4 -2
  218. package/dist/workflow/loopback.d.ts.map +1 -1
  219. package/dist/workflow/loopback.js +2 -1
  220. package/package.json +4 -4
  221. package/src/access/access.ts +298 -0
  222. package/src/access/acting.ts +59 -0
  223. package/src/access/policyCheck.ts +77 -0
  224. package/src/access/usage.ts +141 -0
  225. package/src/access/visibility.ts +109 -0
  226. package/src/asyncapi/document.ts +164 -0
  227. package/src/audit/auditEvent.ts +4 -0
  228. package/src/capability/bindings.ts +159 -13
  229. package/src/capability/capability.ts +106 -29
  230. package/src/capability/composition.ts +2 -1
  231. package/src/capability/settings.ts +165 -4
  232. package/src/cli/command.ts +865 -0
  233. package/src/cli/commandCatalog.generated.ts +2723 -0
  234. package/src/cli/commandFacts.ts +220 -0
  235. package/src/controlPlane/capability.ts +25 -1
  236. package/src/controlPlane/context.ts +4 -0
  237. package/src/controlPlane/data/connection.ts +90 -0
  238. package/src/controlPlane/error/errors.ts +10 -3
  239. package/src/controlPlane/http/cors.ts +4 -4
  240. package/src/controlPlane/http/guard.ts +35 -2
  241. package/src/controlPlane/http/handlers.ts +41 -0
  242. package/src/controlPlane/http/readiness.ts +50 -0
  243. package/src/controlPlane/http/responses.ts +140 -2
  244. package/src/controlPlane/http/routes.ts +82 -10
  245. package/src/controlPlane/http/verify.ts +2 -0
  246. package/src/controlPlane/migrationState/migrationState.ts +200 -0
  247. package/src/controlPlane/migrations/0003_connection_principal.ts +37 -0
  248. package/src/controlPlane/scope/scope.ts +14 -2
  249. package/src/createBackend.ts +59 -8
  250. package/src/createEntrypoint.ts +9 -3
  251. package/src/entitlement/allowance.ts +85 -0
  252. package/src/entitlement/entitlement.ts +38 -0
  253. package/src/entitlement/meter.ts +69 -0
  254. package/src/entitlement/require.ts +1 -1
  255. package/src/error/cause.ts +18 -181
  256. package/src/error/payload.ts +270 -4
  257. package/src/error/pithyError.ts +76 -0
  258. package/src/error/unresolved.ts +853 -0
  259. package/src/error/wire.ts +40 -0
  260. package/src/http/authContext.ts +13 -1
  261. package/src/http/oidcWebhook.ts +3 -3
  262. package/src/http/routeContract.ts +1 -1
  263. package/src/http/routeSpec.ts +81 -0
  264. package/src/http/sameOrigin.ts +1 -1
  265. package/src/http/scopeGates.ts +34 -0
  266. package/src/http/signedWebhook.ts +3 -3
  267. package/src/http/socket.ts +55 -0
  268. package/src/http/subprotocol.ts +47 -0
  269. package/src/http/validation.ts +50 -8
  270. package/src/index.ts +1 -0
  271. package/src/migrations/bookkeeping.ts +39 -2
  272. package/src/migrations/capabilitySets.ts +87 -0
  273. package/src/migrations/groups.ts +295 -0
  274. package/src/migrations/migrateStep.ts +19 -0
  275. package/src/migrations/owner.ts +10 -6
  276. package/src/migrations/registry.ts +46 -2
  277. package/src/migrations/retained.ts +2 -2
  278. package/src/migrations/runner.ts +214 -22
  279. package/src/migrations/state.ts +94 -0
  280. package/src/naming/domains.ts +75 -16
  281. package/src/naming/environment.ts +2 -1
  282. package/src/naming/feature.ts +46 -7
  283. package/src/naming/limits.ts +35 -3
  284. package/src/naming/packageName.ts +20 -0
  285. package/src/naming/provisionScope.ts +21 -2
  286. package/src/naming/resourceNames.ts +52 -5
  287. package/src/openapi/document.ts +412 -0
  288. package/src/openapi/routeGroups.ts +25 -0
  289. package/src/seed/writeD1.ts +13 -4
  290. package/src/seed/writeKv.ts +6 -2
  291. package/src/text/comments.ts +56 -4
  292. package/src/text/literals.ts +294 -0
  293. package/src/version.generated.ts +1 -1
  294. package/src/worker/serviceLoopback.ts +105 -0
  295. package/src/workflow/dispatchRoute.ts +13 -6
  296. package/src/workflow/faults.ts +56 -27
  297. package/src/workflow/hostEnv.ts +9 -1
  298. package/src/workflow/loopback.ts +2 -1
@@ -9,9 +9,24 @@ import { assertValidProjectName, kebab } from "./resource.js";
9
9
  const FEATURE_RESOURCE_KINDS = [
10
10
  "d1",
11
11
  "kv",
12
- "r2"
12
+ "r2",
13
+ "queue"
13
14
  ];
14
15
  /**
16
+ * **The segment each kind ends a feature resource's name with — never more than `MAX_FEATURE_KIND` (#662).**
17
+ *
18
+ * `d1`, `kv` and `r2` spell themselves. A queue is `q`, and that is load-bearing: `MAX_FEATURE_KIND` is a term in
19
+ * `FEATURE_DERIVED_PROJECT_NAME`, so spelling it `queue` would take the project budget from 26 to 23 — and a
20
+ * project name is stable forever once anything is provisioned, so a smaller budget orphans every resource of a
21
+ * project already named against the old one. `feature.test.ts` fails on a segment longer than the budget.
22
+ */
23
+ const FEATURE_KIND_SEGMENT = {
24
+ d1: "d1",
25
+ kv: "kv",
26
+ r2: "r2",
27
+ queue: "q"
28
+ };
29
+ /**
15
30
  * Refuse an issue number the budgets were not derived against.
16
31
  *
17
32
  * `MAX_ISSUE_DIGITS` is a term in {@link FEATURE_DERIVED_PROJECT_NAME}, so an eight-digit issue would
@@ -193,14 +208,15 @@ function assertFeatureSlugFits(identity, shapes) {
193
208
  });
194
209
  }
195
210
  /**
196
- * The full Cloudflare resource name for a feature's binding — `<project>-f<issue>-<slug>--<binding>-<kind>`.
211
+ * The full Cloudflare resource name for a feature's binding — `<project>-f<issue>-<slug>--<binding>-<kind>`, the
212
+ * kind spelled by {@link FEATURE_KIND_SEGMENT}.
197
213
  *
198
- * Held to **R2's 63**, the strictest of the three kinds a feature provisions, so one shape is legal for
199
- * all of them: lowercase, hyphenated, alphanumeric at both ends. A D1 or KV name could be longer, but a
214
+ * Held to **R2's 63**, the strictest of the kinds a feature provisions and a queue's number too, so one shape is
215
+ * legal for all of them: lowercase, hyphenated, alphanumeric at both ends. A D1 or KV name could be longer, but a
200
216
  * feature that provisions a bucket and a database wants them recognizably the same name.
201
217
  */
202
218
  function featureResourceName(identity, binding, kind) {
203
- return composeFeatureName(identity, kebab(identity.slug), kebab(binding), `-${kind}`, NAMESPACE_LIMITS.r2.maxLength, NAMESPACE_LIMITS.r2.label);
219
+ return composeFeatureName(identity, kebab(identity.slug), kebab(binding), `-${FEATURE_KIND_SEGMENT[kind]}`, NAMESPACE_LIMITS.r2.maxLength, NAMESPACE_LIMITS.r2.label);
204
220
  }
205
221
  /**
206
222
  * The CF Secrets Store entry name holding one of a feature's **environment-scoped** secrets —
@@ -241,6 +257,20 @@ function featureSecretEntryName(identity, secret) {
241
257
  function featureWorkerName(identity, app) {
242
258
  return composeFeatureName(identity, kebab(identity.slug), kebab(app), "", NAMESPACE_LIMITS.worker.maxLength, NAMESPACE_LIMITS.worker.label);
243
259
  }
260
+ /** The `<thing>` a feature's Artifacts namespace ends with, after {@link FEATURE_TAIL_SEPARATOR} (#673). */
261
+ const FEATURE_ARTIFACTS_THING = "artifacts";
262
+ /**
263
+ * A feature's **Artifacts namespace** — `<project>-f<issue>-<slug>--artifacts` (#673).
264
+ *
265
+ * A declared environment's namespace is `<project>-<env>` and has no `<thing>`. A feature's needs one, because the
266
+ * separator and what follows it are what make a name a feature name: {@link isFeatureOwnedName} reads this one back
267
+ * as this feature's, so `pithy feature destroy` reaps the repos of exactly this branch and of no sibling. Held to the
268
+ * namespace's 63, the same number the rest of a feature's names are derived against, and `artifacts` is shorter than
269
+ * the shortest binding tail, so it moves no slug budget.
270
+ */
271
+ function featureArtifactsNamespace(identity) {
272
+ return composeFeatureName(identity, kebab(identity.slug), FEATURE_ARTIFACTS_THING, "", NAMESPACE_LIMITS.artifactsNamespace.maxLength, NAMESPACE_LIMITS.artifactsNamespace.label);
273
+ }
244
274
  /**
245
275
  * The deployed name of one of a feature's **Workflows** — `<project>-f<issue>-<slug>--<capability>-<job>` (#643).
246
276
  *
@@ -266,4 +296,4 @@ function featureVectorizeIndexName(identity, thing) {
266
296
  return composeFeatureName(identity, kebab(identity.slug), kebab(thing), "", NAMESPACE_LIMITS.vectorizeIndex.maxLength, NAMESPACE_LIMITS.vectorizeIndex.label);
267
297
  }
268
298
  //#endregion
269
- export { FEATURE_RESOURCE_KINDS, assertFeatureProject, assertFeatureSlugFits, canonicalIssue, featureMarkerInProjectName, featureResourceName, featureSecretEntryName, featureSlugRoom, featureVectorizeIndexName, featureWorkerName, featureWorkflowName, isFeatureOwnedName, maxFeatureSlug, parseFeatureName, tightestFeatureShape };
299
+ export { FEATURE_ARTIFACTS_THING, FEATURE_KIND_SEGMENT, FEATURE_RESOURCE_KINDS, assertFeatureProject, assertFeatureSlugFits, canonicalIssue, featureArtifactsNamespace, featureMarkerInProjectName, featureResourceName, featureSecretEntryName, featureSlugRoom, featureVectorizeIndexName, featureWorkerName, featureWorkflowName, isFeatureOwnedName, maxFeatureSlug, parseFeatureName, tightestFeatureShape };
@@ -123,6 +123,47 @@ export declare const NAMESPACE_LIMITS: {
123
123
  readonly policy: "truncate";
124
124
  readonly source: "cloudflare";
125
125
  };
126
+ /**
127
+ * A Queue name: **1 to 63 characters**, lowercase letters, digits and dashes, starting and ending with a letter
128
+ * or number ([Queues · Get started](https://developers.cloudflare.com/queues/get-started/), verified
129
+ * 2026-10-18). Truncated rather than refused: Pithy recomputes a queue's name from its binding on every run,
130
+ * as it does a bucket's, so a deterministic hash is safe (#662). The same 63 as R2, so a feature's queue fits
131
+ * the shape {@link FEATURE_DERIVED_PROJECT_NAME} is derived against and moves no budget.
132
+ */
133
+ readonly queue: {
134
+ readonly label: "a Queue name";
135
+ readonly maxLength: 63;
136
+ readonly minLength: 1;
137
+ readonly policy: "truncate";
138
+ readonly source: "cloudflare";
139
+ };
140
+ /**
141
+ * An Artifacts namespace: **2 to 63 characters**, starting with a letter or digit, the rest letters, digits, `.`,
142
+ * `_` and `-` ([Artifacts · Limits](https://developers.cloudflare.com/artifacts/platform/limits/), verified
143
+ * 2026-10-18). Truncated rather than refused: the kit derives it from the project and the environment on every
144
+ * run, like an R2 bucket name, and the longest project and environment compose 34 characters, so it never is (#673).
145
+ */
146
+ readonly artifactsNamespace: {
147
+ readonly label: "an Artifacts namespace name";
148
+ readonly maxLength: 63;
149
+ readonly minLength: 2;
150
+ readonly policy: "truncate";
151
+ readonly source: "cloudflare";
152
+ };
153
+ /**
154
+ * An Artifacts repo name. **The charset is Cloudflare's** — a letter or digit, then letters, digits, `.`, `_` and
155
+ * `-` ([Artifacts · Limits](https://developers.cloudflare.com/artifacts/platform/limits/), verified 2026-10-18) —
156
+ * and **the length is ours**: that page states one for a namespace and none for a repo, so 2 to 63 mirrors the
157
+ * namespace rather than inventing a second number. Refused, never truncated: a repo name is either a UUID or a
158
+ * name somebody chose, and a name somebody chose is never silently shortened (#673).
159
+ */
160
+ readonly artifactsRepo: {
161
+ readonly label: "an Artifacts repo name";
162
+ readonly maxLength: 63;
163
+ readonly minLength: 2;
164
+ readonly policy: "refuse";
165
+ readonly source: "pithy";
166
+ };
126
167
  /**
127
168
  * A D1 database name: `^[a-zA-Z0-9][a-zA-Z0-9_-]*$` in the OpenAPI schema, and **no documented
128
169
  * length cap** — the limits page has no row for it. So the ceiling here is {@link MAX_PITHY_NAME}.
@@ -211,7 +252,10 @@ export declare const FEATURE_TAIL_SEPARATOR = "--";
211
252
  * and teardown recomputes the name rather than matching a prefix.
212
253
  */
213
254
  export declare const MIN_VERBATIM_BINDING = 12;
214
- /** The longest feature resource kind — `d1`, `kv`, `r2` are all two characters. `feature.test.ts` pins it. */
255
+ /**
256
+ * The longest feature resource kind segment — `d1`, `kv`, `r2`, and a queue's `q` (#662). `feature.test.ts` pins
257
+ * every kind's `FEATURE_KIND_SEGMENT` to it, so a longer segment fails rather than shrinking every project's budget.
258
+ */
215
259
  export declare const MAX_FEATURE_KIND = 2;
216
260
  /**
217
261
  * What the longest Workflow name leaves a project.
@@ -229,7 +273,7 @@ export declare const MAX_FEATURE_KIND = 2;
229
273
  export declare const WORKFLOW_DERIVED_PROJECT_NAME: number;
230
274
  /**
231
275
  * What the longest feature resource name leaves a project — `<project>-f<issue>-<slug>--<binding>-<kind>`,
232
- * against R2's 63 (the strictest of the three kinds a feature provisions, and the same number a
276
+ * against R2's 63 (the strictest of the kinds a feature provisions, a queue's number too, and the same number a
233
277
  * feature Worker script gets).
234
278
  *
235
279
  * ```
@@ -238,7 +282,7 @@ export declare const WORKFLOW_DERIVED_PROJECT_NAME: number;
238
282
  * - 6 the issue number, six digits — `f999999` (MAX_ISSUE_DIGITS)
239
283
  * - 12 `-` + a legible slug (MIN_LEGIBLE_SLUG)
240
284
  * - 14 `--` + a binding kept whole (FEATURE_TAIL_SEPARATOR, MIN_VERBATIM_BINDING)
241
- * - 3 `-` + the kind, `d1` | `kv` | `r2`
285
+ * - 3 `-` + the kind, `d1` | `kv` | `r2` | `q`
242
286
  * ----
243
287
  * 26
244
288
  * ```
@@ -1 +1 @@
1
- {"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/naming/limits.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;GAcG;AAEH,sFAAsF;AACtF,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,OAAO,CAAC;AAEjD;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEnD,8FAA8F;AAC9F,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,kGAAkG;IAClG,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,4FAA4F;IAC5F,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC;;;GAGG;AACH,eAAO,MAAM,gBAAgB;IAC3B;;;OAGG;;iBACS,KAAK,EAAE,iBAAiB;iBAAE,SAAS,EAAE,EAAE;iBAAE,SAAS,EAAE,CAAC;iBAAE,MAAM,EAAE,QAAQ;iBAAE,MAAM,EAAE,YAAY;;IACzG;;;;;;OAMG;;iBACO,KAAK,EAAE,sBAAsB;iBAAE,SAAS,EAAE,EAAE;iBAAE,SAAS,EAAE,CAAC;iBAAE,MAAM,EAAE,QAAQ;iBAAE,MAAM,EAAE,YAAY;;IAC5G;;;OAGG;;iBACG,KAAK,EAAE,mBAAmB;iBAAE,SAAS,EAAE,EAAE;iBAAE,SAAS,EAAE,CAAC;iBAAE,MAAM,EAAE,UAAU;iBAAE,MAAM,EAAE,YAAY;;IACvG;;;;OAIG;;iBAED,KAAK,EAAE,wBAAwB;iBAC/B,SAAS,EAAE,EAAE;iBACb,SAAS,EAAE,CAAC;iBACZ,MAAM,EAAE,QAAQ;iBAChB,MAAM,EAAE,YAAY;;IAEtB;;;;;OAKG;;iBACG,KAAK,EAAE,sBAAsB;iBAAE,SAAS,EAAE,GAAG;iBAAE,SAAS,EAAE,CAAC;iBAAE,MAAM,EAAE,UAAU;iBAAE,MAAM,EAAE,YAAY;;IAC3G;;;OAGG;;iBACG,KAAK,EAAE,oBAAoB;iBAAE,SAAS;iBAAkB,SAAS,EAAE,CAAC;iBAAE,MAAM,EAAE,UAAU;iBAAE,MAAM,EAAE,OAAO;;IAC/G;;;OAGG;;iBAED,KAAK,EAAE,4BAA4B;iBACnC,SAAS;iBACT,SAAS,EAAE,CAAC;iBACZ,MAAM,EAAE,UAAU;iBAClB,MAAM,EAAE,OAAO;;IAEjB;;;OAGG;;iBAED,KAAK,EAAE,6BAA6B;iBACpC,SAAS;iBACT,SAAS,EAAE,CAAC;iBACZ,MAAM,EAAE,UAAU;iBAClB,MAAM,EAAE,OAAO;;CAEgC,CAAC;AAEpD,0DAA0D;AAC1D,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,gBAAgB,CAAC;AAEtD;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,QAAkC,CAAC;AAElE;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAE3C;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC,8GAA8G;AAC9G,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,6BAA6B,QAC+C,CAAC;AAE1F;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,4BAA4B,QAMjB,CAAC"}
1
+ {"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/naming/limits.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;GAcG;AAEH,sFAAsF;AACtF,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,OAAO,CAAC;AAEjD;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEnD,8FAA8F;AAC9F,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,kGAAkG;IAClG,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,4FAA4F;IAC5F,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC;;;GAGG;AACH,eAAO,MAAM,gBAAgB;IAC3B;;;OAGG;;iBACS,KAAK,EAAE,iBAAiB;iBAAE,SAAS,EAAE,EAAE;iBAAE,SAAS,EAAE,CAAC;iBAAE,MAAM,EAAE,QAAQ;iBAAE,MAAM,EAAE,YAAY;;IACzG;;;;;;OAMG;;iBACO,KAAK,EAAE,sBAAsB;iBAAE,SAAS,EAAE,EAAE;iBAAE,SAAS,EAAE,CAAC;iBAAE,MAAM,EAAE,QAAQ;iBAAE,MAAM,EAAE,YAAY;;IAC5G;;;OAGG;;iBACG,KAAK,EAAE,mBAAmB;iBAAE,SAAS,EAAE,EAAE;iBAAE,SAAS,EAAE,CAAC;iBAAE,MAAM,EAAE,UAAU;iBAAE,MAAM,EAAE,YAAY;;IACvG;;;;OAIG;;iBAED,KAAK,EAAE,wBAAwB;iBAC/B,SAAS,EAAE,EAAE;iBACb,SAAS,EAAE,CAAC;iBACZ,MAAM,EAAE,QAAQ;iBAChB,MAAM,EAAE,YAAY;;IAEtB;;;;;OAKG;;iBACG,KAAK,EAAE,sBAAsB;iBAAE,SAAS,EAAE,GAAG;iBAAE,SAAS,EAAE,CAAC;iBAAE,MAAM,EAAE,UAAU;iBAAE,MAAM,EAAE,YAAY;;IAC3G;;;;;;OAMG;;iBACM,KAAK,EAAE,cAAc;iBAAE,SAAS,EAAE,EAAE;iBAAE,SAAS,EAAE,CAAC;iBAAE,MAAM,EAAE,UAAU;iBAAE,MAAM,EAAE,YAAY;;IACrG;;;;;OAKG;;iBAED,KAAK,EAAE,6BAA6B;iBACpC,SAAS,EAAE,EAAE;iBACb,SAAS,EAAE,CAAC;iBACZ,MAAM,EAAE,UAAU;iBAClB,MAAM,EAAE,YAAY;;IAEtB;;;;;;OAMG;;iBACc,KAAK,EAAE,wBAAwB;iBAAE,SAAS,EAAE,EAAE;iBAAE,SAAS,EAAE,CAAC;iBAAE,MAAM,EAAE,QAAQ;iBAAE,MAAM,EAAE,OAAO;;IAChH;;;OAGG;;iBACG,KAAK,EAAE,oBAAoB;iBAAE,SAAS;iBAAkB,SAAS,EAAE,CAAC;iBAAE,MAAM,EAAE,UAAU;iBAAE,MAAM,EAAE,OAAO;;IAC/G;;;OAGG;;iBAED,KAAK,EAAE,4BAA4B;iBACnC,SAAS;iBACT,SAAS,EAAE,CAAC;iBACZ,MAAM,EAAE,UAAU;iBAClB,MAAM,EAAE,OAAO;;IAEjB;;;OAGG;;iBAED,KAAK,EAAE,6BAA6B;iBACpC,SAAS;iBACT,SAAS,EAAE,CAAC;iBACZ,MAAM,EAAE,UAAU;iBAClB,MAAM,EAAE,OAAO;;CAEgC,CAAC;AAEpD,0DAA0D;AAC1D,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,gBAAgB,CAAC;AAEtD;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,QAAkC,CAAC;AAElE;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAE3C;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC;;;GAGG;AACH,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,6BAA6B,QAC+C,CAAC;AAE1F;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,4BAA4B,QAMjB,CAAC"}
@@ -80,6 +80,47 @@ const NAMESPACE_LIMITS = {
80
80
  source: "cloudflare"
81
81
  },
82
82
  /**
83
+ * A Queue name: **1 to 63 characters**, lowercase letters, digits and dashes, starting and ending with a letter
84
+ * or number ([Queues · Get started](https://developers.cloudflare.com/queues/get-started/), verified
85
+ * 2026-10-18). Truncated rather than refused: Pithy recomputes a queue's name from its binding on every run,
86
+ * as it does a bucket's, so a deterministic hash is safe (#662). The same 63 as R2, so a feature's queue fits
87
+ * the shape {@link FEATURE_DERIVED_PROJECT_NAME} is derived against and moves no budget.
88
+ */
89
+ queue: {
90
+ label: "a Queue name",
91
+ maxLength: 63,
92
+ minLength: 1,
93
+ policy: "truncate",
94
+ source: "cloudflare"
95
+ },
96
+ /**
97
+ * An Artifacts namespace: **2 to 63 characters**, starting with a letter or digit, the rest letters, digits, `.`,
98
+ * `_` and `-` ([Artifacts · Limits](https://developers.cloudflare.com/artifacts/platform/limits/), verified
99
+ * 2026-10-18). Truncated rather than refused: the kit derives it from the project and the environment on every
100
+ * run, like an R2 bucket name, and the longest project and environment compose 34 characters, so it never is (#673).
101
+ */
102
+ artifactsNamespace: {
103
+ label: "an Artifacts namespace name",
104
+ maxLength: 63,
105
+ minLength: 2,
106
+ policy: "truncate",
107
+ source: "cloudflare"
108
+ },
109
+ /**
110
+ * An Artifacts repo name. **The charset is Cloudflare's** — a letter or digit, then letters, digits, `.`, `_` and
111
+ * `-` ([Artifacts · Limits](https://developers.cloudflare.com/artifacts/platform/limits/), verified 2026-10-18) —
112
+ * and **the length is ours**: that page states one for a namespace and none for a repo, so 2 to 63 mirrors the
113
+ * namespace rather than inventing a second number. Refused, never truncated: a repo name is either a UUID or a
114
+ * name somebody chose, and a name somebody chose is never silently shortened (#673).
115
+ */
116
+ artifactsRepo: {
117
+ label: "an Artifacts repo name",
118
+ maxLength: 63,
119
+ minLength: 2,
120
+ policy: "refuse",
121
+ source: "pithy"
122
+ },
123
+ /**
83
124
  * A D1 database name: `^[a-zA-Z0-9][a-zA-Z0-9_-]*$` in the OpenAPI schema, and **no documented
84
125
  * length cap** — the limits page has no row for it. So the ceiling here is {@link MAX_PITHY_NAME}.
85
126
  */
@@ -165,7 +206,10 @@ const FEATURE_TAIL_SEPARATOR = "--";
165
206
  * and teardown recomputes the name rather than matching a prefix.
166
207
  */
167
208
  const MIN_VERBATIM_BINDING = 12;
168
- /** The longest feature resource kind — `d1`, `kv`, `r2` are all two characters. `feature.test.ts` pins it. */
209
+ /**
210
+ * The longest feature resource kind segment — `d1`, `kv`, `r2`, and a queue's `q` (#662). `feature.test.ts` pins
211
+ * every kind's `FEATURE_KIND_SEGMENT` to it, so a longer segment fails rather than shrinking every project's budget.
212
+ */
169
213
  const MAX_FEATURE_KIND = 2;
170
214
  /**
171
215
  * What the longest Workflow name leaves a project.
@@ -183,7 +227,7 @@ const MAX_FEATURE_KIND = 2;
183
227
  const WORKFLOW_DERIVED_PROJECT_NAME = NAMESPACE_LIMITS.workflow.maxLength - 1 - MAX_ENVIRONMENT_NAME - 1 - 22;
184
228
  /**
185
229
  * What the longest feature resource name leaves a project — `<project>-f<issue>-<slug>--<binding>-<kind>`,
186
- * against R2's 63 (the strictest of the three kinds a feature provisions, and the same number a
230
+ * against R2's 63 (the strictest of the kinds a feature provisions, a queue's number too, and the same number a
187
231
  * feature Worker script gets).
188
232
  *
189
233
  * ```
@@ -192,7 +236,7 @@ const WORKFLOW_DERIVED_PROJECT_NAME = NAMESPACE_LIMITS.workflow.maxLength - 1 -
192
236
  * - 6 the issue number, six digits — `f999999` (MAX_ISSUE_DIGITS)
193
237
  * - 12 `-` + a legible slug (MIN_LEGIBLE_SLUG)
194
238
  * - 14 `--` + a binding kept whole (FEATURE_TAIL_SEPARATOR, MIN_VERBATIM_BINDING)
195
- * - 3 `-` + the kind, `d1` | `kv` | `r2`
239
+ * - 3 `-` + the kind, `d1` | `kv` | `r2` | `q`
196
240
  * ----
197
241
  * 26
198
242
  * ```
@@ -0,0 +1,17 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ /**
4
+ * The package a bare specifier names: `@pithy-sh/payments` from `@pithy-sh/payments/src/capability`, and
5
+ * `stripe` from `stripe/lib/x` — **scope-aware, and the only copy in the kit (#709)**.
6
+ *
7
+ * There were five. Three took the first segment or two depending on a leading `@`; two took the first two
8
+ * segments whatever they were, which is right for every `@pithy-sh/*` name they were written against and
9
+ * wrong for the first unscoped dependency anyone passed them. A rule that small drifts precisely because
10
+ * nobody thinks it needs a home, so it has one. That it is the only copy is a gate, not a claim: `packages/cli/src/ci/packageOfCopies.test.ts` fails on any source that writes the rule out by hand, because the first migration left three behind and said it had not.
11
+ *
12
+ * Total, and deliberately unopinionated about what it is handed: a caller with a relative path, a `#`
13
+ * import or a URL gets the first segment back. Deciding whether a specifier is a package at all is the
14
+ * unresolved-import classifier's job (`error/unresolved.ts`), not this function's.
15
+ */
16
+ export declare function packageOf(specifier: string): string;
17
+ //# sourceMappingURL=packageName.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packageName.d.ts","sourceRoot":"","sources":["../../src/naming/packageName.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGnD"}
@@ -0,0 +1,22 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ //#region src/naming/packageName.ts
4
+ /**
5
+ * The package a bare specifier names: `@pithy-sh/payments` from `@pithy-sh/payments/src/capability`, and
6
+ * `stripe` from `stripe/lib/x` — **scope-aware, and the only copy in the kit (#709)**.
7
+ *
8
+ * There were five. Three took the first segment or two depending on a leading `@`; two took the first two
9
+ * segments whatever they were, which is right for every `@pithy-sh/*` name they were written against and
10
+ * wrong for the first unscoped dependency anyone passed them. A rule that small drifts precisely because
11
+ * nobody thinks it needs a home, so it has one. That it is the only copy is a gate, not a claim: `packages/cli/src/ci/packageOfCopies.test.ts` fails on any source that writes the rule out by hand, because the first migration left three behind and said it had not.
12
+ *
13
+ * Total, and deliberately unopinionated about what it is handed: a caller with a relative path, a `#`
14
+ * import or a URL gets the first segment back. Deciding whether a specifier is a package at all is the
15
+ * unresolved-import classifier's job (`error/unresolved.ts`), not this function's.
16
+ */
17
+ function packageOf(specifier) {
18
+ const parts = specifier.split("/");
19
+ return specifier.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0] ?? specifier;
20
+ }
21
+ //#endregion
22
+ export { packageOf };
@@ -171,6 +171,12 @@ export interface ProvisionScope {
171
171
  * `<project>-feature-email-send` would be one Workflow every open branch deployed over every other's.
172
172
  */
173
173
  readonly workflowHost: Omit<WorkflowHostNameParts, "capability">;
174
+ /**
175
+ * The Artifacts namespace an `artifacts` binding names in this scope (#673): `<project>-<env>` in a declared
176
+ * environment, `<project>-f<issue>-<slug>--artifacts` in a feature. On the scope for the reason every other name
177
+ * is: the stanza a run writes and the namespace it writes into it are one decision.
178
+ */
179
+ readonly artifactsNamespace: string;
174
180
  }
175
181
  /**
176
182
  * The same branch, one line down, for a provisioned resource: a `global` binding resolves to the
@@ -1 +1 @@
1
- {"version":3,"file":"provisionScope.d.ts","sourceRoot":"","sources":["../../src/naming/provisionScope.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhE,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EAIzB,MAAM,WAAW,CAAC;AAInB;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG,QAAQ,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;CAC1B;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,oBAAoB;IACnC,2GAA2G;IAC3G,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,oGAAoG;IACpG,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B,6FAA6F;IAC7F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,CAAC;IACpF;;;;;;;;;OASG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B;;;;;;;;;;OAUG;IACH,MAAM,CAAC,MAAM,EAAE,oBAAoB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChE;;;;;;;OAOG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,GAAG,MAAM,CAAC;IAClE;;;;;;;;OAQG;IACH,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC,qBAAqB,EAAE,YAAY,CAAC,CAAC;CAClE;AAiBD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,mBAAmB,EACzB,MAAM,EAAE,mBAAmB,GAC1B,MAAM,CAAC;AACV,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,mBAAmB,EACzB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAChC,MAAM,CAAC;AAsBV;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAKpE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,cAAc,CA8BrF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,cAAc,CAiBtE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,oBAAoB,GAAG,MAAM,EAAE,CAY1G"}
1
+ {"version":3,"file":"provisionScope.d.ts","sourceRoot":"","sources":["../../src/naming/provisionScope.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhE,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EAKzB,MAAM,WAAW,CAAC;AAInB;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG,QAAQ,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;CAC1B;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,oBAAoB;IACnC,2GAA2G;IAC3G,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,oGAAoG;IACpG,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B,6FAA6F;IAC7F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,CAAC;IACpF;;;;;;;;;OASG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B;;;;;;;;;;OAUG;IACH,MAAM,CAAC,MAAM,EAAE,oBAAoB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChE;;;;;;;OAOG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,GAAG,MAAM,CAAC;IAClE;;;;;;;;OAQG;IACH,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC,qBAAqB,EAAE,YAAY,CAAC,CAAC;IACjE;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACrC;AAsBD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,mBAAmB,EACzB,MAAM,EAAE,mBAAmB,GAC1B,MAAM,CAAC;AACV,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,mBAAmB,EACzB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAChC,MAAM,CAAC;AAsBV;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAKpE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,cAAc,CA+BrF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,cAAc,CAsBtE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,oBAAoB,GAAG,MAAM,EAAE,CAY1G"}
@@ -1,16 +1,18 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
3
  import { InternalError, ValidationError } from "../error/pithyError.js";
4
+ import { commandName } from "../cli/command.js";
4
5
  import { FEATURE_ENVIRONMENT, assertValidEnvironment, isFeatureMarker } from "./environment.js";
5
6
  import { kebab } from "./resource.js";
6
- import { featureResourceName, featureSecretEntryName, featureWorkerName } from "./feature.js";
7
+ import { featureArtifactsNamespace, featureResourceName, featureSecretEntryName, featureWorkerName } from "./feature.js";
7
8
  import { resourceNames } from "./resourceNames.js";
8
9
  //#region src/naming/provisionScope.ts
9
10
  /** The wrangler binding array a resource kind's name is composed for. */
10
11
  const KIND_NAMER = {
11
12
  d1: "d1",
12
13
  kv: "kv",
13
- r2: "r2"
14
+ r2: "r2",
15
+ queue: "queue"
14
16
  };
15
17
  /**
16
18
  * The one branch every scope shares: a `global` secret resolves to the project's single
@@ -93,7 +95,7 @@ function environmentScope(project, environment) {
93
95
  if (isFeatureName(project, name)) throw new ValidationError({
94
96
  message: `The ${environment} Worker "${name}" is named the way a feature's Worker is.`,
95
97
  action: `Rename it in env.${environment}.name, or the Worker's top-level name, so it does not follow ${kebab(project)}- with f and a number.`,
96
- detail: `${declared === void 0 ? "Composed by wrangler from the deploy name" : `Declared in env.${environment}.name`}. A feature's Worker is <project>-f<issue>-<slug>-<app>, and \`pithy feature destroy\` deletes it by that exact name.`
98
+ detail: `${declared === void 0 ? "Composed by wrangler from the deploy name" : `Declared in env.${environment}.name`}. A feature's Worker is <project>-f<issue>-<slug>-<app>, and \`${commandName("feature destroy")}\` deletes it by that exact name.`
97
99
  });
98
100
  return name;
99
101
  },
@@ -101,7 +103,8 @@ function environmentScope(project, environment) {
101
103
  workflowHost: {
102
104
  project,
103
105
  env: environment
104
- }
106
+ },
107
+ artifactsNamespace: names.artifactsNamespace()
105
108
  };
106
109
  }
107
110
  /**
@@ -144,6 +147,9 @@ function featureScope(identity) {
144
147
  project: identity.project,
145
148
  env: FEATURE_ENVIRONMENT,
146
149
  feature: identity
150
+ },
151
+ get artifactsNamespace() {
152
+ return featureArtifactsNamespace(identity);
147
153
  }
148
154
  };
149
155
  }
@@ -49,6 +49,8 @@ export interface ScopedNames {
49
49
  kv(binding: string): string;
50
50
  /** An R2 bucket. Cloudflare's 63 — the one namespace where that number was always right. */
51
51
  r2(binding: string): string;
52
+ /** A Queue. Cloudflare's 63, truncated with a stable hash like a bucket (#662). */
53
+ queue(binding: string): string;
52
54
  /** A Vectorize index. 64 bytes, refused rather than truncated: a renamed index has no vectors. */
53
55
  vectorizeIndex(index: string): string;
54
56
  /** A Secrets Store entry. No Cloudflare cap; Pithy's ceiling. */
@@ -56,22 +58,39 @@ export interface ScopedNames {
56
58
  /** A Cloudflare API token label. No Cloudflare cap; Pithy's ceiling. */
57
59
  apiToken(profile: string): string;
58
60
  }
61
+ /**
62
+ * The names in one declared environment: everything a scope has, and the one name that exists per environment
63
+ * and never at `global`.
64
+ */
65
+ export interface EnvironmentNames extends ScopedNames {
66
+ /**
67
+ * The Artifacts namespace — `<project>-<env>`, with no `<thing>` (#673). One per environment, so a feature's
68
+ * repos never sit beside production's and the per-namespace rate limit splits per environment. There is no
69
+ * global one, because a namespace shared across environments is exactly that mix.
70
+ */
71
+ artifactsNamespace(): string;
72
+ }
59
73
  /** The names a feature environment provisions under, with the project already bound. */
60
74
  export interface FeatureNames {
61
- /** A feature's D1, KV, or R2 resource — `<project>-f<issue>-<slug>-<binding>-<kind>`. */
75
+ /** A feature's D1, KV, R2 or Queue resource — `<project>-f<issue>-<slug>--<binding>-<kind>`. */
62
76
  resource(binding: string, kind: FeatureResourceKind): string;
63
77
  /**
64
78
  * A feature's Worker script — `<project>-f<issue>-<slug>-<app>`, from the `apps/<app>` directory and
65
79
  * never the deploy name, which already leads with the project (#587).
66
80
  */
67
81
  worker(app: string): string;
82
+ /**
83
+ * A feature's Artifacts namespace — `<project>-f<issue>-<slug>--artifacts` (#673). The tail is what makes it a
84
+ * feature name `isFeatureOwnedName` reads back, so teardown reaps this feature's repos and no sibling's.
85
+ */
86
+ artifactsNamespace(): string;
68
87
  }
69
88
  /** Everything a project can be asked to name. Created once, from the project, by {@link resourceNames}. */
70
89
  export interface ProjectNames {
71
90
  /** The kebabbed project name every name below leads with. */
72
91
  readonly project: string;
73
92
  /** The names in one environment. Throws if the environment is not one this scheme accepts. */
74
- env(environment: string): ScopedNames;
93
+ env(environment: string): EnvironmentNames;
75
94
  /** The names shared by every environment — the `global` scope, without typing the word. */
76
95
  readonly global: ScopedNames;
77
96
  /** The names a feature environment provisions under. */
@@ -1 +1 @@
1
- {"version":3,"file":"resourceNames.d.ts","sourceRoot":"","sources":["../../src/naming/resourceNames.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,mBAAmB,EAA0C,MAAM,WAAW,CAAC;AAInH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,8FAA8F;AAC9F,MAAM,WAAW,WAAW;IAC1B,sGAAsG;IACtG,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,0GAA0G;IAC1G,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAClD,uFAAuF;IACvF,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,kFAAkF;IAClF,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,4FAA4F;IAC5F,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,kGAAkG;IAClG,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACtC,iEAAiE;IACjE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CACnC;AAED,wFAAwF;AACxF,MAAM,WAAW,YAAY;IAC3B,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAAC;IAC7D;;;OAGG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7B;AAED,2GAA2G;AAC3G,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,8FAA8F;IAC9F,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAAC;IACtC,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,wDAAwD;IACxD,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG,YAAY,CAAC;CACnE;AA8DD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAmB3D"}
1
+ {"version":3,"file":"resourceNames.d.ts","sourceRoot":"","sources":["../../src/naming/resourceNames.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EAIzB,MAAM,WAAW,CAAC;AAInB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,8FAA8F;AAC9F,MAAM,WAAW,WAAW;IAC1B,sGAAsG;IACtG,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,0GAA0G;IAC1G,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAClD,uFAAuF;IACvF,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,kFAAkF;IAClF,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,4FAA4F;IAC5F,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,mFAAmF;IACnF,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,kGAAkG;IAClG,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACtC,iEAAiE;IACjE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CACnC;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD;;;;OAIG;IACH,kBAAkB,IAAI,MAAM,CAAC;CAC9B;AAED,wFAAwF;AACxF,MAAM,WAAW,YAAY;IAC3B,gGAAgG;IAChG,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAAC;IAC7D;;;OAGG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B;;;OAGG;IACH,kBAAkB,IAAI,MAAM,CAAC;CAC9B;AAED,2GAA2G;AAC3G,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,8FAA8F;IAC9F,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC3C,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,wDAAwD;IACxD,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG,YAAY,CAAC;CACnE;AA+ED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAuB3D"}
@@ -4,7 +4,7 @@ import { InternalError, ValidationError } from "../error/pithyError.js";
4
4
  import { GLOBAL_SCOPE, assertValidEnvironment } from "./environment.js";
5
5
  import { NAMESPACE_LIMITS } from "./limits.js";
6
6
  import { assertValidProjectName, kebab, resourceName } from "./resource.js";
7
- import { featureResourceName, featureWorkerName } from "./feature.js";
7
+ import { featureArtifactsNamespace, featureResourceName, featureWorkerName } from "./feature.js";
8
8
  import { workflowHostName, workflowScriptName } from "../workflow/naming.js";
9
9
  //#region src/naming/resourceNames.ts
10
10
  /**
@@ -49,6 +49,19 @@ function scopedName(project, scope, thing, limit) {
49
49
  });
50
50
  return name;
51
51
  }
52
+ /**
53
+ * `<project>-<env>`, under the Artifacts namespace rule. The project and environment are both validated by now, and
54
+ * the longest of each compose 34 characters, so the cap is a check rather than a truncation that ever happens.
55
+ */
56
+ function artifactsNamespaceName(project, environment) {
57
+ const limit = NAMESPACE_LIMITS.artifactsNamespace;
58
+ const name = `${project}-${environment}`;
59
+ if (name.length > limit.maxLength || name.length < limit.minLength) throw new InternalError({
60
+ message: `"${name}" does not fit ${limit.label}, which takes ${limit.minLength} to ${limit.maxLength} characters.`,
61
+ action: "Shorten the project or environment name."
62
+ });
63
+ return name;
64
+ }
52
65
  /** The getters for one scope. `global` and every environment share this, so nothing special-cases either. */
53
66
  function scopedNames(project, scope) {
54
67
  return {
@@ -66,6 +79,7 @@ function scopedNames(project, scope) {
66
79
  d1: (binding) => scopedName(project, scope, binding, NAMESPACE_LIMITS.d1),
67
80
  kv: (binding) => scopedName(project, scope, binding, NAMESPACE_LIMITS.kv),
68
81
  r2: (binding) => scopedName(project, scope, binding, NAMESPACE_LIMITS.r2),
82
+ queue: (binding) => scopedName(project, scope, binding, NAMESPACE_LIMITS.queue),
69
83
  vectorizeIndex: (index) => scopedName(project, scope, index, NAMESPACE_LIMITS.vectorizeIndex),
70
84
  secretEntry: (secret) => scopedName(project, scope, secret, NAMESPACE_LIMITS.secretEntry),
71
85
  apiToken: (profile) => scopedName(project, scope, profile, NAMESPACE_LIMITS.apiToken)
@@ -85,7 +99,10 @@ function resourceNames(project) {
85
99
  project: normalized,
86
100
  env(environment) {
87
101
  assertValidEnvironment(environment);
88
- return scopedNames(normalized, environment);
102
+ return {
103
+ ...scopedNames(normalized, environment),
104
+ artifactsNamespace: () => artifactsNamespaceName(normalized, environment)
105
+ };
89
106
  },
90
107
  global: scopedNames(normalized, GLOBAL_SCOPE),
91
108
  feature(identity) {
@@ -95,7 +112,8 @@ function resourceNames(project) {
95
112
  };
96
113
  return {
97
114
  resource: (binding, kind) => featureResourceName(full, binding, kind),
98
- worker: (app) => featureWorkerName(full, app)
115
+ worker: (app) => featureWorkerName(full, app),
116
+ artifactsNamespace: () => featureArtifactsNamespace(full)
99
117
  };
100
118
  }
101
119
  };
@@ -0,0 +1,106 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import type { Hono } from "hono";
4
+ import { z } from "zod";
5
+ /**
6
+ * **The OpenAPI contract, read off a composed app.**
7
+ *
8
+ * Nothing here is written by hand. A route's request schemas come from its `validate` middleware, its
9
+ * summary, verification and responses from its `describeRoute`, and both are found by walking
10
+ * `app.routes` — the same table Hono dispatches from. So the document describes exactly what the Worker
11
+ * serves, the adopter's own routes included, and a schema edit reaches it with no second step.
12
+ *
13
+ * Zod is already the source of truth for every request and response, and every field carries a
14
+ * `.describe()` (CLAUDE.md §Zod). `z.toJSONSchema` keeps those descriptions, which is what lets a client
15
+ * generated in Swift or Kotlin carry the same documentation as the TypeScript one.
16
+ *
17
+ * OpenAPI 3.1, whose schema dialect is JSON Schema 2020-12 — the dialect `z.toJSONSchema` writes — so
18
+ * every schema crosses unchanged.
19
+ */
20
+ /** The OpenAPI version this module writes. */
21
+ export declare const OPENAPI_VERSION = "3.1.0";
22
+ /** One entry of a Hono app's route table: a method, a path and one handler. */
23
+ export type RouterRoute = Hono["routes"][number];
24
+ /** One capability's routes, as registered by its `routes` hook. Becomes one tag. */
25
+ export interface RouteGroup {
26
+ /** The tag, normally the capability's name. */
27
+ readonly tag: string;
28
+ /** What the capability does, for the tag's description. */
29
+ readonly description?: string;
30
+ /** The routes it registered, in registration order. */
31
+ readonly routes: readonly RouterRoute[];
32
+ }
33
+ /** The document's `info` block. */
34
+ export interface ContractInfo {
35
+ readonly title: string;
36
+ readonly version: string;
37
+ readonly description?: string;
38
+ }
39
+ /** A JSON Schema object, as `z.toJSONSchema` writes one. */
40
+ export type JsonSchema = Record<string, unknown>;
41
+ /** The subset of an OpenAPI 3.1 document this module writes. */
42
+ export interface OpenApiDocument {
43
+ openapi: string;
44
+ info: ContractInfo;
45
+ tags: {
46
+ name: string;
47
+ description?: string;
48
+ }[];
49
+ paths: Record<string, Record<string, unknown>>;
50
+ components: {
51
+ schemas: Record<string, JsonSchema>;
52
+ responses: Record<string, unknown>;
53
+ securitySchemes: Record<string, unknown>;
54
+ };
55
+ }
56
+ /** A route that registered no `describeRoute`, so the contract can say nothing true about it. */
57
+ export interface UndescribedRoute {
58
+ readonly method: string;
59
+ readonly path: string;
60
+ }
61
+ /** Hono's `/a/:id{[0-9]+}/*` as OpenAPI's `/a/{id}/{path}`. */
62
+ export declare function openApiPath(path: string): string;
63
+ /**
64
+ * `get` + `/leaderboard/{board}/top` → `getLeaderboardByBoardTop`. A parameter reads as `By<Name>`, so
65
+ * `/items/{id}` and `/items/id` do not meet. Stable, but not unique on its own — `/a-b` and `/a/b` still
66
+ * share one — so {@link openApiDocument} numbers a repeat rather than writing an invalid document.
67
+ */
68
+ export declare function operationId(method: string, path: string): string;
69
+ /** A Zod schema as JSON Schema, without the `$schema` key OpenAPI does not want inside a document. */
70
+ export declare function jsonSchema(schema: z.ZodType, io: "input" | "output"): JsonSchema;
71
+ /** Every route in these groups that registered no `describeRoute`. Empty is the contract being met. */
72
+ export declare function undescribedRoutes(groups: readonly RouteGroup[]): UndescribedRoute[];
73
+ /** How {@link openApiDocument} treats a route with no `describeRoute`. */
74
+ export interface DocumentOptions {
75
+ /**
76
+ * `omit` (the default) leaves it out, which is right for the kit: {@link undescribedRoutes} keeps that
77
+ * set empty, so anything missing is a bug the gate names. `include` writes what the validators alone
78
+ * can say — the path, its parameters and body — marked `x-pithy-undescribed`, which is right for an
79
+ * adopter's own routes: a client generated from the contract still reaches them, and the mark says
80
+ * which ones to describe.
81
+ */
82
+ readonly undescribed?: "omit" | "include";
83
+ }
84
+ /**
85
+ * The OpenAPI document for these route groups. Undescribed routes are left out rather than guessed at,
86
+ * unless {@link DocumentOptions.undescribed} says otherwise; {@link undescribedRoutes} is the check that
87
+ * keeps that set empty.
88
+ */
89
+ export declare function openApiDocument(info: ContractInfo, groups: readonly RouteGroup[], options?: DocumentOptions): OpenApiDocument;
90
+ /** One schema property somewhere in the document that carries no `description`. */
91
+ export interface UndescribedField {
92
+ /** A JSON pointer to the property, e.g. `/paths/~1leaderboard/get/responses/200/…/properties/rank`. */
93
+ readonly pointer: string;
94
+ }
95
+ /**
96
+ * Every object property and every parameter in the document without a description. The kit holds every
97
+ * Zod field to `.describe()`, and this is how that rule is checked on the wire shape a client actually
98
+ * generates from, rather than on the source it came from.
99
+ */
100
+ export declare function undescribedFields(document: OpenApiDocument): UndescribedField[];
101
+ /**
102
+ * The same sweep over any part of a contract document, from a JSON pointer: every object property and every
103
+ * OpenAPI parameter below `node` without a description. The AsyncAPI document runs it over its messages.
104
+ */
105
+ export declare function undescribedFieldsIn(node: unknown, at: string): UndescribedField[];
106
+ //# sourceMappingURL=document.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../src/openapi/document.ts"],"names":[],"mappings":"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"}