@pithy-sh/core 0.1.5 → 0.3.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 (60) hide show
  1. package/dist/capability/bindings.d.ts +5 -0
  2. package/dist/capability/bindings.d.ts.map +1 -1
  3. package/dist/capability/bindings.js +44 -3
  4. package/dist/capability/capability.d.ts +51 -0
  5. package/dist/capability/capability.d.ts.map +1 -1
  6. package/dist/capability/manifest.d.ts +66 -0
  7. package/dist/capability/manifest.d.ts.map +1 -1
  8. package/dist/capability/manifest.js +62 -2
  9. package/dist/capability/validateBindings.js +1 -1
  10. package/dist/controlPlane/http/cors.js +1 -1
  11. package/dist/createBackend.d.ts +2 -1
  12. package/dist/createBackend.d.ts.map +1 -1
  13. package/dist/createBackend.js +5 -4
  14. package/dist/createEntrypoint.d.ts.map +1 -1
  15. package/dist/createEntrypoint.js +1 -0
  16. package/dist/error/http.d.ts +27 -5
  17. package/dist/error/http.d.ts.map +1 -1
  18. package/dist/error/http.js +33 -9
  19. package/dist/http/oidcWebhook.d.ts +283 -0
  20. package/dist/http/oidcWebhook.d.ts.map +1 -0
  21. package/dist/http/oidcWebhook.js +414 -0
  22. package/dist/http/signedWebhook.d.ts +9 -65
  23. package/dist/http/signedWebhook.d.ts.map +1 -1
  24. package/dist/http/signedWebhook.js +19 -9
  25. package/dist/http/webhookWindow.d.ts +33 -0
  26. package/dist/http/webhookWindow.d.ts.map +1 -0
  27. package/dist/http/webhookWindow.js +35 -0
  28. package/dist/logger/errorHandler.d.ts +11 -0
  29. package/dist/logger/errorHandler.d.ts.map +1 -0
  30. package/dist/logger/errorHandler.js +87 -0
  31. package/dist/naming/environment.js +1 -1
  32. package/dist/naming/provisionScope.d.ts +108 -3
  33. package/dist/naming/provisionScope.d.ts.map +1 -1
  34. package/dist/naming/provisionScope.js +27 -2
  35. package/dist/naming/resource.js +1 -1
  36. package/dist/naming/resourceNames.js +1 -1
  37. package/dist/schema/describedness.d.ts +30 -1
  38. package/dist/schema/describedness.d.ts.map +1 -1
  39. package/dist/schema/describedness.js +42 -6
  40. package/dist/test-utils/oidcFixtures.d.ts +93 -0
  41. package/dist/test-utils/oidcFixtures.d.ts.map +1 -0
  42. package/dist/test-utils/oidcFixtures.js +111 -0
  43. package/dist/version.generated.d.ts +1 -1
  44. package/dist/version.generated.js +1 -1
  45. package/dist/workflow/naming.js +1 -1
  46. package/package.json +1 -1
  47. package/src/capability/bindings.ts +49 -0
  48. package/src/capability/capability.ts +52 -0
  49. package/src/capability/manifest.ts +94 -0
  50. package/src/createBackend.ts +7 -3
  51. package/src/createEntrypoint.ts +5 -0
  52. package/src/error/http.ts +34 -10
  53. package/src/http/oidcWebhook.ts +672 -0
  54. package/src/http/signedWebhook.ts +44 -16
  55. package/src/http/webhookWindow.ts +35 -0
  56. package/src/logger/errorHandler.ts +94 -0
  57. package/src/naming/provisionScope.ts +150 -4
  58. package/src/schema/describedness.ts +51 -6
  59. package/src/test-utils/oidcFixtures.ts +138 -0
  60. package/src/version.generated.ts +1 -1
@@ -57,6 +57,11 @@ export declare const BindingSpec: z.ZodObject<{
57
57
  job: z.ZodOptional<z.ZodString>;
58
58
  service: z.ZodOptional<z.ZodString>;
59
59
  remote: z.ZodOptional<z.ZodBoolean>;
60
+ scope: z.ZodOptional<z.ZodEnum<{
61
+ environment: "environment";
62
+ global: "global";
63
+ }>>;
64
+ resource: z.ZodOptional<z.ZodString>;
60
65
  }, z.core.$strip>;
61
66
  export type BindingSpec = z.infer<typeof BindingSpec>;
62
67
  /** Authoring shape for a capability's `requiredBindings`: `optional` may be omitted. */
