@fuzdev/fuz_app 0.56.0 → 0.57.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.
@@ -132,17 +132,28 @@ export declare const ApiError: z.ZodObject<{
132
132
  }, z.core.$loose>;
133
133
  export type ApiError = z.infer<typeof ApiError>;
134
134
  /**
135
- * Input validation error — returned when the request body fails Zod parsing.
135
+ * Input validation error — returned when params / query / body fails Zod
136
+ * parsing, or when the request body is not valid JSON.
136
137
  *
137
- * `issues` contains the Zod validation issues for diagnostic display.
138
+ * `error` is one of the four validation codes the framework emits.
139
+ * `issues` carries Zod's validation issues for diagnostic display on the
140
+ * three schema-failure cases (`invalid_request_body`,
141
+ * `invalid_route_params`, `invalid_query_params`). The `invalid_json_body`
142
+ * case (request body parse failure or non-object root) emits no `issues`,
143
+ * so the field is optional.
138
144
  */
139
145
  export declare const ValidationError: z.ZodObject<{
140
- error: z.ZodString;
141
- issues: z.ZodArray<z.ZodObject<{
146
+ error: z.ZodEnum<{
147
+ invalid_request_body: "invalid_request_body";
148
+ invalid_json_body: "invalid_json_body";
149
+ invalid_route_params: "invalid_route_params";
150
+ invalid_query_params: "invalid_query_params";
151
+ }>;
152
+ issues: z.ZodOptional<z.ZodArray<z.ZodObject<{
142
153
  code: z.ZodString;
143
154
  message: z.ZodString;
144
155
  path: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
145
- }, z.core.$loose>>;
156
+ }, z.core.$loose>>>;
146
157
  }, z.core.$loose>;
147
158
  export type ValidationError = z.infer<typeof ValidationError>;
148
159
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"error_schemas.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/error_schemas.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"error_schemas.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/error_schemas.ts"],"names":[],"mappings":"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"}
@@ -139,17 +139,30 @@ export const ERROR_DATABASE_CONNECTION_FAILED = 'database_connection_failed';
139
139
  /** Base API error — all JSON error responses have at least `{error: string}`. */
140
140
  export const ApiError = z.looseObject({ error: z.string() });
141
141
  /**
142
- * Input validation error — returned when the request body fails Zod parsing.
142
+ * Input validation error — returned when params / query / body fails Zod
143
+ * parsing, or when the request body is not valid JSON.
143
144
  *
144
- * `issues` contains the Zod validation issues for diagnostic display.
145
+ * `error` is one of the four validation codes the framework emits.
146
+ * `issues` carries Zod's validation issues for diagnostic display on the
147
+ * three schema-failure cases (`invalid_request_body`,
148
+ * `invalid_route_params`, `invalid_query_params`). The `invalid_json_body`
149
+ * case (request body parse failure or non-object root) emits no `issues`,
150
+ * so the field is optional.
145
151
  */
146
152
  export const ValidationError = z.looseObject({
147
- error: z.string(),
148
- issues: z.array(z.looseObject({
153
+ error: z.enum([
154
+ ERROR_INVALID_REQUEST_BODY,
155
+ ERROR_INVALID_JSON_BODY,
156
+ ERROR_INVALID_ROUTE_PARAMS,
157
+ ERROR_INVALID_QUERY_PARAMS,
158
+ ]),
159
+ issues: z
160
+ .array(z.looseObject({
149
161
  code: z.string(),
150
162
  message: z.string(),
151
163
  path: z.array(z.union([z.string(), z.number()])),
152
- })),
164
+ }))
165
+ .optional(),
153
166
  });
154
167
  /**
155
168
  * Permission error — returned by `require_role()` and the dispatcher's
@@ -37,6 +37,10 @@ export declare const assert_middleware_errors_propagated: (surface: AppSurface)
37
37
  * Every route's declared error schemas must have an `error` field at the top level
38
38
  * (conforming to the `ApiError` base shape `{error: string}`).
39
39
  *
40
+ * Walks union branches (`anyOf` from `z.union`, `oneOf` from
41
+ * `z.discriminatedUnion`) so every emit shape inside a merged 400 / 404
42
+ * is checked, not just the top-level wrapper.
43
+ *
40
44
  * Catches typos in error schema definitions and ensures consumers can always
41
45
  * read `.error` from error responses.
42
46
  */
