@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.
- package/dist/http/error_schemas.d.ts +16 -5
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +18 -5
- package/dist/testing/surface_invariants.d.ts +13 -5
- package/dist/testing/surface_invariants.d.ts.map +1 -1
- package/dist/testing/surface_invariants.js +119 -43
- package/package.json +1 -1
|
@@ -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
|
|
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
|
-
* `
|
|
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.
|
|
141
|
-
|
|
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
|
|
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
|
-
* `
|
|
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.
|
|
148
|
-
|
|
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).
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
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":"AAAA,OAAO,qBAAqB,CAAC;AAuB7B,OAAO,KAAK,EAAC,UAAU,EAAuB,MAAM,oBAAoB,CAAC;AAczE;;GAEG;AACH,eAAO,MAAM,mCAAmC,GAAI,SAAS,UAAU,KAAG,IAQzE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,8BAA8B,GAAI,SAAS,UAAU,KAAG,IASpE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,+BAA+B,GAAI,SAAS,UAAU,KAAG,IAQrE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gCAAgC,GAAI,SAAS,UAAU,KAAG,IAQtE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,+BAA+B,GAAI,SAAS,UAAU,KAAG,IAQrE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,2BAA2B,GAAI,SAAS,UAAU,KAAG,IAIjE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,GAAI,SAAS,UAAU,KAAG,IAOhE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mCAAmC,GAAI,SAAS,UAAU,KAAG,IAezE,CAAC;AAEF
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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).
|
|
133
|
-
*
|
|
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
|
|
136
|
-
*
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
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
|
|
244
|
+
return [];
|
|
203
245
|
if (typeof error_prop.const === 'string')
|
|
204
|
-
return error_prop.const;
|
|
205
|
-
return
|
|
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;
|