@@ -1 +1 @@
1
- {"version":3,"file":"bindings.d.ts","sourceRoot":"","sources":["../../src/capability/bindings.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,WAAW,sTAmBuC,CAAC;AAChE,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAE/D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAU3D;AAqBD;;;GAGG;AACH,eAAO,MAAM,WAAW;;;;;;;;;iBAqFpB,CAAC;AACL,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD,wFAAwF;AACxF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC"}
1
+ {"version":3,"file":"bindings.d.ts","sourceRoot":"","sources":["../../src/capability/bindings.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,WAAW,sTAmBuC,CAAC;AAChE,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAE/D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAU3D;AAkCD;;;GAGG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;iBAwHpB,CAAC;AACL,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD,wFAAwF;AACxF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC"}
@@ -1,6 +1,7 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
3
  import { NAME_SEGMENT } from "../naming/segment.js";
4
+ import { FEATURE_RESOURCE_KINDS } from "../naming/feature.js";
4
5
  import { z } from "zod";
5
6
  //#region src/capability/bindings.ts
6
7
  const BindingType = z.union([
@@ -63,6 +64,35 @@ function isWrittenBinding(type) {
63
64
  return type === "d1" || type === "kv" || type === "r2" || type === "ai" || type === "durable_object" || type === "ratelimit" || type === "workflow";
64
65
  }
65
66
  /**
67
+ * A JavaScript class name — what `className` may be.
68
+ *
69
+ * Constrained because it is no longer only a JSON value. A Durable Object's `className` is written into
70
+ * the adopter's Worker entry as `export { <className> } from "…";` (#428), which is generated TypeScript
71
+ * built out of third-party data read from `node_modules` — the shape #171, #174 and #183 each met one
72
+ * field too late. An identifier cannot close the statement and open another.
73
+ */
74
+ const CLASS_NAME = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
75
+ /**
76
+ * A bare module specifier — a package, optionally with a path into it.
77
+ *
78
+ * The other half of the generated export line, and narrowed for the same reason. No quotes, no
79
+ * whitespace, no `..`: a specifier that walked back out of its own package would re-export whatever it
80
+ * landed on, which is `configImports.isInside`'s argument in a regex.
81
+ */
82
+ const CLASS_MODULE = /^(@[a-z0-9~-][a-z0-9._~-]*\/)?[a-z0-9~-][a-z0-9._~-]*(\/[A-Za-z0-9_~-][A-Za-z0-9._~-]*)*$/;
83
+ /**
84
+ * The kinds whose resource Pithy names and creates — the only kinds `scope` and `resource` mean anything
85
+ * for.
86
+ *
87
+ * {@link FEATURE_RESOURCE_KINDS} rather than a fresh literal, because it is already the repo's answer to
88
+ * "which bindings does a provisioning run compose a `<project>-<scope>-<thing>` name for": it is the
89
+ * domain of `ProvisionScope.resource`, and the CLI's own `PROVISIONABLE` map is the same three. Every
90
+ * other kind's name is composed by a different rule with no `<thing>` slot to fill — a Workflow's from
91
+ * the capability and the job, a Worker script's by wrangler — and a `secret` already states its scope in
92
+ * `defineSecretRegistry`, where the value it names lives.
93
+ */
94
+ const NAMED_RESOURCE_KINDS = new Set(FEATURE_RESOURCE_KINDS);
95
+ /**
66
96
  * Declares a Cloudflare binding a capability requires in the Worker env. The authoring
67
97
  * shape lets `optional` be omitted (defaults false); `createBackend` normalizes via parse.
68
98
  */
@@ -70,11 +100,13 @@ const BindingSpec = z.object({
70
100
  type: BindingType.describe("Resource kind this binding provides."),
71
101
  name: z.string().min(1).describe("Binding name expected in the Worker env (e.g. \"DB\", \"SESSIONS\")."),
72
102
  optional: z.boolean().default(false).describe("If true, createBackend won't fail when this binding is absent."),
73
- className: z.string().min(1).regex(/^[A-Za-z_$][A-Za-z0-9_$]*$/, "A className is a JavaScript identifier: letters, digits, `_` and `$`, not leading a digit.").optional().describe("The exported class this binding is backed by. For a `durable_object` binding it is the DO class (e.g. \"MultiplayerSession\") the CLI writes into `durable_objects.bindings`, the DO class migration tag, and the `export { … }` line in the Worker entry. For a `workflow` binding it is the `WorkflowEntrypoint` subclass (e.g. \"EmailSendWorkflow\") the CLI writes as `class_name` — the same value the capability's own `WorkflowSpec.className` carries. Ignored for every other kind."),
74
- classModule: z.string().min(1).regex(/^(@[a-z0-9~-][a-z0-9._~-]*\/)?[a-z0-9~-][a-z0-9._~-]*(\/[A-Za-z0-9_~-][A-Za-z0-9._~-]*)*$/, "A classModule is a bare module specifier: a package, optionally with a path into it.").optional().describe("The module the class is exported from (e.g. \"@pithy-sh/multiplayer/src/session/durableObject\") — what the CLI writes the Worker entry's `export { <className> } from \"<classModule>\";` against. Required for a `durable_object` binding, because wrangler resolves `class_name` against the entry `main` names and refuses the deploy when nothing there exports it. Its own module, never the package entry point, which `pithy.config.ts` loads in Node. Ignored for every other kind."),
103
+ className: z.string().min(1).regex(CLASS_NAME, "A className is a JavaScript identifier: letters, digits, `_` and `$`, not leading a digit.").optional().describe("The exported class this binding is backed by. For a `durable_object` binding it is the DO class (e.g. \"MultiplayerSession\") the CLI writes into `durable_objects.bindings`, the DO class migration tag, and the `export { … }` line in the Worker entry. For a `workflow` binding it is the `WorkflowEntrypoint` subclass (e.g. \"EmailSendWorkflow\") the CLI writes as `class_name` — the same value the capability's own `WorkflowSpec.className` carries. Ignored for every other kind."),
104
+ classModule: z.string().min(1).regex(CLASS_MODULE, "A classModule is a bare module specifier: a package, optionally with a path into it.").optional().describe("The module the class is exported from (e.g. \"@pithy-sh/multiplayer/src/session/durableObject\") — what the CLI writes the Worker entry's `export { <className> } from \"<classModule>\";` against. Required for a `durable_object` binding, because wrangler resolves `class_name` against the entry `main` names and refuses the deploy when nothing there exports it. Its own module, never the package entry point, which `pithy.config.ts` loads in Node. Ignored for every other kind."),
75
105
  job: z.string().min(1).regex(NAME_SEGMENT, "A job is one name segment: lowercase letters, digits, and single hyphens.").optional().describe("The job within the capability this Workflow runs (e.g. \"send\") — the `<job>` segment of the deployed `<project>-<env>-<capability>-<job>` name, and the second half of the `<capability>/<job>` dispatch key. Meaningful only for a `workflow` binding, where it is what lets `pithy add` name the Workflow offline instead of leaving the binding unwritten. Ignored for every other kind."),
76
106
  service: z.string().min(1).optional().describe("The Worker this binding calls, named as it appears in `apps/<name>/` (e.g. \"api\"). Meaningful only for a `service` binding — the CLI resolves it to that Worker's environment-scoped script name when writing `services` into wrangler.jsonc, so worker-to-worker RPC targets the right deployment per environment. Ignored for every other kind."),
77
- remote: z.boolean().optional().describe("Reach the real Cloudflare resource during local development instead of a local emulation. Set it for a binding that has none — Vectorize and Workers AI both lack local simulation — so `wrangler dev` and any Workflow host, which always runs locally, still work. Left unset rather than defaulting to false, so a spec that does not care emits no flag at all. Ignored in a deployed Worker.")
107
+ remote: z.boolean().optional().describe("Reach the real Cloudflare resource during local development instead of a local emulation. Set it for a binding that has none — Vectorize and Workers AI both lack local simulation — so `wrangler dev` and any Workflow host, which always runs locally, still work. Left unset rather than defaulting to false, so a spec that does not care emits no flag at all. Ignored in a deployed Worker."),
108
+ scope: z.enum(["environment", "global"]).optional().describe("Whether the resource behind this binding is one per environment (absent, the default) or one for the whole project. A `global` resource takes the literal `global` where the environment segment goes — `<project>-global-<thing>` — so every environment's stanza names the identical resource and provisioning creates it once. Declare it where the data is not an environment-local fact: `@pithy-sh/email`'s suppression list is one per project, because an unsubscribe recorded through a staging Worker has to be honored by a production one, and three per-environment databases meant it was not (#513). Say nothing where it is: a session store, a cache, and `@pithy-sh/secrets`' own database are per environment, and one line apart in the same env there is no convention to tell them apart by — which is why this is declared rather than inferred. Meaningful only for a `d1`, `kv` or `r2` binding."),
109
+ resource: z.string().min(1).regex(NAME_SEGMENT, "A resource is one name segment: lowercase letters, digits, and single hyphens.").optional().describe("The `<thing>` segment of this resource's name, when it is not the kebabbed binding name. Absent is the ordinary case and means the binding name is the segment (`EMAIL_SUPPRESSIONS` → `email-suppressions`). Declare it where the two must differ: `SUPPORT_BUCKET` backs `<project>-global-support`, because the binding keeps `_BUCKET` for whoever reads `env.SUPPORT_BUCKET` in a Worker while the resource drops it — `r2` is already the composed name's kind, so the suffix repeats it. Meaningful only for a `d1`, `kv` or `r2` binding.")
78
110
  }).describe("Declares a Cloudflare binding a capability requires in the Worker env.").check((ctx) => {
79
111
  if (ctx.value.type === "durable_object" && ctx.value.className === void 0) ctx.issues.push({
80
112
  code: "custom",
@@ -94,6 +126,15 @@ const BindingSpec = z.object({
94
126
  path: ["service"],
95
127
  message: `Service binding "${ctx.value.name}" needs a service — the Worker it calls, as named in apps/.`
96
128
  });
129
+ if (!NAMED_RESOURCE_KINDS.has(ctx.value.type)) for (const field of ["scope", "resource"]) {
130
+ if (ctx.value[field] === void 0) continue;
131
+ ctx.issues.push({
132
+ code: "custom",
133
+ input: ctx.value,
134
+ path: [field],
135
+ message: `Binding "${ctx.value.name}" declares a ${field}, which only a d1, kv or r2 binding has — this one is a ${ctx.value.type}.`
136
+ });
137
+ }
97
138
  });
98
139
  //#endregion
99
140
  export { BindingSpec, BindingType, isProvisionedBinding, isWrittenBinding };
@@ -156,6 +156,33 @@ export interface SecretRegistryEntrySeam {
156
156
  }
157
157
  /** A capability's secret-registry slice: secret name → {@link SecretRegistryEntrySeam}. */
158
158
  export type SecretRegistrySeam = Record<string, SecretRegistryEntrySeam>;
159
+ /**
160
+ * **Which branches of a `json` secret's schema this Worker's configuration actually uses** — secret
161
+ * name → the top-level keys that apply, in the order they should be offered.
162
+ *
163
+ * A `json` secret is often a bundle of independent blocks: `payments-provider-credentials` is five
164
+ * optional rail blocks, `turnstile-secret-keys` is two optional widgets. The schema says which blocks
165
+ * are *possible*; only the composed config says which are *real*, and a credential for a rail that is
166
+ * off is a value nothing will ever read. So `pithy secrets create` asks per field for the blocks named
167
+ * here, and never offers — never writes — one that is not.
168
+ *
169
+ * **It is declared, not matched by name.** `PaymentsRailToggles.paddle` and
170
+ * `PaymentsProviderCredentials.paddle` happen to be spelled the same today, and a CLI that keyed off
171
+ * that would be right by coincidence: nothing makes a config flag and a schema key the same thing, and
172
+ * two of them one line apart cannot be told apart by convention (#513). The capability already knows
173
+ * the answer at construction — it has both halves in hand — so it states it, and the CLI reads a fact
174
+ * instead of inferring one.
175
+ *
176
+ * **It lives on the capability rather than on the entry** because a registry entry is plain data,
177
+ * shared by every Worker that declares the name and projected into `pithy.manifest.json`. This answer
178
+ * is per composition — the same secret, two Workers, two configs — so it belongs where the config is.
179
+ *
180
+ * An absent declaration is not an empty one. A capability that says nothing leaves the CLI with no way
181
+ * to know which blocks apply, and it falls back to asking for the whole document rather than guessing;
182
+ * an empty array says *none of them apply*, which is the same fallback for a different reason. A
183
+ * secret whose schema has no branches at all needs no declaration — every field is asked.
184
+ */
185
+ export type SecretBranchSeam = Record<string, readonly string[]>;
159
186
  /**
160
187
  * The structural seam for one capability's token-profile slice — profile name → the scoped CF API
161
188
  * token that capability's code needs. Declared next to the code that uses it (alongside
@@ -280,6 +307,12 @@ export interface Capability<Databases extends DatabaseSpecMap = DatabaseSpecMap,
280
307
  * every declared secret in one batch — and no capability needs to know another's secrets.
281
308
  */
282
309
  secretRegistry?: SecretRegistrySeam;
310
+ /**
311
+ * Which branches of this capability's `json` secrets this Worker's configuration uses — see
312
+ * {@link SecretBranchSeam}. Additive and optional: a capability whose secrets are flat, or which has
313
+ * no `json` secret at all, declares nothing.
314
+ */
315
+ secretBranches?: SecretBranchSeam;
283
316
  /**
284
317
  * The scoped CF API tokens this capability's code needs, as a token-profile slice (profile name →
285
318
  * {@link TokenProfileSeam}). Additive and optional, and declared next to {@link Capability.secretRegistry}
@@ -392,6 +425,24 @@ export interface Capability<Databases extends DatabaseSpecMap = DatabaseSpecMap,
392
425
  * every {@link Capability.secretRegistry} slice here into one combined registry.
393
426
  */
394
427
  compose?: (context: CapabilityComposeContext) => void;
428
+ /**
429
+ * Optional **entrypoint** hook, called once by {@link createEntrypoint} with every composed
430
+ * capability, after {@link Capability.compose} has run for all of them.
431
+ *
432
+ * **The distinction from `compose` is the audience, and it is load-bearing.** `createBackend` assembles
433
+ * a backend for anything that wants to look at one, and the CLI is a caller: `pithy ui` builds the app
434
+ * to read its route tree, and `composeCapabilities` runs every `compose` hook to read what a capability
435
+ * reports. `createEntrypoint` is the other thing — it is only ever called by a Worker's own
436
+ * `src/index.ts`, so a throw from here is a Worker that does not serve, and nothing else.
437
+ *
438
+ * So this is where a capability refuses a composition that must never take a request but must still
439
+ * *load*, because the adopter's own toolchain has to keep working on the project while they fix it.
440
+ * `@pithy-sh/payments` is the case it exists for: `pithy add` scaffolds an unimplemented
441
+ * `resolveSubject`, every CLI command keeps loading that config, and the Worker refuses to boot until
442
+ * the adopter has written it (#500). A check that can be made at composition still belongs at
443
+ * composition — earlier is better, and a refusal the CLI can raise is a refusal an adopter sees sooner.
444
+ */
445
+ boot?: (context: CapabilityComposeContext) => void;
395
446
  /** Mounts a Hono sub-router. */
396
447
  routes?: (app: Hono<PithyHonoEnv>) => void;
397
448
  /** Composable middleware (e.g. turnstile(), requireAuth()). */
@@ -1 +1 @@
1
- {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../../src/capability/capability.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../../src/capability/capability.ts"],"names":[],"mappings":"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"}
@@ -118,6 +118,22 @@ export declare function renderConfigOptionLine(key: string, value: ConfigOptionV
118
118
  * cannot reach the throw, because every manifest is parsed before it is rendered.
119
119
  */
120
120
  export declare function renderConfigOptionComment(describe: string, indent: string): string;
121
+ /**
122
+ * The line a writer puts in `pithy.config.ts` for a **seam** — the option a capability takes that is a
123
+ * function, so no renderer can ever state its value.
124
+ *
125
+ * Shorthand (`resolveSubject,`) rather than `key: value`, because the two are the same identifier: the
126
+ * scaffolded module exports the name the factory takes, and a config that spelled it twice would invite
127
+ * an adopter to rename one half of it.
128
+ *
129
+ * **It takes the seam's key and nothing else.** That is the same closed-set argument
130
+ * {@link CONFIG_CONSTANTS} makes one function up, and it has to be made again here for a stronger
131
+ * reason: a constant is one identifier in an expression position, and a seam is an identifier *plus* an
132
+ * import statement plus a file written into the adopter's repository. A manifest states which seam, by a
133
+ * key this package enumerates; every character that reaches the adopter's TypeScript comes from
134
+ * {@link CONFIG_SEAMS}.
135
+ */
136
+ export declare function renderConfigSeamLine(seam: ConfigSeam, indent: string): string;
121
137
  /**
122
138
  * The one import line a capability's wiring is written as.
123
139
  *
@@ -199,11 +215,55 @@ export declare const ConfigConstant: z.ZodEnum<{
199
215
  publicOrigin: "publicOrigin";
200
216
  }>;
201
217
  export type ConfigConstant = z.infer<typeof ConfigConstant>;
218
+ /** One seam a capability takes: what `pithy add` writes for it, and what the config then references. */
219
+ export interface ConfigSeamSpec {
220
+ /** The identifier the scaffolded module exports, and the key the capability's factory takes for it. */
221
+ readonly binding: string;
222
+ /** The module `pithy add` writes, relative to the Worker's own directory. */
223
+ readonly module: string;
224
+ /** How that module is imported from the Worker's `pithy.config.ts`. */
225
+ readonly specifier: string;
226
+ /** The comment written above the seam's line, saying what the adopter still owes it. */
227
+ readonly describe: string;
228
+ }
229
+ /**
230
+ * The seams `pithy add` knows how to scaffold — a capability option whose value is **behavior**, named
231
+ * from a closed set exactly as {@link CONFIG_CONSTANTS} names an identifier.
232
+ *
233
+ * A missing *value* has always been scaffoldable: `pithy add secrets` writes an empty registry and the
234
+ * project still loads, because an empty registry is a valid empty state. A missing *behavior* was not,
235
+ * so `payments`' `billingSubject: "organization"` was refused outright — and its remedy routed through
236
+ * `--set billingSubject=user`, a value that is untrue for every project that wanted the other one (#500).
237
+ *
238
+ * What makes the behavior scaffoldable is that the scaffold is **not a stub that answers**. A resolver
239
+ * returning nothing composes cleanly and then denies every gate, which is indistinguishable from a
240
+ * customer who has not paid. The module written here is branded as unimplemented by the capability that
241
+ * owns it, and that capability refuses the Worker's entrypoint while the brand is still on it — so the
242
+ * adopter says what they mean, gets the file and the signature, and the project still refuses to boot
243
+ * until they have written the one thing only they can write.
244
+ *
245
+ * One entry today. Every string in it is this package's, because all four of them reach the adopter's
246
+ * repository unquoted: an identifier, a path, an import specifier, a comment.
247
+ */
248
+ export declare const CONFIG_SEAMS: {
249
+ readonly paymentsSubject: {
250
+ readonly binding: "resolveSubject";
251
+ readonly module: "src/billing/subject.ts";
252
+ readonly specifier: "./src/billing/subject";
253
+ readonly describe: "Which organization this caller is acting for. Scaffolded unimplemented — this Worker refuses to boot until src/billing/subject.ts answers it.";
254
+ };
255
+ };
256
+ /** Which scaffolded seam a choice needs, by key. */
257
+ export declare const ConfigSeam: z.ZodEnum<{
258
+ paymentsSubject: "paymentsSubject";
259
+ }>;
260
+ export type ConfigSeam = z.infer<typeof ConfigSeam>;
202
261
  export declare const ConfigOption: z.ZodObject<{
203
262
  key: z.ZodString;
204
263
  default: z.ZodOptional<z.ZodType<ConfigOptionValue, unknown, z.core.$ZodTypeInternals<ConfigOptionValue, unknown>>>;
205
264
  choices: z.ZodOptional<z.ZodArray<z.ZodString>>;
206
265
  choicesNeedingCode: z.ZodOptional<z.ZodPipe<z.ZodCustom<Record<string, string>, Record<string, string>>, z.ZodType<Record<string, string>, Record<string, string>, z.core.$ZodTypeInternals<Record<string, string>, Record<string, string>>>>>;
266
+ choicesNeedingSeam: z.ZodOptional<z.ZodPipe<z.ZodCustom<Record<string, "paymentsSubject">, Record<string, "paymentsSubject">>, z.ZodType<Record<string, "paymentsSubject">, Record<string, "paymentsSubject">, z.core.$ZodTypeInternals<Record<string, "paymentsSubject">, Record<string, "paymentsSubject">>>>>;
207
267
  constant: z.ZodOptional<z.ZodEnum<{
208
268
  publicOrigin: "publicOrigin";
209
269
  }>>;
@@ -236,6 +296,11 @@ export declare const CapabilityManifest: z.ZodObject<{
236
296
  job: z.ZodOptional<z.ZodString>;
237
297
  service: z.ZodOptional<z.ZodString>;
238
298
  remote: z.ZodOptional<z.ZodBoolean>;
299
+ scope: z.ZodOptional<z.ZodEnum<{
300
+ environment: "environment";
301
+ global: "global";
302
+ }>>;
303
+ resource: z.ZodOptional<z.ZodString>;
239
304
  }, z.core.$strip>>;
240
305
  peerCapabilities: z.ZodDefault<z.ZodArray<z.ZodString>>;
241
306
  optionalCapabilities: z.ZodDefault<z.ZodArray<z.ZodString>>;
@@ -289,6 +354,7 @@ export declare const CapabilityManifest: z.ZodObject<{
289
354
  default: z.ZodOptional<z.ZodType<ConfigOptionValue, unknown, z.core.$ZodTypeInternals<ConfigOptionValue, unknown>>>;
290
355
  choices: z.ZodOptional<z.ZodArray<z.ZodString>>;
291
356
  choicesNeedingCode: z.ZodOptional<z.ZodPipe<z.ZodCustom<Record<string, string>, Record<string, string>>, z.ZodType<Record<string, string>, Record<string, string>, z.core.$ZodTypeInternals<Record<string, string>, Record<string, string>>>>>;
357
+ choicesNeedingSeam: z.ZodOptional<z.ZodPipe<z.ZodCustom<Record<string, "paymentsSubject">, Record<string, "paymentsSubject">>, z.ZodType<Record<string, "paymentsSubject">, Record<string, "paymentsSubject">, z.core.$ZodTypeInternals<Record<string, "paymentsSubject">, Record<string, "paymentsSubject">>>>>;
292
358
  constant: z.ZodOptional<z.ZodEnum<{
293
359
  publicOrigin: "publicOrigin";
294
360
  }>>;
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/capability/manifest.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAgDxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,iBAAiB,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAAA;CAAE,CAAC;AAEvH,eAAO,MAAM,iBAAiB,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAUgD,CAAC;AA6D5G;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CASlE;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAE7C;;;;;;;;;;;GAWG;AACH;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAChC,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;CACnC;AAOD,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,iBAAiB,GAAG,iBAAiB,EAC5C,MAAM,EAAE,MAAM,GACb,MAAM,CAaR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CASlF;AAwDD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAU9E;AAED,8EAA8E;AAC9E,MAAM,WAAW,sBAAsB;IACrC,+FAA+F;IAC/F,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,EAC3C,IAAI,EACJ,MAAM,EACN,WAAgB,EAChB,aAAoB,GACrB,EAAE,sBAAsB,GAAG,MAAM,CAKjC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB;aAAK,YAAY,EAAE,eAAe;CAAW,CAAC;AAE3E,8DAA8D;AAC9D,eAAO,MAAM,cAAc;;EAEuF,CAAC;AACnH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,eAAO,MAAM,YAAY;;;;;;;;;iBA4EoE,CAAC;AAC9F,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAExD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiE0D,CAAC;AAC1F,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/capability/manifest.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
- import { BindingSpec } from "./bindings.js";
4
3
  import { ValidationError } from "../error/pithyError.js";
4
+ import { BindingSpec } from "./bindings.js";
5
5
  import { manifestRecord } from "./vanishingKey.js";
6
6
  import { DevSecret } from "./devSecret.js";
7
7
  import { NAMESPACE_PATTERN } from "../migrations/registry.js";
@@ -175,6 +175,24 @@ function renderConfigOptionComment(describe, indent) {
175
175
  return `${indent}// ${describe}`;
176
176
  }
177
177
  /**
178
+ * The line a writer puts in `pithy.config.ts` for a **seam** — the option a capability takes that is a
179
+ * function, so no renderer can ever state its value.
180
+ *
181
+ * Shorthand (`resolveSubject,`) rather than `key: value`, because the two are the same identifier: the
182
+ * scaffolded module exports the name the factory takes, and a config that spelled it twice would invite
183
+ * an adopter to rename one half of it.
184
+ *
185
+ * **It takes the seam's key and nothing else.** That is the same closed-set argument
186
+ * {@link CONFIG_CONSTANTS} makes one function up, and it has to be made again here for a stronger
187
+ * reason: a constant is one identifier in an expression position, and a seam is an identifier *plus* an
188
+ * import statement plus a file written into the adopter's repository. A manifest states which seam, by a
189
+ * key this package enumerates; every character that reaches the adopter's TypeScript comes from
190
+ * {@link CONFIG_SEAMS}.
191
+ */
192
+ function renderConfigSeamLine(seam, indent) {
193
+ return `${indent}${CONFIG_SEAMS[seam].binding},`;
194
+ }
195
+ /**
178
196
  * A capability's own name, as generated source carries it.
179
197
  *
180
198
  * The same shape a config option's key is held to, and for the same reason: it is written **bare**, and
@@ -299,11 +317,39 @@ function renderCapabilityRegistration({ name, indent, optionLines = [], trailing
299
317
  const CONFIG_CONSTANTS = { publicOrigin: "PUBLIC_ORIGIN" };
300
318
  /** Which scaffolded constant an option's value is, by key. */
301
319
  const ConfigConstant = z.enum(Object.keys(CONFIG_CONSTANTS)).describe("A constant the scaffolded pithy.config.ts defines, named from a closed set rather than spelled out.");
320
+ /**
321
+ * The seams `pithy add` knows how to scaffold — a capability option whose value is **behavior**, named
322
+ * from a closed set exactly as {@link CONFIG_CONSTANTS} names an identifier.
323
+ *
324
+ * A missing *value* has always been scaffoldable: `pithy add secrets` writes an empty registry and the
325
+ * project still loads, because an empty registry is a valid empty state. A missing *behavior* was not,
326
+ * so `payments`' `billingSubject: "organization"` was refused outright — and its remedy routed through
327
+ * `--set billingSubject=user`, a value that is untrue for every project that wanted the other one (#500).
328
+ *
329
+ * What makes the behavior scaffoldable is that the scaffold is **not a stub that answers**. A resolver
330
+ * returning nothing composes cleanly and then denies every gate, which is indistinguishable from a
331
+ * customer who has not paid. The module written here is branded as unimplemented by the capability that
332
+ * owns it, and that capability refuses the Worker's entrypoint while the brand is still on it — so the
333
+ * adopter says what they mean, gets the file and the signature, and the project still refuses to boot
334
+ * until they have written the one thing only they can write.
335
+ *
336
+ * One entry today. Every string in it is this package's, because all four of them reach the adopter's
337
+ * repository unquoted: an identifier, a path, an import specifier, a comment.
338
+ */
339
+ const CONFIG_SEAMS = { paymentsSubject: {
340
+ binding: "resolveSubject",
341
+ module: "src/billing/subject.ts",
342
+ specifier: "./src/billing/subject",
343
+ describe: "Which organization this caller is acting for. Scaffolded unimplemented — this Worker refuses to boot until src/billing/subject.ts answers it."
344
+ } };
345
+ /** Which scaffolded seam a choice needs, by key. */
346
+ const ConfigSeam = z.enum(Object.keys(CONFIG_SEAMS)).describe("A seam pithy add knows how to scaffold, named from a closed set rather than described.");
302
347
  const ConfigOption = z.object({
303
348
  key: z.string().regex(BARE_KEY, { error: (issue) => `A config option key must be a bare identifier, and ${JSON.stringify(issue.input)} is not — it is written bare into pithy.config.ts.` }).describe("Option name passed to the capability factory (e.g. \"basePath\"); a bare identifier."),
304
349
  default: ConfigOptionValue.optional().describe("The value rendered into pithy.config.ts when no override is given — and **its absence is what makes an option required**. There is no flag beside it saying so: an option that states a default has an answer the kit is willing to pick, and an option that states none has one only the adopter can. A required option is settled before a byte is written — a prompt asks it with nothing to accept by pressing enter, `--set key=value` answers it non-interactively, and a run carrying neither is refused naming the flag. Nothing is guessed, because a decision worth refusing over is one that is expensive to reverse: payments' `billingSubject` decides whether an entitlement is held by a person or a company, and it lands in a column and a UNIQUE index."),
305
350
  choices: z.array(PrintableString).min(1).optional().describe("The values this option accepts, when they are a closed set. Three things follow from stating them, and none of them can be had without: the prompt is a select rather than free text, `--set` refuses a value outside them instead of writing it into the config, and a refusal can name what is legal — which is the whole of what a caller needs in order to answer a required option. Held to the same printable-string rule as a default, because a choice becomes the value written into the adopter's TypeScript."),
306
351
  choicesNeedingCode: manifestRecord(z.record(PrintableString, z.string().min(1))).optional().describe("Choices `pithy add` must refuse, each mapped to the sentence telling the adopter what to do instead — a value whose composition needs a seam only they can write. `pithy add` renders JSON into `pithy.config.ts`; it cannot render a function, so a choice whose validity depends on one is a choice it can write and the kit will then refuse to load. `payments`' `billingSubject: \"organization\"` is the one: it requires a `resolveSubject` saying which organization a caller acts for, deliberately has no default because a capability that guessed would key a company's plan to whoever signed in first, and so a config carrying the choice without the seam is refused at assembly — bricking every later command in the project, since they all begin by loading the config (#483). Refusing the choice up front costs the adopter one hand-edit; writing it costs them the project."),
352
+ choicesNeedingSeam: manifestRecord(z.record(PrintableString, ConfigSeam)).optional().describe("Choices `pithy add` writes **together with the code they need** — the other half of `choicesNeedingCode`, for a choice whose missing half the kit can scaffold. Each names a seam from `CONFIG_SEAMS`; `pithy add` writes that module into the Worker, imports it, and passes it to the capability's factory beside the choice. `payments`' `billingSubject: \"organization\"` is the one: reaching it used to mean passing `--set billingSubject=user`, a value that is wrong for the project, and then hand-editing both halves (#500). The scaffolded module is deliberately **not** a working stub — it is branded unimplemented, and the capability refuses the Worker's entrypoint while the brand is on it, because a resolver that answers nothing denies every gate and reads exactly like a customer who has not paid. A choice states this or `choicesNeedingCode`, never both: one is a refusal and the other is a scaffold."),
307
353
  constant: ConfigConstant.optional().describe("A constant the scaffolded pithy.config.ts defines, rendered *unquoted* in place of `default` when the target config declares it. The one that exists is `publicOrigin` — `PUBLIC_ORIGIN`, this Worker's address for the environment it composes in. An option whose value is an origin must name it rather than state a URL, because a URL written down is production's URL written into staging: it is what mailed staging's testers magic links into production and unsubscribed them there (#256). `default` is still required *for such an option* and is what a config with no such constant gets, so an older project is never handed an identifier it does not define — the one place the absent-default rule does not reach, and it is checked rather than trusted."),
308
354
  describe: z.string().min(1).refine(isPrintableComment, { error: (issue) => `A config option's rationale must be one line with no trailing whitespace, and ${JSON.stringify(issue.input)} is not — it is written into pithy.config.ts as a // comment.` }).describe("Rationale rendered as the comment above this option in pithy.config.ts; one line.")
309
355
  }).check((ctx) => {
@@ -320,6 +366,20 @@ const ConfigOption = z.object({
320
366
  path: ["choicesNeedingCode", choice],
321
367
  message: `A choice needing code must be one this option offers, and ${JSON.stringify(choice)} is not — ${option.key} offers ${JSON.stringify(option.choices ?? [])}.`
322
368
  });
369
+ for (const choice of Object.keys(option.choicesNeedingSeam ?? {})) {
370
+ if (!option.choices?.includes(choice)) ctx.issues.push({
371
+ code: "custom",
372
+ input: choice,
373
+ path: ["choicesNeedingSeam", choice],
374
+ message: `A choice needing a seam must be one this option offers, and ${JSON.stringify(choice)} is not — ${option.key} offers ${JSON.stringify(option.choices ?? [])}.`
375
+ });
376
+ if (option.choicesNeedingCode?.[choice] !== void 0) ctx.issues.push({
377
+ code: "custom",
378
+ input: choice,
379
+ path: ["choicesNeedingSeam", choice],
380
+ message: `A choice is refused or scaffolded, never both, and ${option.key} states ${JSON.stringify(choice)} in choicesNeedingCode and choicesNeedingSeam alike.`
381
+ });
382
+ }
323
383
  if (option.constant !== void 0 && option.default === void 0) ctx.issues.push({
324
384
  code: "custom",
325
385
  input: option.constant,
@@ -355,4 +415,4 @@ const CapabilityManifest = z.object({
355
415
  whenToEnable: z.string().optional().describe("Self-documenting rationale the CLI surfaces when offering this capability.")
356
416
  }).describe("Declarative, CLI-facing description of a capability (pithy.manifest.json).");
357
417
  //#endregion
358
- export { CONFIG_CONSTANTS, CONFIG_LINE_WIDTH, CONFIG_OPTION_INDENT, CapabilityManifest, ConfigConstant, ConfigOption, ConfigOptionValue, renderCapabilityImport, renderCapabilityRegistration, renderConfigOptionComment, renderConfigOptionLine, renderConfigValue };
418
+ export { CONFIG_CONSTANTS, CONFIG_LINE_WIDTH, CONFIG_OPTION_INDENT, CONFIG_SEAMS, CapabilityManifest, ConfigConstant, ConfigOption, ConfigOptionValue, ConfigSeam, renderCapabilityImport, renderCapabilityRegistration, renderConfigOptionComment, renderConfigOptionLine, renderConfigSeamLine, renderConfigValue };
@@ -1,7 +1,7 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
- import { isProvisionedBinding } from "./bindings.js";
4
3
  import { InternalError } from "../error/pithyError.js";
4
+ import { isProvisionedBinding } from "./bindings.js";
5
5
  //#region src/capability/validateBindings.ts
6
6
  /** How a missing binding is named in both halves of the error: `kv:SESSIONS`. */
7
7
  function label(binding) {
@@ -1,8 +1,8 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
+ import "../../naming/environment.js";
3
4
  import "../../worker/identity.js";
4
5
  import { CONTROL_PLANE_HEADER, CONTROL_PLANE_VERSION_CREATED_HEADER, CONTROL_PLANE_VERSION_HEADER } from "../wire.js";
5
- import "../../naming/environment.js";
6
6
  //#region src/controlPlane/http/cors.ts
7
7
  /**
8
8
  * CORS for the control-plane surface — the one thing standing between a browser and a Worker that is
@@ -47,7 +47,8 @@ type BackendEnv<Caps extends readonly Capability[]> = {
47
47
  * each capability's middleware; and mounts the capability (then app) routes. On every request
48
48
  * `c.var.db` is the typed database registry — one `Kysely` per named database (`c.var.db.app`) —
49
49
  * and `c.var.kv` the typed namespace registry — one `TypedKv` per store (`c.var.kv.cms.pages`).
50
- * `PithyError`s become their declared HTTP status via {@link pithyErrorHandler}.
50
+ * `PithyError`s become their declared HTTP status via {@link loggingErrorHandler}, which also writes
51
+ * each fault to the request logger with its `action` and `detail` — the fields the wire body strips.
51
52
  *
52
53
  * Binding validation runs **once on the first request**, not at module load: in Workers `env` is
53
54
  * per-request, so there is no env to check until a request arrives. The result is memoized.
@@ -1 +1 @@
1
- {"version":3,"file":"createBackend.d.ts","sourceRoot":"","sources":["../src/createBackend.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,KAAK,EACV,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EAEpB,SAAS,EACV,MAAM,yBAAyB,CAAC;AAKjC,OAAO,EAAqC,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAMtF,OAAO,EAA8B,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAK9C,OAAO,EAA2B,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGvF,oGAAoG;AACpG,MAAM,WAAW,oBAAoB,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,EAAE,GAAG,SAAS,UAAU;IAC9F,2EAA2E;IAC3E,YAAY,EAAE,IAAI,CAAC;IACnB;;;OAGG;IACH,GAAG,CAAC,EAAE,GAAG,CAAC;IACV;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,iHAAiH;AACjH,KAAK,UAAU,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,IAAI;IACpD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,GAAG,IAAI,GAAG,WAAW,CAAC,GAAG;QACtD,EAAE,EAAE,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;QACtC,EAAE,EAAE,UAAU,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;QACzC,SAAS,EAAE,kBAAkB,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC;KAC3D,CAAC;CACH,CAAC;AAuCF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAC3B,KAAK,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,EACxC,KAAK,CAAC,GAAG,SAAS,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EACrF,OAAO,EAAE,oBAAoB,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAuKrF"}
1
+ {"version":3,"file":"createBackend.d.ts","sourceRoot":"","sources":["../src/createBackend.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,KAAK,EACV,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EAEpB,SAAS,EACV,MAAM,yBAAyB,CAAC;AAKjC,OAAO,EAAqC,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKtF,OAAO,EAA8B,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAK9C,OAAO,EAA2B,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGvF,oGAAoG;AACpG,MAAM,WAAW,oBAAoB,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,EAAE,GAAG,SAAS,UAAU;IAC9F,2EAA2E;IAC3E,YAAY,EAAE,IAAI,CAAC;IACnB;;;OAGG;IACH,GAAG,CAAC,EAAE,GAAG,CAAC;IACV;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,iHAAiH;AACjH,KAAK,UAAU,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,IAAI;IACpD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,GAAG,IAAI,GAAG,WAAW,CAAC,GAAG;QACtD,EAAE,EAAE,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;QACtC,EAAE,EAAE,UAAU,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;QACzC,SAAS,EAAE,kBAAkB,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC;KAC3D,CAAC;CACH,CAAC;AAuCF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAC3B,KAAK,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,EACxC,KAAK,CAAC,GAAG,SAAS,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EACrF,OAAO,EAAE,oBAAoB,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CA0KrF"}
@@ -1,8 +1,8 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
3
  import { noopEmit } from "./audit/recorder.js";
4
- import { BindingSpec } from "./capability/bindings.js";
5
4
  import { ValidationError } from "./error/pithyError.js";
5
+ import { BindingSpec } from "./capability/bindings.js";
6
6
  import { recordComposition } from "./capability/composition.js";
7
7
  import { validateBindings } from "./capability/validateBindings.js";
8
8
  import { workerVersion } from "./worker/identity.js";
@@ -10,11 +10,11 @@ import { isControlPlaneCapability } from "./controlPlane/capability.js";
10
10
  import { allowedOriginSet, corsSurface, registerControlPlaneCors } from "./controlPlane/http/cors.js";
11
11
  import { buildDbRegistry, composeDatabases } from "./data/databases.js";
12
12
  import { noEntitlementProvider } from "./entitlement/entitlement.js";
13
- import { pithyErrorHandler } from "./error/http.js";
14
13
  import { bakedTranslator } from "./i18n/translator.js";
15
14
  import { catalogFor, composeMessages } from "./i18n/registry.js";
16
15
  import { buildKvRegistry, composeKv } from "./kv/namespaces.js";
17
16
  import { bindRequestContext, createWorkerLogger } from "./logger/worker.js";
17
+ import { loggingErrorHandler } from "./logger/errorHandler.js";
18
18
  import { HEALTH_PATH } from "./worker/health.js";
19
19
  import { registeredWorkflowBinding } from "./workflow/bindings.js";
20
20
  import { buildWorkflowDispatcher } from "./workflow/dispatch.js";
@@ -63,7 +63,8 @@ function envNameOf(env, fallback) {
63
63
  * each capability's middleware; and mounts the capability (then app) routes. On every request
64
64
  * `c.var.db` is the typed database registry — one `Kysely` per named database (`c.var.db.app`) —
65
65
  * and `c.var.kv` the typed namespace registry — one `TypedKv` per store (`c.var.kv.cms.pages`).
66
- * `PithyError`s become their declared HTTP status via {@link pithyErrorHandler}.
66
+ * `PithyError`s become their declared HTTP status via {@link loggingErrorHandler}, which also writes
67
+ * each fault to the request logger with its `action` and `detail` — the fields the wire body strips.
67
68
  *
68
69
  * Binding validation runs **once on the first request**, not at module load: in Workers `env` is
69
70
  * per-request, so there is no env to check until a request arrives. The result is memoized.
@@ -98,7 +99,7 @@ function createBackend(options) {
98
99
  ...Object.values(workflows).map((entry) => BindingSpec.parse(registeredWorkflowBinding(entry)))
99
100
  ]);
100
101
  const app = new Hono();
101
- app.onError(pithyErrorHandler);
102
+ app.onError(loggingErrorHandler);
102
103
  const baseLogger = options.logger ?? createWorkerLogger();
103
104
  const controlPlane = all.find(isControlPlaneCapability);
104
105
  if (controlPlane) {
@@ -1 +1 @@
1
- {"version":3,"file":"createEntrypoint.d.ts","sourceRoot":"","sources":["../src/createEntrypoint.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAC3F,OAAO,KAAK,EAAE,UAAU,EAA0B,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,KAAK,oBAAoB,EAAiB,MAAM,iBAAiB,CAAC;AAI3E;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,gBAAgB,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/G;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,uBAAuB,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjH;;;;;;;;;;;;;;;;;;;OAmBG;IACH,SAAS,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzG;AAkBD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,EACxC,KAAK,CAAC,GAAG,SAAS,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EACrF,OAAO,EAAE,oBAAoB,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,eAAe,CA+C3D"}
1
+ {"version":3,"file":"createEntrypoint.d.ts","sourceRoot":"","sources":["../src/createEntrypoint.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAC3F,OAAO,KAAK,EAAE,UAAU,EAA0B,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,KAAK,oBAAoB,EAAiB,MAAM,iBAAiB,CAAC;AAI3E;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,gBAAgB,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/G;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,uBAAuB,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjH;;;;;;;;;;;;;;;;;;;OAmBG;IACH,SAAS,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzG;AAkBD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,CAAC,IAAI,SAAS,SAAS,UAAU,EAAE,EACxC,KAAK,CAAC,GAAG,SAAS,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EACrF,OAAO,EAAE,oBAAoB,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,eAAe,CAoD3D"}
@@ -28,6 +28,7 @@ function createEntrypoint(options) {
28
28
  const app = createBackend(options);
29
29
  const all = options.app ? [...options.capabilities, options.app] : [...options.capabilities];
30
30
  const handlers = all.flatMap((cap) => cap.email ? [cap.email] : []);
31
+ for (const cap of all) cap.boot?.({ capabilities: all });
31
32
  const registry = composeWorkflows(all);
32
33
  const scheduled = scheduledWorkflows(registry);
33
34
  const entrypoint = { fetch: (request, env, ctx) => app.fetch(request, env, ctx) };
@@ -2,6 +2,7 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  import type { Context } from "hono";
4
4
  import { z } from "zod";
5
+ import { PithyError } from "./pithyError";
5
6
  /**
6
7
  * The HTTP surface of an error, as a real codec. `encode` (server emits) maps an in-memory
7
8
  * `ErrorPayload` down to the public wire shape by calling {@link clientError} — **the security
@@ -1508,11 +1509,32 @@ export declare const HttpError: z.ZodCodec<z.ZodUnion<readonly [z.ZodDiscriminat
1508
1509
  status: z.ZodInt;
1509
1510
  }, z.core.$strip>]>>;
1510
1511
  /**
1511
- * Hono `onError` handler. Register once on the root app (`app.onError(pithyErrorHandler)`): any
1512
- * `PithyError` becomes `{ error: <public payload> }` at its declared status; a Hono `HTTPException`
1513
- * 400 becomes `validation/invalid_input`; any other throw is wrapped as a `core/internal` 500
1514
- * carrying the original as `cause` (kept internal) and a generic public message — mirroring the
1515
- * CLI's "unexpected crash" path.
1512
+ * Whatever was thrown, as the `PithyError` the response will be rendered from.
1513
+ *
1514
+ * A `PithyError` is itself; a Hono `HTTPException` 400 becomes `validation/invalid_input`; anything
1515
+ * else is wrapped as a `core/internal` 500 carrying the original as `cause` (kept internal) and a
1516
+ * generic public message — mirroring the CLI's "unexpected crash" path.
1517
+ *
1518
+ * Split out from {@link pithyErrorHandler} so a caller that wants to **read** the fault before it is
1519
+ * encoded — the logging handler in `logger/errorHandler.ts` — works from the same object the response
1520
+ * is built from, rather than translating a second time and logging a different instance of it. The
1521
+ * split is what keeps this module free of the logger: the translation is exported, the log is written
1522
+ * on the other side of the boundary. See `logger/boundary.test.ts`.
1523
+ */
1524
+ export declare function toPithyError(err: Error): PithyError;
1525
+ /** Render an already-translated fault as its HTTP response — the client half, and only that. */
1526
+ export declare function renderPithyError(pithy: PithyError, c: Context): Response;
1527
+ /**
1528
+ * Hono `onError` handler — the **encoder**, with no log of its own.
1529
+ *
1530
+ * Any `PithyError` becomes `{ error: <public payload> }` at its declared status; a Hono
1531
+ * `HTTPException` 400 becomes `validation/invalid_input`; any other throw is wrapped as a
1532
+ * `core/internal` 500.
1533
+ *
1534
+ * **Prefer `loggingErrorHandler` from `logger/errorHandler.ts`** — `createBackend` registers that one,
1535
+ * and it is what makes a misconfiguration's `action` reach an operator instead of dying at the wire
1536
+ * (#521). This one stays exported for an app assembled without the logger seam, and it stays here,
1537
+ * logger-free, because this module is on the client side of the logger boundary.
1516
1538
  */
1517
1539
  export declare function pithyErrorHandler(err: Error, c: Context): Response;
1518
1540
  //# sourceMappingURL=http.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/error/http.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAGpC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBA8BpB,CAAC;AAeH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,GAAG,QAAQ,CAUlE"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/error/http.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAGpC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAA4B,UAAU,EAAmB,MAAM,cAAc,CAAC;AAErF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBA8BpB,CAAC;AAeH;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,KAAK,GAAG,UAAU,CAInD;AAED,gGAAgG;AAChG,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,GAAG,QAAQ,CAKxE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,GAAG,QAAQ,CAElE"}