@@ -46,11 +50,15 @@ export declare const assert_error_schemas_structurally_valid: (surface: AppSurfa
46
50
  * across routes.
47
51
  *
48
52
  * Extracts `const` values from error schema `error` properties (which correspond to
49
- * `z.literal()` in the Zod source). Flags when the same literal appears at different
50
- * status codes — e.g., `ERROR_INVALID_CREDENTIALS` at both 401 and 403 would be a bug.
51
- *
52
- * Only checks schemas with `const` values (literal schemas). Generic `z.string()`
53
- * schemas (which produce `{type: 'string'}` in JSON Schema) are ignored.
53
+ * `z.literal()` in the Zod source). Walks union branches (`anyOf` from `z.union`,
54
+ * `oneOf` from `z.discriminatedUnion`) so literal codes nested inside merged unions
55
+ * (e.g. validation 400 + actor-resolution 400) are still tracked. Flags when the
56
+ * same literal appears at different status codes — e.g., `ERROR_INVALID_CREDENTIALS`
57
+ * at both 401 and 403 would be a bug.
58
+ *
59
+ * Only checks `const` values (literal schemas). Generic `z.string()` schemas
60
+ * (which produce `{type: 'string'}`) and `z.enum()` schemas are ignored — the
61
+ * literal-only narrow keeps the check unambiguous.
54
62
  */
55
63
  export declare const assert_error_code_status_consistency: (surface: AppSurface) => void;
56
64
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"surface_invariants.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/surface_invariants.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"surface_invariants.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/surface_invariants.ts"],"names":[],"mappings":"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"}
@@ -105,6 +105,10 @@ export const assert_middleware_errors_propagated = (surface) => {
105
105
  * Every route's declared error schemas must have an `error` field at the top level
106
106
  * (conforming to the `ApiError` base shape `{error: string}`).
107
107
  *
108
+ * Walks union branches (`anyOf` from `z.union`, `oneOf` from
109
+ * `z.discriminatedUnion`) so every emit shape inside a merged 400 / 404
110
+ * is checked, not just the top-level wrapper.
111
+ *
108
112
  * Catches typos in error schema definitions and ensures consumers can always
109
113
  * read `.error` from error responses.
110
114
  */
@@ -113,15 +117,24 @@ export const assert_error_schemas_structurally_valid = (surface) => {
113
117
  if (!route.error_schemas)
114
118
  continue;
115
119
  for (const [status, schema] of Object.entries(route.error_schemas)) {
116
- if (typeof schema !== 'object' || schema === null)
117
- continue;
118
- const s = schema;
119
- // JSON Schema must have properties.error or be an object type
120
- if (s.type === 'object' && s.properties && typeof s.properties === 'object') {
121
- const props = s.properties;
122
- assert.ok('error' in props, `${format_route_key(route)} error schema for status ${status} missing 'error' property`);
123
- }
120
+ assert_branch_has_error_property(schema, format_route_key(route), status);
121
+ }
122
+ }
123
+ };
124
+ const assert_branch_has_error_property = (schema, route_key, status) => {
125
+ const branches = get_union_branches(schema);
126
+ if (branches) {
127
+ for (const branch of branches) {
128
+ assert_branch_has_error_property(branch, route_key, status);
124
129
  }
130
+ return;
131
+ }
132
+ if (typeof schema !== 'object' || schema === null)
133
+ return;
134
+ const s = schema;
135
+ if (s.type === 'object' && s.properties && typeof s.properties === 'object') {
136
+ const props = s.properties;
137
+ assert.ok('error' in props, `${route_key} error schema for status ${status} missing 'error' property`);
125
138
  }
126
139
  };
127
140
  /**
@@ -129,44 +142,42 @@ export const assert_error_schemas_structurally_valid = (surface) => {
129
142
  * across routes.
130
143
  *
131
144
  * Extracts `const` values from error schema `error` properties (which correspond to
132
- * `z.literal()` in the Zod source). Flags when the same literal appears at different
133
- * status codes — e.g., `ERROR_INVALID_CREDENTIALS` at both 401 and 403 would be a bug.
145
+ * `z.literal()` in the Zod source). Walks union branches (`anyOf` from `z.union`,
146
+ * `oneOf` from `z.discriminatedUnion`) so literal codes nested inside merged unions
147
+ * (e.g. validation 400 + actor-resolution 400) are still tracked. Flags when the
148
+ * same literal appears at different status codes — e.g., `ERROR_INVALID_CREDENTIALS`
149
+ * at both 401 and 403 would be a bug.
134
150
  *
135
- * Only checks schemas with `const` values (literal schemas). Generic `z.string()`
136
- * schemas (which produce `{type: 'string'}` in JSON Schema) are ignored.
151
+ * Only checks `const` values (literal schemas). Generic `z.string()` schemas
152
+ * (which produce `{type: 'string'}`) and `z.enum()` schemas are ignored — the
153
+ * literal-only narrow keeps the check unambiguous.
137
154
  */
