@pithy-sh/core 0.1.4 → 0.2.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 (270) hide show
  1. package/dist/address/address.d.ts +2 -0
  2. package/dist/address/address.js +2 -0
  3. package/dist/audit/auditEvent.d.ts +2 -0
  4. package/dist/audit/auditEvent.js +2 -0
  5. package/dist/audit/recorder.d.ts +2 -0
  6. package/dist/audit/recorder.js +2 -0
  7. package/dist/capability/bindings.d.ts +2 -0
  8. package/dist/capability/bindings.js +2 -0
  9. package/dist/capability/capability.d.ts +20 -0
  10. package/dist/capability/capability.d.ts.map +1 -1
  11. package/dist/capability/capability.js +2 -0
  12. package/dist/capability/client.d.ts +2 -0
  13. package/dist/capability/client.js +2 -0
  14. package/dist/capability/compose.d.ts +2 -0
  15. package/dist/capability/compose.js +2 -0
  16. package/dist/capability/composition.d.ts +2 -0
  17. package/dist/capability/composition.js +2 -0
  18. package/dist/capability/config.d.ts +2 -0
  19. package/dist/capability/config.js +2 -0
  20. package/dist/capability/devSecret.d.ts +2 -0
  21. package/dist/capability/devSecret.js +2 -0
  22. package/dist/capability/manifest.d.ts +63 -0
  23. package/dist/capability/manifest.d.ts.map +1 -1
  24. package/dist/capability/manifest.js +63 -1
  25. package/dist/capability/secretOrigin.d.ts +2 -0
  26. package/dist/capability/secretOrigin.js +2 -0
  27. package/dist/capability/settings.d.ts +2 -0
  28. package/dist/capability/settings.js +2 -0
  29. package/dist/capability/validateBindings.d.ts +2 -0
  30. package/dist/capability/validateBindings.js +2 -0
  31. package/dist/capability/vanishingKey.d.ts +2 -0
  32. package/dist/capability/vanishingKey.js +2 -0
  33. package/dist/controlPlane/audit/actions.d.ts +2 -0
  34. package/dist/controlPlane/audit/actions.js +2 -0
  35. package/dist/controlPlane/capability.d.ts +2 -0
  36. package/dist/controlPlane/capability.js +2 -0
  37. package/dist/controlPlane/config/config.d.ts +2 -0
  38. package/dist/controlPlane/config/config.js +2 -0
  39. package/dist/controlPlane/context.d.ts +2 -0
  40. package/dist/controlPlane/context.js +2 -0
  41. package/dist/controlPlane/data/connection.d.ts +2 -0
  42. package/dist/controlPlane/data/connection.js +2 -0
  43. package/dist/controlPlane/data/keyLifecycle.d.ts +2 -0
  44. package/dist/controlPlane/data/keyLifecycle.js +2 -0
  45. package/dist/controlPlane/data/replay.d.ts +2 -0
  46. package/dist/controlPlane/data/replay.js +2 -0
  47. package/dist/controlPlane/data/tables.d.ts +2 -0
  48. package/dist/controlPlane/data/tables.js +2 -0
  49. package/dist/controlPlane/discovery/adminRoute.d.ts +2 -0
  50. package/dist/controlPlane/discovery/adminRoute.js +2 -0
  51. package/dist/controlPlane/discovery/configuration.d.ts +2 -0
  52. package/dist/controlPlane/discovery/configuration.js +2 -0
  53. package/dist/controlPlane/discovery/drift.d.ts +2 -0
  54. package/dist/controlPlane/discovery/drift.js +2 -0
  55. package/dist/controlPlane/discovery/health.d.ts +2 -0
  56. package/dist/controlPlane/discovery/health.js +2 -0
  57. package/dist/controlPlane/discovery/healthSummary.d.ts +2 -0
  58. package/dist/controlPlane/discovery/healthSummary.js +2 -0
  59. package/dist/controlPlane/error/errors.d.ts +2 -0
  60. package/dist/controlPlane/error/errors.js +2 -0
  61. package/dist/controlPlane/http/cors.d.ts +2 -0
  62. package/dist/controlPlane/http/cors.js +2 -0
  63. package/dist/controlPlane/http/guard.d.ts +2 -0
  64. package/dist/controlPlane/http/guard.js +2 -0
  65. package/dist/controlPlane/http/handlers.d.ts +2 -0
  66. package/dist/controlPlane/http/handlers.js +2 -0
  67. package/dist/controlPlane/http/responses.d.ts +2 -0
  68. package/dist/controlPlane/http/responses.js +2 -0
  69. package/dist/controlPlane/http/routes.d.ts +2 -0
  70. package/dist/controlPlane/http/routes.js +2 -0
  71. package/dist/controlPlane/http/schemas.d.ts +2 -0
  72. package/dist/controlPlane/http/schemas.js +2 -0
  73. package/dist/controlPlane/http/verify.d.ts +2 -0
  74. package/dist/controlPlane/http/verify.js +2 -0
  75. package/dist/controlPlane/migrations/0001_init.d.ts +2 -0
  76. package/dist/controlPlane/migrations/0001_init.js +2 -0
  77. package/dist/controlPlane/replay/d1Guard.d.ts +2 -0
  78. package/dist/controlPlane/replay/d1Guard.js +2 -0
  79. package/dist/controlPlane/replay/guard.d.ts +2 -0
  80. package/dist/controlPlane/replay/guard.js +2 -0
  81. package/dist/controlPlane/replay/kvGuard.d.ts +2 -0
  82. package/dist/controlPlane/replay/kvGuard.js +2 -0
  83. package/dist/controlPlane/scope/scope.d.ts +2 -0
  84. package/dist/controlPlane/scope/scope.js +2 -0
  85. package/dist/controlPlane/token/base64url.d.ts +2 -0
  86. package/dist/controlPlane/token/base64url.js +2 -0
  87. package/dist/controlPlane/token/claims.d.ts +2 -0
  88. package/dist/controlPlane/token/claims.js +2 -0
  89. package/dist/controlPlane/token/digest.d.ts +2 -0
  90. package/dist/controlPlane/token/digest.js +2 -0
  91. package/dist/controlPlane/token/jws.d.ts +2 -0
  92. package/dist/controlPlane/token/jws.js +2 -0
  93. package/dist/controlPlane/token/mint.d.ts +2 -0
  94. package/dist/controlPlane/token/mint.js +2 -0
  95. package/dist/controlPlane/wire.d.ts +2 -0
  96. package/dist/controlPlane/wire.js +2 -0
  97. package/dist/createBackend.d.ts +2 -0
  98. package/dist/createBackend.js +2 -0
  99. package/dist/createEntrypoint.d.ts +2 -0
  100. package/dist/createEntrypoint.d.ts.map +1 -1
  101. package/dist/createEntrypoint.js +3 -0
  102. package/dist/data/boundParameters.d.ts +2 -0
  103. package/dist/data/boundParameters.js +2 -0
  104. package/dist/data/codecs.d.ts +2 -0
  105. package/dist/data/codecs.js +2 -0
  106. package/dist/data/cursor.d.ts +2 -0
  107. package/dist/data/cursor.js +2 -0
  108. package/dist/data/databases.d.ts +2 -0
  109. package/dist/data/databases.js +2 -0
  110. package/dist/data/db.d.ts +2 -0
  111. package/dist/data/db.js +2 -0
  112. package/dist/data/withD1Retry.d.ts +2 -0
  113. package/dist/data/withD1Retry.js +2 -0
  114. package/dist/entitlement/entitlement.d.ts +2 -0
  115. package/dist/entitlement/entitlement.js +2 -0
  116. package/dist/entitlement/gateScan.d.ts +2 -0
  117. package/dist/entitlement/gateScan.js +2 -0
  118. package/dist/entitlement/require.d.ts +2 -0
  119. package/dist/entitlement/require.js +2 -0
  120. package/dist/env/ambient.d.ts +2 -0
  121. package/dist/env/ambient.js +2 -0
  122. package/dist/env/ci.d.ts +2 -0
  123. package/dist/env/ci.js +2 -0
  124. package/dist/env/stem.d.ts +2 -0
  125. package/dist/env/stem.js +2 -0
  126. package/dist/error/cause.d.ts +68 -0
  127. package/dist/error/cause.d.ts.map +1 -1
  128. package/dist/error/cause.js +94 -1
  129. package/dist/error/client.d.ts +2 -0
  130. package/dist/error/client.js +2 -0
  131. package/dist/error/extend.d.ts +2 -0
  132. package/dist/error/extend.js +2 -0
  133. package/dist/error/http.d.ts +2 -0
  134. package/dist/error/http.js +2 -0
  135. package/dist/error/payload.d.ts +2 -0
  136. package/dist/error/payload.js +2 -0
  137. package/dist/error/pithyError.d.ts +2 -0
  138. package/dist/error/pithyError.js +2 -0
  139. package/dist/error/terminal.d.ts +2 -0
  140. package/dist/error/terminal.js +2 -0
  141. package/dist/http/authContext.d.ts +2 -0
  142. package/dist/http/authContext.js +2 -0
  143. package/dist/http/routeContract.d.ts +2 -0
  144. package/dist/http/routeContract.js +2 -0
  145. package/dist/http/sameOrigin.d.ts +2 -0
  146. package/dist/http/sameOrigin.js +2 -0
  147. package/dist/http/signedWebhook.d.ts +2 -0
  148. package/dist/http/signedWebhook.js +2 -0
  149. package/dist/http/validation.d.ts +2 -0
  150. package/dist/http/validation.js +2 -0
  151. package/dist/http/verification.d.ts +2 -0
  152. package/dist/http/verification.js +2 -0
  153. package/dist/i18n/acceptLanguage.d.ts +2 -0
  154. package/dist/i18n/acceptLanguage.js +2 -0
  155. package/dist/i18n/catalog.d.ts +2 -0
  156. package/dist/i18n/catalog.js +2 -0
  157. package/dist/i18n/locale.d.ts +2 -0
  158. package/dist/i18n/locale.js +2 -0
  159. package/dist/i18n/localeMarker.d.ts +2 -0
  160. package/dist/i18n/localeMarker.js +2 -0
  161. package/dist/i18n/match.d.ts +2 -0
  162. package/dist/i18n/match.js +2 -0
  163. package/dist/i18n/registry.d.ts +2 -0
  164. package/dist/i18n/registry.js +2 -0
  165. package/dist/i18n/translator.d.ts +2 -0
  166. package/dist/i18n/translator.js +2 -0
  167. package/dist/index.d.ts +2 -0
  168. package/dist/index.js +2 -0
  169. package/dist/kv/kv.d.ts +2 -0
  170. package/dist/kv/kv.js +2 -0
  171. package/dist/kv/namespaces.d.ts +2 -0
  172. package/dist/kv/namespaces.js +2 -0
  173. package/dist/logger/local.d.ts +2 -0
  174. package/dist/logger/local.js +2 -0
  175. package/dist/logger/logger.d.ts +2 -0
  176. package/dist/logger/logger.js +2 -0
  177. package/dist/logger/record.d.ts +2 -0
  178. package/dist/logger/record.js +2 -0
  179. package/dist/logger/worker.d.ts +2 -0
  180. package/dist/logger/worker.js +2 -0
  181. package/dist/migrations/batch.d.ts +2 -0
  182. package/dist/migrations/batch.js +2 -0
  183. package/dist/migrations/bookkeeping.d.ts +2 -0
  184. package/dist/migrations/bookkeeping.js +2 -0
  185. package/dist/migrations/owner.d.ts +2 -0
  186. package/dist/migrations/owner.js +2 -0
  187. package/dist/migrations/registry.d.ts +2 -0
  188. package/dist/migrations/registry.js +2 -0
  189. package/dist/migrations/runner.d.ts +2 -0
  190. package/dist/migrations/runner.js +2 -0
  191. package/dist/naming/domains.d.ts +2 -0
  192. package/dist/naming/domains.js +2 -0
  193. package/dist/naming/environment.d.ts +2 -0
  194. package/dist/naming/environment.js +2 -0
  195. package/dist/naming/feature.d.ts +2 -0
  196. package/dist/naming/feature.js +2 -0
  197. package/dist/naming/limits.d.ts +2 -0
  198. package/dist/naming/limits.js +2 -0
  199. package/dist/naming/provisionScope.d.ts +2 -0
  200. package/dist/naming/provisionScope.js +2 -0
  201. package/dist/naming/resource.d.ts +2 -0
  202. package/dist/naming/resource.js +2 -0
  203. package/dist/naming/resourceNames.d.ts +2 -0
  204. package/dist/naming/resourceNames.js +2 -0
  205. package/dist/naming/segment.d.ts +2 -0
  206. package/dist/naming/segment.js +2 -0
  207. package/dist/projection/asRead.d.ts +2 -0
  208. package/dist/projection/asRead.js +2 -0
  209. package/dist/projection/published.d.ts +2 -0
  210. package/dist/projection/published.js +2 -0
  211. package/dist/schema/describedness.d.ts +2 -0
  212. package/dist/schema/describedness.js +2 -0
  213. package/dist/seed/compose.d.ts +2 -0
  214. package/dist/seed/compose.js +2 -0
  215. package/dist/seed/devLogin.d.ts +2 -0
  216. package/dist/seed/devLogin.js +2 -0
  217. package/dist/seed/exampleIdentities.d.ts +2 -0
  218. package/dist/seed/exampleIdentities.js +2 -0
  219. package/dist/seed/metadata.d.ts +2 -0
  220. package/dist/seed/metadata.js +2 -0
  221. package/dist/seed/seed.d.ts +2 -0
  222. package/dist/seed/seed.js +2 -0
  223. package/dist/seed/seededRows.d.ts +2 -0
  224. package/dist/seed/seededRows.js +2 -0
  225. package/dist/seed/writeD1.d.ts +2 -0
  226. package/dist/seed/writeD1.js +2 -0
  227. package/dist/seed/writeKv.d.ts +2 -0
  228. package/dist/seed/writeKv.js +2 -0
  229. package/dist/semver/semver.d.ts +2 -0
  230. package/dist/semver/semver.js +2 -0
  231. package/dist/text/comments.d.ts +2 -0
  232. package/dist/text/comments.js +2 -0
  233. package/dist/version.generated.d.ts +3 -1
  234. package/dist/version.generated.js +3 -1
  235. package/dist/worker/health.d.ts +2 -0
  236. package/dist/worker/health.js +2 -0
  237. package/dist/worker/identity.d.ts +2 -0
  238. package/dist/worker/identity.js +2 -0
  239. package/dist/workflow/bindings.d.ts +2 -0
  240. package/dist/workflow/bindings.js +2 -0
  241. package/dist/workflow/dispatch.d.ts +2 -0
  242. package/dist/workflow/dispatch.js +2 -0
  243. package/dist/workflow/dispatchRoute.d.ts +2 -0
  244. package/dist/workflow/dispatchRoute.js +2 -0
  245. package/dist/workflow/faults.d.ts +2 -0
  246. package/dist/workflow/faults.js +2 -0
  247. package/dist/workflow/host.d.ts +2 -0
  248. package/dist/workflow/host.js +2 -0
  249. package/dist/workflow/hostEntry.d.ts +2 -0
  250. package/dist/workflow/hostEntry.js +2 -0
  251. package/dist/workflow/hostEnv.d.ts +2 -0
  252. package/dist/workflow/hostEnv.js +2 -0
  253. package/dist/workflow/loopback.d.ts +2 -0
  254. package/dist/workflow/loopback.js +2 -0
  255. package/dist/workflow/naming.d.ts +2 -0
  256. package/dist/workflow/naming.js +2 -0
  257. package/dist/workflow/register.d.ts +2 -0
  258. package/dist/workflow/register.js +2 -0
  259. package/dist/workflow/schemas.d.ts +2 -0
  260. package/dist/workflow/schemas.js +2 -0
  261. package/dist/workflow/spec.d.ts +2 -0
  262. package/dist/workflow/spec.js +2 -0
  263. package/dist/workflow/stepMessage.d.ts +2 -0
  264. package/dist/workflow/stepMessage.js +2 -0
  265. package/package.json +2 -2
  266. package/src/capability/capability.ts +18 -0
  267. package/src/capability/manifest.ts +94 -0
  268. package/src/createEntrypoint.ts +5 -0
  269. package/src/error/cause.ts +116 -0
  270. package/src/version.generated.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"cause.d.ts","sourceRoot":"","sources":["../../src/error/cause.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAGzD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAQjD;AAKD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAG7D;AAeD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAG/D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAQ7D;AAED,mGAAmG;AACnG,MAAM,WAAW,eAAe;IAC9B,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,GAAG,SAAS,CAS3E;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAKtE"}
1
+ {"version":3,"file":"cause.d.ts","sourceRoot":"","sources":["../../src/error/cause.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAGzD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAQjD;AAKD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAG7D;AAeD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAG/D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAQ7D;AAED,mGAAmG;AACnG,MAAM,WAAW,eAAe;IAC9B,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,GAAG,SAAS,CAS3E;AAED,4FAA4F;AAC5F,MAAM,MAAM,cAAc;AACxB,mGAAmG;AACjG,SAAS;AACX,sGAAsG;GACpG,iBAAiB;AACnB,+FAA+F;GAC7F,YAAY,CAAC;AAOjB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,GAAG,SAAS,CAiBzE;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAKtE;AAkBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CASnE"}
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  //#region src/error/cause.ts
2
4
  /**
3
5
  * Reading a thrown value that no type describes — the one place the kit records **what a runtime does to
@@ -174,6 +176,43 @@ function failurePosition(cause) {
174
176
  column: Number(match[2])
175
177
  };
176
178
  }
179
+ /** Whether a path sits inside an installed package. */
180
+ function insideNodeModules(path) {
181
+ return path.split(/[\\/]/).includes("node_modules");
182
+ }
183
+ /**
184
+ * Which of the three unresolved-import causes this was, or `undefined` when it cannot be told.
185
+ *
186
+ * **The discriminator was already in the message and was being thrown away.** `unresolvedSpecifier`
187
+ * matches `Cannot find (?:package|module)` — and `package` versus `module` is exactly the fact that
188
+ * separates a missing dependency from the other two. It sat in a non-capturing group, so every cause
189
+ * arrived wearing one sentence, and for two of the three that sentence advised an install which is
190
+ * *guaranteed* to change nothing. That is #489's class exactly: guidance a caller cannot follow, worst
191
+ * for the caller it is written for, which has no human to shrug and try something else.
192
+ *
193
+ * Measured across Node 24.13.0 and Bun 1.3.14, because the two runtimes hand back different halves and
194
+ * each hands back exactly one usable one:
195
+ *
196
+ * | cause | Node says | Bun's `specifier` |
197
+ * |---|---|---|
198
+ * | package absent | `Cannot find package 'pkg'`, no `url` | `pkg` |
199
+ * | subpath missing | `Cannot find module '/abs/node_modules/pkg/src/nope.js'`, `url` under node_modules | `pkg/src/nope` |
200
+ * | adopter's file | `Cannot find module '/abs/apps/board/src/x'`, `url` outside node_modules | `./src/x` |
201
+ *
202
+ * Bun gives the **specifier as written**, so a leading `.` settles it. Node gives the **already-resolved
203
+ * path**, where being under `node_modules` settles it. Neither read works on both runtimes; the pair
204
+ * does, and it is the same predicate — *is this inside node_modules* — applied to whichever fact the
205
+ * runtime supplied.
206
+ */
207
+ function unresolvedKind(cause) {
208
+ if (/Cannot find package /.test(causeMessage(cause) ?? "")) return "package";
209
+ const specifier = unresolvedSpecifier(cause);
210
+ if (specifier === void 0) return void 0;
211
+ if (/^(?:\.|\/|[A-Za-z]:[\\/])/.test(specifier)) return insideNodeModules(specifier) ? "package-subpath" : "local-file";
212
+ const url = prop(cause, "url");
213
+ if (typeof url === "string" && url.length > 0) return insideNodeModules(url) ? "package-subpath" : "local-file";
214
+ return "package-subpath";
215
+ }
177
216
  /**
178
217
  * The specifier that did not resolve.
179
218
  *
@@ -188,5 +227,59 @@ function unresolvedSpecifier(cause) {
188
227
  if (typeof field === "string" && field.length > 0) return field;
189
228
  return /Cannot find (?:package|module) ['"]([^'"]+)['"]/.exec(causeMessage(cause) ?? "")?.[1];
190
229
  }
230
+ /** A package name as npm allows one: an optional `@scope/`, and never a store's dot-directory. */
231
+ const PACKAGE_NAME = /^(?:@[a-z0-9][\w.-]*\/)?[a-z0-9][\w.-]*$/i;
232
+ /**
233
+ * The file the failing import was written in, as the runtime named it. **Module-private on purpose**: it
234
+ * is an absolute path, and {@link importingPackage} exists to make sure only its package half leaves here.
235
+ */
236
+ function importerPath(cause) {
237
+ const field = prop(cause, "referrer");
238
+ if (typeof field === "string" && field.length > 0) return field;
239
+ const message = causeMessage(cause) ?? "";
240
+ return (/ imported from (.+)$/.exec(message) ?? /\bfrom ['"]([^'"]+)['"]/.exec(message))?.[1];
241
+ }
242
+ /**
243
+ * The package whose own source contained the import that did not resolve — **never a path**.
244
+ *
245
+ * {@link unresolvedSpecifier} answers *what* did not resolve. This answers *where the import lives*, and
246
+ * the two are different facts whenever the failing import is not the adopter's own. #480 is that case
247
+ * verbatim: `pithy add email` on a fresh project refused with
248
+ *
249
+ * > Nothing resolves "@pithy-sh/core/src/capability/capability".
250
+ *
251
+ * while `@pithy-sh/core` resolved from the Worker at every step of the run, before and after. The
252
+ * specifier was honest — the runtime really could not resolve it — but the import belonged to
253
+ * `@pithy-sh/email`, which had just been installed and was the package genuinely not linked. So the
254
+ * refusal named the one dependency that was definitely fine, and an adopter following it ran `bun
255
+ * install` against a tree that already had core in it. The importer is the half that would have pointed
256
+ * at `email`, and both runtimes hand it over: **Bun's `ResolveMessage` carries `referrer` as a field**
257
+ * (measured on 1.3.14) and Node states it in prose as `imported from <path>`.
258
+ *
259
+ * **A package name, or nothing.** The referrer is an absolute path — our frame, and the reason
260
+ * {@link unresolvedSpecifier} drops the prose around the specifier — so what travels is the one part of
261
+ * it that is not a path: the package directory it sits under. A referrer outside `node_modules` is the
262
+ * adopter's own file, and there is nothing to say about it that the refusal does not already say by
263
+ * naming the config, so it answers `undefined` rather than a path. The path itself is never returned
264
+ * from this module, which is what makes leaking it impossible rather than merely discouraged.
265
+ *
266
+ * The **last** `node_modules` in the path, because every store layout nests: pnpm's
267
+ * `node_modules/.pnpm/<id>/node_modules/<pkg>` and Bun's isolated linker's
268
+ * `node_modules/.bun/<pkg>@<version>/node_modules/<pkg>` (both measured) put the real owner last, and so
269
+ * does an ordinary nested install. The name is then checked against what npm allows, so a store's own
270
+ * bookkeeping directory (`.bun`, `.pnpm`, `hono@4.6.3`) can only ever answer nothing.
271
+ *
272
+ * Whether a surface names it, and what it advises when it does, is that surface's policy and stays there.
273
+ */
274
+ function importingPackage(cause) {
275
+ const referrer = importerPath(cause);
276
+ if (referrer === void 0) return void 0;
277
+ const segments = referrer.split(/[\\/]/);
278
+ const at = segments.lastIndexOf("node_modules");
279
+ const head = at === -1 ? void 0 : segments[at + 1];
280
+ if (head === void 0) return void 0;
281
+ const name = head.startsWith("@") ? `${head}/${segments[at + 2] ?? ""}` : head;
282
+ return PACKAGE_NAME.test(name) ? name : void 0;
283
+ }
191
284
  //#endregion
192
- export { causeMessage, failurePosition, isBuildFailureWrapper, prop, rootCause, safeReason, unresolvedSpecifier };
285
+ export { causeMessage, failurePosition, importingPackage, isBuildFailureWrapper, prop, rootCause, safeReason, unresolvedKind, unresolvedSpecifier };
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { z } from "zod";
2
4
  import type { ErrorPayload } from "./payload";
3
5
  import { PublicErrorPayload } from "./payload";
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { PublicErrorPayload } from "./payload.js";
2
4
  //#region src/error/client.ts
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { MessageParams } from "../i18n/catalog";
2
4
  import type { ErrorPayload, KitErrorDomain } from "./payload";
3
5
  import { ExtendedErrorPayload } from "./payload";
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { ExtendedErrorPayload } from "./payload.js";
2
4
  import { InternalError } from "./pithyError.js";
3
5
  //#region src/error/extend.ts
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { Context } from "hono";
2
4
  import { z } from "zod";
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { ErrorPayload, PublicErrorPayload } from "./payload.js";
2
4
  import { InternalError, PithyError, ValidationError, messageOf } from "./pithyError.js";
3
5
  import { clientError } from "./client.js";
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { z } from "zod";
2
4
  /**
3
5
  * The error object model. One Zod schema is the whole definition of every failure Pithy
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { MessageParams } from "../i18n/catalog.js";
2
4
  import { z } from "zod";
3
5
  //#region src/error/payload.ts
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { z } from "zod";
2
4
  import type { MessageParams } from "../i18n/catalog";
3
5
  import type { ValidationIssue } from "./payload";
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { ErrorPayload } from "./payload.js";
2
4
  //#region src/error/pithyError.ts
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { ErrorPayload } from "./payload";
2
4
  import { PublicErrorPayload } from "./payload";
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { PublicErrorPayload } from "./payload.js";
2
4
  //#region src/error/terminal.ts
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { z } from "zod";
2
4
  /**
3
5
  * The auth seam. `@pithy-sh/core` defines this shape; `@pithy-sh/auth` populates it on the
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { Locale } from "../i18n/locale.js";
2
4
  import { z } from "zod";
3
5
  //#region src/http/authContext.ts
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { Hono } from "hono";
2
4
  /**
3
5
  * Gate 2 of the route request contract (issue #74). Its sibling, the `no-raw-request-input` Biome
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  //#region src/http/routeContract.ts
2
4
  /** The `:segment` names in a path pattern, in order. */
3
5
  function pathParams(path) {
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { MiddlewareHandler } from "hono";
2
4
  import type { PithyHonoEnv } from "../capability/capability";
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { ForbiddenError } from "../error/pithyError.js";
2
4
  //#region src/http/sameOrigin.ts
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { MiddlewareHandler } from "hono";
2
4
  import type { PithyHonoEnv } from "../capability/capability";
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { InternalError, WebhookUnverifiedError } from "../error/pithyError.js";
2
4
  //#region src/http/signedWebhook.ts
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { z } from "zod";
2
4
  /**
3
5
  * How a route declares what it accepts. Its sibling {@link ./verification.VerificationStrategy}
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { fromZodError } from "../error/pithyError.js";
2
4
  //#region src/http/validation.ts
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { z } from "zod";
2
4
  /**
3
5
  * How a route verifies the caller's identity/authenticity. Every route declares one —
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { z } from "zod";
2
4
  //#region src/http/verification.ts
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  /** One entry of an `Accept-Language` header: the tag the caller asked for, and how much they meant it. */
2
4
  export interface LanguageRange {
3
5
  /** The language range, lower-cased. `*` survives as itself — it is a valid range, not a tag. */
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import "./locale.js";
2
4
  //#region src/i18n/acceptLanguage.ts
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { z } from "zod";
2
4
  /** A catalog key — `<domain>/<path>`, where `<domain>` is the contributing capability's name. */
3
5
  export declare const MessageKey: z.ZodString;
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { Locale } from "./locale.js";
2
4
  import { z } from "zod";
3
5
  /** A catalog key — `<domain>/<path>`, where `<domain>` is the contributing capability's name. */
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { z } from "zod";
2
4
  /**
3
5
  * The longest language tag this kit accepts. RFC 5646's own grammar allows far more, but a tag that
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { z } from "zod";
2
4
  //#region src/i18n/locale.ts
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  /**
2
4
  * The locale tag this source declares in its head, or `null` if it declares none.
3
5
  *
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  //#region src/i18n/localeMarker.ts
2
4
  /**
3
5
  * Reading the locale a source file declares in its head — the reader for the marker `docs/I18N.md` publishes.
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  /**
2
4
  * A declared exception map: a language range the truncation walk would miss, and the supported locale
3
5
  * it means. `{ nb: "no", tl: "fil" }` — the pairs no algorithm derives, because they are historical
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { parseLocale } from "./locale.js";
2
4
  //#region src/i18n/match.ts
3
5
  /** Lower-cased index of the supported list, so matching is case-insensitive without lower-casing answers. */
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { Capability } from "../capability/capability";
2
4
  import { type LocaleCatalogs, type MessageCatalog } from "./catalog";
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { messageDomain } from "./catalog.js";
2
4
  import { ValidationError } from "../error/pithyError.js";
3
5
  import "./translator.js";
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { type MessageCatalog, type MessageParams } from "./catalog";
2
4
  import { type TextDirection } from "./locale";
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { localeDirection } from "./locale.js";
2
4
  import { interpolate, lookupMessage } from "./catalog.js";
3
5
  //#region src/i18n/translator.ts
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  /**
2
4
  * The `pithy add controlplane` surface — **not a barrel over `@pithy-sh/core`.**
3
5
  *
package/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { ANY_VERIFIED_CALLER, ControlPlaneScope, KEYS_ROTATE_SCOPE, MANIFEST_READ_SCOPE, SEAM_SCOPES } from "./controlPlane/scope/scope.js";
2
4
  import { ControlPlaneConfig } from "./controlPlane/config/config.js";
3
5
  import { ControlPlaneConnection, Ed25519PublicJwk, RegisteredKey } from "./controlPlane/data/connection.js";
package/dist/kv/kv.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { KVNamespace } from "@cloudflare/workers-types";
2
4
  import type { z } from "zod";
3
5
  import type { Logger } from "../logger/logger";
package/dist/kv/kv.js CHANGED
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { InternalError, NotFoundError, messageOf } from "../error/pithyError.js";
2
4
  import { noopLogger } from "../logger/logger.js";
3
5
  //#region src/kv/kv.ts
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { z } from "zod";
2
4
  import type { Capability } from "../capability/capability";
3
5
  import { type BindingGroup } from "../capability/compose";
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { bindingGroupsFrom, composeBindingGroups } from "../capability/compose.js";
2
4
  import { noopLogger } from "../logger/logger.js";
3
5
  import { TypedKv } from "./kv.js";
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { type Logger } from "./logger";
2
4
  import type { LogLevel } from "./record";
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { serializeRecord } from "./record.js";
2
4
  import { createLogger } from "./logger.js";
3
5
  //#region src/logger/local.ts
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { type LogFields, type LogLevel, type LogRecord } from "./record";
2
4
  /**
3
5
  * The `Logger` seam. Four levels, each taking a message plus **structured fields** (not a formatted
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { PithyError } from "../error/pithyError.js";
2
4
  import { LOG_LEVEL_ORDER } from "./record.js";
3
5
  //#region src/logger/logger.ts
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { z } from "zod";
2
4
  /**
3
5
  * The logger object model. A log call is a **record**, not a formatted line — `{ level, msg, ...fields }`
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { ErrorPayload } from "../error/payload.js";
2
4
  import { z } from "zod";
3
5
  //#region src/logger/record.ts
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { type Logger } from "./logger";
2
4
  import type { LogFields, LogLevel, LogRecord } from "./record";
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { serializeRecord } from "./record.js";
2
4
  import { createLogger } from "./logger.js";
3
5
  //#region src/logger/worker.ts
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { D1Database } from "@cloudflare/workers-types";
2
4
  import type { MigrationProvider } from "kysely/migration";
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { D1MigrationDialect } from "./bookkeeping.js";
2
4
  import { CamelCasePlugin, Kysely } from "kysely";
3
5
  //#region src/migrations/batch.ts
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { D1Database } from "@cloudflare/workers-types";
2
4
  import type { DatabaseIntrospector } from "kysely";
3
5
  import { Kysely } from "kysely";
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { CamelCasePlugin, Kysely } from "kysely";
2
4
  import { D1Dialect } from "kysely-d1";
3
5
  //#region src/migrations/bookkeeping.ts
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { D1Database } from "@cloudflare/workers-types";
2
4
  import { z } from "zod";
3
5
  /** The recorded owner of a database: who stamped it, and when. */
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { ConflictError, ValidationError } from "../error/pithyError.js";
2
4
  import { SQLiteDate } from "../data/codecs.js";
3
5
  import { MIGRATION_OWNER_TABLE, migrationKysely } from "./bookkeeping.js";
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { Migration, MigrationProvider } from "kysely/migration";
2
4
  /** Maximum per-capability `order`, derived from the prefix width so the two never drift. */
3
5
  export declare const MAX_MIGRATION_ORDER: number;
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { InternalError } from "../error/pithyError.js";
2
4
  //#region src/migrations/registry.ts
3
5
  /** Width of the zero-padded `order` prefix in a composed key — the stable anchor. */
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import type { D1Database } from "@cloudflare/workers-types";
2
4
  import { type MigrationProvider, type MigrationResult } from "kysely/migration";
3
5
  /**
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { InternalError } from "../error/pithyError.js";
2
4
  import { causeMessage } from "../error/cause.js";
3
5
  import { MIGRATION_LOCK_TABLE, MIGRATION_TABLE, migrationKysely } from "./bookkeeping.js";
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { z } from "zod";
2
4
  /** The environments a domain may be declared for — every managed one, never `dev`. */
3
5
  export declare const DOMAIN_ENVIRONMENTS: ("prod" | "staging")[];
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { ENVIRONMENTS } from "./environment.js";
2
4
  import { z } from "zod";
3
5
  //#region src/naming/domains.ts
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { z } from "zod";
2
4
  /**
3
5
  * What an environment may be called, in one module.
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { NAME_SEGMENT } from "./segment.js";
2
4
  import { PithyError, ValidationError } from "../error/pithyError.js";
3
5
  import { z } from "zod";
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  /**
2
4
  * The names a feature environment provisions under: `<project>-f<issue>-<slug>-<binding>-<kind>` for a
3
5
  * resource, `<project>-f<issue>-<slug>-<worker>` for a Worker script.
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  import { ValidationError } from "../error/pithyError.js";
2
4
  import { NAMESPACE_LIMITS } from "./limits.js";
3
5
  import { assertValidProjectName, fitSegment, kebab } from "./resource.js";
@@ -1,3 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
1
3
  /**
2
4
  * What Cloudflare will actually accept as a name, per namespace — and, where it publishes nothing,
3
5
  * what Pithy chooses instead.