138
155
  export const assert_error_code_status_consistency = (surface) => {
139
156
  // Map from error code literal → Set of status codes where it appears
140
157
  const code_to_statuses = new Map();
141
- for (const route of surface.routes) {
142
- if (!route.error_schemas)
143
- continue;
144
- for (const [status, schema] of Object.entries(route.error_schemas)) {
145
- const error_const = extract_error_const(schema);
146
- if (error_const === null)
147
- continue;
148
- let statuses = code_to_statuses.get(error_const);
158
+ const record = (status, schema) => {
159
+ for (const code of extract_error_consts(schema)) {
160
+ let statuses = code_to_statuses.get(code);
149
161
  if (!statuses) {
150
162
  statuses = new Set();
151
- code_to_statuses.set(error_const, statuses);
163
+ code_to_statuses.set(code, statuses);
152
164
  }
153
165
  statuses.add(status);
154
166
  }
167
+ };
168
+ for (const route of surface.routes) {
169
+ if (!route.error_schemas)
170
+ continue;
171
+ for (const [status, schema] of Object.entries(route.error_schemas)) {
172
+ record(status, schema);
173
+ }
155
174
  }
156
175
  // Also check middleware error schemas
157
176
  for (const mw of surface.middleware) {
158
177
  if (!mw.error_schemas)
159
178
  continue;
160
179
  for (const [status, schema] of Object.entries(mw.error_schemas)) {
161
- const error_const = extract_error_const(schema);
162
- if (error_const === null)
163
- continue;
164
- let statuses = code_to_statuses.get(error_const);
165
- if (!statuses) {
166
- statuses = new Set();
167
- code_to_statuses.set(error_const, statuses);
168
- }
169
- statuses.add(status);
180
+ record(status, schema);
170
181
  }
171
182
  }
172
183
  for (const [code, statuses] of code_to_statuses) {
@@ -191,31 +202,59 @@ const get_error_property = (schema) => {
191
202
  return props.error;
192
203
  };
193
204
  /**
194
- * Extract the `const` value from a JSON Schema error property, if present.
205
+ * Read the branch array off a JSON Schema union, if present.
206
+ *
207
+ * Zod 4 emits `anyOf` for `z.union(...)` and `oneOf` for
208
+ * `z.discriminatedUnion(...)` via `z.toJSONSchema`; both are union-shaped
209
+ * for tightness/code-extraction purposes. Nested unions are NOT flattened
210
+ * by `toJSONSchema`, so every caller must recurse through the returned
211
+ * branches. Returns the branch array or `null` for non-union schemas.
212
+ */
213
+ const get_union_branches = (schema) => {
214
+ if (typeof schema !== 'object' || schema === null)
215
+ return null;
216
+ const s = schema;
217
+ if (Array.isArray(s.anyOf))
218
+ return s.anyOf;
219
+ if (Array.isArray(s.oneOf))
220
+ return s.oneOf;
221
+ return null;
222
+ };
223
+ /**
224
+ * Extract every `const` value from a JSON Schema error property, walking
225
+ * union branches.
195
226
  *
196
227
  * Looks for `schema.properties.error.const` — the JSON Schema representation
197
- * of `z.literal('some_error_code')`.
228
+ * of `z.literal('some_error_code')` — and recurses into `anyOf` / `oneOf`
229
+ * branches so literals nested inside `z.union` or `z.discriminatedUnion`
230
+ * are still tracked. Returns an empty array for schemas with no literal
231
+ * codes (`z.enum`, `z.string`, non-object schemas).
198
232
  */
199
- const extract_error_const = (schema) => {
233
+ const extract_error_consts = (schema) => {
234
+ const branches = get_union_branches(schema);
235
+ if (branches) {
236
+ const codes = [];
237
+ for (const branch of branches) {
238
+ codes.push(...extract_error_consts(branch));
239
+ }
240
+ return codes;
241
+ }
200
242
  const error_prop = get_error_property(schema);
201
243
  if (!error_prop)
202
- return null;
244
+ return [];
203
245
  if (typeof error_prop.const === 'string')
204
- return error_prop.const;
205
- return null;
246
+ return [error_prop.const];
247
+ return [];
206
248
  };
207
249
  /**
208
250
  * Check if a JSON Schema error property uses specific error codes (`const` or `enum`),
209
251
  * not just generic `z.string()` (`{type: 'string'}`).
210
252
  *
211
- * Returns `true` for `z.literal()` (`{const: '...'}`) and `z.enum()` (`{enum: [...]}`).
253
+ * Returns `true` for `z.literal()` (`{const: '...'}`) and `z.enum()` (`{enum: [...]}`),
254
+ * and for union schemas where every branch is specific. Defers to
255
+ * `classify_error_specificity` so the union walk stays in one place.
212
256
  */
213
- const has_specific_error_schema = (schema) => {
214
- const error_prop = get_error_property(schema);
215
- if (!error_prop)
216
- return false;
217
- return typeof error_prop.const === 'string' || Array.isArray(error_prop.enum);
218
- };
257
+ const has_specific_error_schema = (schema) => classify_error_specificity(schema) !== 'generic';
219
258
  /**
220
259
  * Routes declaring 404 error schemas should use specific `z.literal()` or `z.enum()`
221
260
  * error codes, not generic `z.string()`.
@@ -245,8 +284,29 @@ export const assert_404_schemas_use_specific_errors = (surface) => {
245
284
  * - `'literal'` — `z.literal()` (`{const: '...'}`)
246
285
  * - `'enum'` — `z.enum()` (`{enum: [...]}`)
247
286
  * - `'generic'` — `z.string()` or unrecognized
287
+ *
288
+ * Walks union branches (`anyOf` from `z.union`, `oneOf` from
289
+ * `z.discriminatedUnion`) — `derive_error_schemas` emits `anyOf` when it
290
+ * merges multiple shapes at one status (e.g. validation 400 +
291
+ * actor-resolution 400), and a consumer that explicitly declares a
292
+ * discriminated-union error schema emits `oneOf`. Reports the **minimum**
293
+ * specificity across branches — a union's contract is only as tight as
294
+ * its loosest member.
248
295
  */
249
296
  const classify_error_specificity = (schema) => {
297
+ const branches = get_union_branches(schema);
298
+ if (branches) {
299
+ if (branches.length === 0)
300
+ return 'generic';
301
+ let min = 'literal';
302
+ for (const branch of branches) {
303
+ const branch_specificity = classify_error_specificity(branch);
304
+ if (SPECIFICITY_ORDER[branch_specificity] < SPECIFICITY_ORDER[min]) {
305
+ min = branch_specificity;
306
+ }
307
+ }
308
+ return min;
309
+ }
250
310
  const error_prop = get_error_property(schema);
251
311
  if (!error_prop)
252
312
  return 'generic';
@@ -260,8 +320,24 @@ const classify_error_specificity = (schema) => {
260
320
  * Extract error code values from a JSON Schema error property.
261
321
  *
262
322
  * Returns the literal value or enum array, or `null` for generic schemas.
323
+ *
324
+ * For union schemas (`anyOf` / `oneOf`), collects codes from every branch
325
+ * (deduped). If any branch is generic, returns `null` because the union
326
+ * admits arbitrary strings on that branch.
263
327
  */
264
328
  const extract_error_codes = (schema) => {
329
+ const branches = get_union_branches(schema);
330
+ if (branches) {
331
+ const codes = new Set();
332
+ for (const branch of branches) {
333
+ const branch_codes = extract_error_codes(branch);
334
+ if (branch_codes === null)
335
+ return null;
336
+ for (const code of branch_codes)
337
+ codes.add(code);
338
+ }
339
+ return [...codes];
340
+ }
265
341
  const error_prop = get_error_property(schema);
266
342
  if (!error_prop)
267
343
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_app",
3
- "version": "0.56.0",
3
+ "version": "0.57.0",
4
4
  "description": "fullstack app library",
5
5
  "glyph": "🗝",
6
6
  "logo": "logo.svg",