@codewithagents/api-errors 1.0.6 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/index.d.ts +133 -7
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +163 -181
  4. package/dist/index.js.map +1 -1
  5. package/dist/parsers/dispatch.d.ts +12 -0
  6. package/dist/parsers/dispatch.d.ts.map +1 -0
  7. package/dist/parsers/dispatch.js +116 -0
  8. package/dist/parsers/dispatch.js.map +1 -0
  9. package/dist/parsers/flat.d.ts +12 -0
  10. package/dist/parsers/flat.d.ts.map +1 -0
  11. package/dist/parsers/flat.js +31 -0
  12. package/dist/parsers/flat.js.map +1 -0
  13. package/dist/parsers/graphql-extensions.d.ts +18 -0
  14. package/dist/parsers/graphql-extensions.d.ts.map +1 -0
  15. package/dist/parsers/graphql-extensions.js +83 -0
  16. package/dist/parsers/graphql-extensions.js.map +1 -0
  17. package/dist/parsers/invalid-params.d.ts +7 -0
  18. package/dist/parsers/invalid-params.d.ts.map +1 -0
  19. package/dist/parsers/invalid-params.js +12 -0
  20. package/dist/parsers/invalid-params.js.map +1 -0
  21. package/dist/parsers/json-api.d.ts +14 -0
  22. package/dist/parsers/json-api.d.ts.map +1 -0
  23. package/dist/parsers/json-api.js +85 -0
  24. package/dist/parsers/json-api.js.map +1 -0
  25. package/dist/parsers/laravel-drf.d.ts +10 -0
  26. package/dist/parsers/laravel-drf.d.ts.map +1 -0
  27. package/dist/parsers/laravel-drf.js +46 -0
  28. package/dist/parsers/laravel-drf.js.map +1 -0
  29. package/dist/parsers/rfc7807.d.ts +7 -0
  30. package/dist/parsers/rfc7807.d.ts.map +1 -0
  31. package/dist/parsers/rfc7807.js +24 -0
  32. package/dist/parsers/rfc7807.js.map +1 -0
  33. package/dist/parsers/spring.d.ts +7 -0
  34. package/dist/parsers/spring.d.ts.map +1 -0
  35. package/dist/parsers/spring.js +24 -0
  36. package/dist/parsers/spring.js.map +1 -0
  37. package/dist/parsers/types.d.ts +44 -0
  38. package/dist/parsers/types.d.ts.map +1 -0
  39. package/dist/parsers/types.js +2 -0
  40. package/dist/parsers/types.js.map +1 -0
  41. package/dist/parsers/unwrap.d.ts +3 -0
  42. package/dist/parsers/unwrap.d.ts.map +1 -0
  43. package/dist/parsers/unwrap.js +29 -0
  44. package/dist/parsers/unwrap.js.map +1 -0
  45. package/dist/parsers/utils.d.ts +12 -0
  46. package/dist/parsers/utils.d.ts.map +1 -0
  47. package/dist/parsers/utils.js +65 -0
  48. package/dist/parsers/utils.js.map +1 -0
  49. package/dist/parsers/violations.d.ts +7 -0
  50. package/dist/parsers/violations.d.ts.map +1 -0
  51. package/dist/parsers/violations.js +12 -0
  52. package/dist/parsers/violations.js.map +1 -0
  53. package/dist/parsers/zod-flatten.d.ts +11 -0
  54. package/dist/parsers/zod-flatten.d.ts.map +1 -0
  55. package/dist/parsers/zod-flatten.js +37 -0
  56. package/dist/parsers/zod-flatten.js.map +1 -0
  57. package/package.json +4 -1
package/dist/index.d.ts CHANGED
@@ -1,9 +1,27 @@
1
+ export type { FieldError, ParsedErrors, ErrorFormat, CustomParser } from './parsers/types.js';
2
+ import type { FieldError, ErrorFormat, CustomParser } from './parsers/types.js';
1
3
  /**
2
- * Normalized representation of a single field-level error.
4
+ * Rich result returned by `extractErrors`.
3
5
  */
4
- export interface FieldError {
5
- field: string;
6
- message: string;
6
+ export interface ExtractResult {
7
+ /**
8
+ * Field-level errors extracted from the response body.
9
+ */
10
+ fieldErrors: FieldError[];
11
+ /**
12
+ * Non-field (global/form-level) error messages.
13
+ * These are messages that could not be attributed to a specific field,
14
+ * such as RFC 9457 `detail`, JSON:API errors without a source pointer,
15
+ * or violations/invalid-params entries without a field name.
16
+ */
17
+ formErrors: string[];
18
+ /**
19
+ * The format that was recognized.
20
+ * `null` when no supported format matched (both `fieldErrors` and `formErrors` are empty).
21
+ *
22
+ * Use this to distinguish "unrecognized shape" from "recognized but genuinely no errors".
23
+ */
24
+ format: ErrorFormat | null;
7
25
  }
8
26
  /**
9
27
  * Options for mapApiErrors and extractFieldErrors.
@@ -17,7 +35,7 @@ export interface MapApiErrorsOptions {
17
35
  /**
18
36
  * Optional transform applied to every field name before it is returned.
19
37
  * Useful for mapping backend camelCase field names to nested React Hook Form
20
- * paths, e.g. `"addressCity"` → `"address.city"`.
38
+ * paths, e.g. `"addressCity"` to `"address.city"`.
21
39
  */
22
40
  transformField?: (field: string) => string;
23
41
  /**
@@ -32,19 +50,68 @@ export interface MapApiErrorsOptions {
32
50
  * extractFieldErrors(err, { statusCodes: [422] })
33
51
  */
34
52
  statusCodes?: number[];
53
+ /**
54
+ * Optional message resolver / i18n hook.
55
+ * Called for every error message (both field errors and form errors) before
56
+ * the message is included in the result. Return a replacement string to
57
+ * translate or reformat the message.
58
+ *
59
+ * `field` is `null` for global/form-level errors.
60
+ *
61
+ * @example
62
+ * resolveMessage: (msg, field) => t(`errors.${msg}`) ?? msg
63
+ */
64
+ resolveMessage?: (message: string, field: string | null) => string;
65
+ /**
66
+ * Custom parsers to try before the built-in parsers.
67
+ * Parsers are tried in order; the first one that returns a non-null result wins.
68
+ * Return `null` to indicate "not recognized by this parser".
69
+ *
70
+ * Custom parsers receive the already-unwrapped body (after ApiError / Axios
71
+ * unwrapping), so they do not need to re-implement body unwrapping.
72
+ */
73
+ parsers?: ReadonlyArray<CustomParser>;
35
74
  }
75
+ /**
76
+ * Extract errors from an unknown API error response, returning a rich result
77
+ * that includes field errors, form-level (non-field) errors, and the matched format.
78
+ *
79
+ * Use `format` to distinguish "unrecognized shape" (format is null) from
80
+ * "recognized but genuinely no errors" (format is non-null, both arrays empty).
81
+ *
82
+ * `formErrors` contains global / non-field error messages that cannot be
83
+ * attributed to a specific field (e.g. RFC 9457 `detail`, JSON:API errors
84
+ * without a source pointer, violations without a field name).
85
+ *
86
+ * Supports all formats recognized by `extractFieldErrors`, plus:
87
+ * - `violations: [{ field, message }]`
88
+ * - `"invalid-params": [{ name, reason }]`
89
+ * - JSON:API `errors: [{ source: { pointer }, detail }]`
90
+ * - Laravel / DRF top-level field map `{ field: ["msg", ...] }`
91
+ *
92
+ * Use `options.parsers` to register custom parsers for application-specific shapes.
93
+ *
94
+ * Never throws.
95
+ */
96
+ export declare function extractErrors(error: unknown, options?: MapApiErrorsOptions): ExtractResult;
36
97
  /**
37
98
  * Extract normalized field errors from an unknown API error response.
38
99
  *
39
100
  * Supports:
40
101
  * - RFC 7807 / RFC 9457 Problem Details (Spring Boot 3+) with `errors` map
41
102
  * - RFC 9457 top-level `detail` field as a root-level error
103
+ * - RFC 9457 `violations: [{ field, message }]` array
104
+ * - RFC 9457 `"invalid-params": [{ name, reason }]` array
105
+ * - JSON:API `errors: [{ source: { pointer }, detail }]` array
106
+ * - Laravel / DRF top-level field map `{ field: ["msg", ...] }`
42
107
  * - Spring Boot default validation format (array of `{ field, defaultMessage }`)
43
108
  * - Simple flat `{ field, message }` object
44
109
  * - Array of `{ field, message }` objects
45
110
  *
46
- * Use `statusCodes` to restrict extraction to specific HTTP status codes —
47
- * avoids parsing 404 or 500 bodies as field errors.
111
+ * Use `statusCodes` to restrict extraction to specific HTTP status codes.
112
+ *
113
+ * For a richer result that includes non-field errors and the matched format,
114
+ * use `extractErrors` instead.
48
115
  *
49
116
  * Never throws — returns an empty array for unrecognized shapes.
50
117
  */
@@ -68,4 +135,63 @@ export declare function mapApiErrors(error: unknown, setError: (field: string, e
68
135
  type: string;
69
136
  message: string;
70
137
  }) => void, options?: MapApiErrorsOptions): void;
138
+ /**
139
+ * Vanilla (framework-agnostic) adapter.
140
+ *
141
+ * Extracts field errors from an unknown API error response and returns a plain
142
+ * `Record<string, string>` mapping field names to their first error message.
143
+ * Useful for any custom form library or imperative error handling.
144
+ *
145
+ * Only fieldErrors are included. For form-level (global) errors use `extractErrors`.
146
+ *
147
+ * @example
148
+ * ```ts
149
+ * const record = mapApiErrorsToRecord(error)
150
+ * // { email: "must not be blank", name: "required" }
151
+ * ```
152
+ */
153
+ export declare function mapApiErrorsToRecord(error: unknown, options?: MapApiErrorsOptions): Record<string, string>;
154
+ /**
155
+ * Formik adapter.
156
+ *
157
+ * Extracts field errors from an unknown API error response and calls Formik's
158
+ * `setErrors` with a `Record<string, string>` of field -> first error message.
159
+ *
160
+ * No Formik import is required. The `setErrors` parameter is typed by its
161
+ * shape only (structural typing).
162
+ *
163
+ * @example
164
+ * ```ts
165
+ * try {
166
+ * await submitForm(values)
167
+ * } catch (error) {
168
+ * mapApiErrorsFormik(error, setErrors)
169
+ * }
170
+ * ```
171
+ */
172
+ export declare function mapApiErrorsFormik(error: unknown, setErrors: (errors: Record<string, string>) => void, options?: MapApiErrorsOptions): void;
173
+ /**
174
+ * TanStack Form v1 adapter.
175
+ *
176
+ * Extracts field errors from an unknown API error response and calls
177
+ * `form.setFieldMeta` for each field to inject server-side errors into the
178
+ * form state. The updater function merges errors and errorMap onto the
179
+ * existing field meta.
180
+ *
181
+ * No TanStack Form import is required. The `form` parameter is typed by its
182
+ * shape only (structural typing), so this adapter works without adding
183
+ * `@tanstack/form-core` as a dependency.
184
+ *
185
+ * @example
186
+ * ```ts
187
+ * try {
188
+ * await form.handleSubmit()
189
+ * } catch (error) {
190
+ * mapApiErrorsTanstack(error, form)
191
+ * }
192
+ * ```
193
+ */
194
+ export declare function mapApiErrorsTanstack(error: unknown, form: {
195
+ setFieldMeta: (field: string, updater: (meta: any) => any) => void;
196
+ }, options?: MapApiErrorsOptions): void;
71
197
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IAC1C;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AA8KD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,UAAU,EAAE,CA0E9F;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,EAC3E,OAAO,CAAC,EAAE,mBAAmB,GAC5B,IAAI,CAKN"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAC7F,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAM/E;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB;;;;;OAKG;IACH,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB;;;;;OAKG;IACH,MAAM,EAAE,WAAW,GAAG,IAAI,CAAA;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IAC1C;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,MAAM,CAAA;IAClE;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAA;CACtC;AA4BD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,aAAa,CA2B1F;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,UAAU,EAAE,CAqB9F;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,EAC3E,OAAO,CAAC,EAAE,mBAAmB,GAC5B,IAAI,CAKN;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASxB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,EACnD,OAAO,CAAC,EAAE,mBAAmB,GAC5B,IAAI,CAEN;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE;IAAE,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,GAAG,KAAK,IAAI,CAAA;CAAE,EAC5E,OAAO,CAAC,EAAE,mBAAmB,GAC5B,IAAI,CASN"}
package/dist/index.js CHANGED
@@ -1,146 +1,98 @@
1
+ import { finalize } from './parsers/utils.js';
2
+ import { unwrapBody } from './parsers/unwrap.js';
3
+ import { matchBody } from './parsers/dispatch.js';
4
+ import { isObject } from './parsers/utils.js';
1
5
  // ---------------------------------------------------------------------------
2
- // Internal type guards
6
+ // Status filtering helper
3
7
  // ---------------------------------------------------------------------------
4
- function isObject(value) {
5
- return typeof value === 'object' && value !== null && !Array.isArray(value);
6
- }
7
- function isStringArray(value) {
8
- return Array.isArray(value) && value.every((v) => typeof v === 'string');
9
- }
10
- // ---------------------------------------------------------------------------
11
- // Format detectors + parsers
12
- // ---------------------------------------------------------------------------
13
- /**
14
- * RFC 7807 Problem Details (Spring Boot 3+ default):
15
- * { "errors": { "email": ["must not be blank"], "name": ["too short"] } }
16
- */
17
- function tryParseRfc7807(body, fallbackField, transformField) {
18
- const { errors } = body;
19
- if (!isObject(errors))
20
- return null;
21
- const result = [];
22
- for (const [rawField, messages] of Object.entries(errors)) {
23
- const field = transformField(rawField);
24
- if (isStringArray(messages)) {
25
- for (const message of messages) {
26
- result.push({ field, message });
27
- }
28
- }
29
- else if (typeof messages === 'string') {
30
- result.push({ field, message: messages });
31
- }
32
- // null / unknown value shapes are skipped — no partial/garbage errors
33
- }
34
- return result.length > 0 ? result : null;
35
- }
36
- /**
37
- * Spring Boot default validation format (pre-3):
38
- * { "errors": [{ "field": "email", "defaultMessage": "must not be blank" }] }
39
- */
40
- function tryParseSpringArray(body, fallbackField, transformField) {
41
- const { errors } = body;
42
- if (!Array.isArray(errors))
43
- return null;
44
- const result = [];
45
- for (const item of errors) {
46
- if (!isObject(item))
47
- continue;
48
- const rawField = typeof item['field'] === 'string' ? item['field'] : fallbackField;
49
- const message = typeof item['defaultMessage'] === 'string'
50
- ? item['defaultMessage']
51
- : typeof item['message'] === 'string'
52
- ? item['message']
53
- : 'Unknown error';
54
- result.push({ field: transformField(rawField), message });
8
+ function extractStatus(error) {
9
+ if (!isObject(error))
10
+ return undefined;
11
+ const e = error;
12
+ if (typeof e['status'] === 'number')
13
+ return e['status'];
14
+ if (isObject(e['response'])) {
15
+ const r = e['response'];
16
+ if (typeof r['status'] === 'number')
17
+ return r['status'];
55
18
  }
56
- return result.length > 0 ? result : null;
57
- }
58
- /**
59
- * Simple flat object format:
60
- * { "field": "email", "message": "Invalid email" }
61
- */
62
- function tryParseFlatObject(body, fallbackField, transformField) {
63
- const rawField = typeof body['field'] === 'string' ? body['field'] : null;
64
- const message = typeof body['message'] === 'string' ? body['message'] : null;
65
- if (message === null)
66
- return null;
67
- const field = rawField !== null ? rawField : fallbackField;
68
- return [{ field: transformField(field), message }];
19
+ return undefined;
69
20
  }
70
- /**
71
- * Array of simple flat objects:
72
- * [{ "field": "email", "message": "Invalid email" }]
73
- */
74
- function tryParseFlatArray(body, fallbackField, transformField) {
75
- const result = [];
76
- for (const item of body) {
77
- if (!isObject(item))
78
- continue;
79
- const rawField = typeof item['field'] === 'string' ? item['field'] : fallbackField;
80
- const message = typeof item['message'] === 'string' ? item['message'] : null;
81
- if (message === null)
82
- continue;
83
- result.push({ field: transformField(rawField), message });
84
- }
85
- return result.length > 0 ? result : null;
86
- }
87
- /**
88
- * RFC 9457 / RFC 7807 top-level detail field:
89
- * { "title": "Bad Request", "detail": "Email is already taken.", "status": 422 }
90
- *
91
- * Fires as a last-resort fallback when no field-specific errors are found.
92
- */
93
- function tryParseRfc9457Detail(body, fallbackField, transformField) {
94
- const detail = body['detail'];
95
- if (typeof detail !== 'string')
96
- return null;
97
- return [{ field: transformField(fallbackField), message: detail }];
21
+ /** True when the error's status code is present but not in the allowed list. */
22
+ function isStatusBlocked(error, options) {
23
+ if (!options?.statusCodes)
24
+ return false;
25
+ const status = extractStatus(error);
26
+ return status !== undefined && !options.statusCodes.includes(status);
98
27
  }
99
28
  // ---------------------------------------------------------------------------
100
- // Safety
29
+ // Public API
101
30
  // ---------------------------------------------------------------------------
102
31
  /**
103
- * Field-path segments that must never be forwarded to a path-aware setter.
104
- * A path-aware setter (e.g. React Hook Form's `setError`) splits the field name
105
- * on `.`/`[]` and walks/creates nested objects, so a malicious field like
106
- * `__proto__.polluted` from an untrusted error body would otherwise become a
107
- * prototype-pollution write in the consuming app.
108
- */
109
- const FORBIDDEN_FIELD_SEGMENTS = new Set(['__proto__', 'constructor', 'prototype']);
110
- /**
111
- * Upper bound on the number of field errors returned. A hostile body with a huge
112
- * `errors` map or array would otherwise produce an unbounded list (and an equal
113
- * number of `setError` calls / re-renders downstream).
32
+ * Extract errors from an unknown API error response, returning a rich result
33
+ * that includes field errors, form-level (non-field) errors, and the matched format.
34
+ *
35
+ * Use `format` to distinguish "unrecognized shape" (format is null) from
36
+ * "recognized but genuinely no errors" (format is non-null, both arrays empty).
37
+ *
38
+ * `formErrors` contains global / non-field error messages that cannot be
39
+ * attributed to a specific field (e.g. RFC 9457 `detail`, JSON:API errors
40
+ * without a source pointer, violations without a field name).
41
+ *
42
+ * Supports all formats recognized by `extractFieldErrors`, plus:
43
+ * - `violations: [{ field, message }]`
44
+ * - `"invalid-params": [{ name, reason }]`
45
+ * - JSON:API `errors: [{ source: { pointer }, detail }]`
46
+ * - Laravel / DRF top-level field map `{ field: ["msg", ...] }`
47
+ *
48
+ * Use `options.parsers` to register custom parsers for application-specific shapes.
49
+ *
50
+ * Never throws.
114
51
  */
115
- const MAX_FIELD_ERRORS = 1000;
116
- /** True if no path segment of `field` is a prototype-pollution gadget key. */
117
- function isSafeFieldPath(field) {
118
- for (const segment of field.split(/[.[\]]+/)) {
119
- if (FORBIDDEN_FIELD_SEGMENTS.has(segment))
120
- return false;
52
+ export function extractErrors(error, options) {
53
+ const fallbackField = options?.fallbackField ?? 'root';
54
+ const transformField = options?.transformField ?? ((f) => f);
55
+ const resolveMessage = options?.resolveMessage;
56
+ try {
57
+ if (isStatusBlocked(error, options))
58
+ return { fieldErrors: [], formErrors: [], format: null };
59
+ const match = matchBody(unwrapBody(error), fallbackField, transformField, options?.parsers);
60
+ if (match === null)
61
+ return { fieldErrors: [], formErrors: [], format: null };
62
+ const { parsed, format } = match;
63
+ const fieldErrors = finalize(resolveMessage
64
+ ? parsed.fieldErrors.map((e) => ({
65
+ field: e.field,
66
+ message: resolveMessage(e.message, e.field),
67
+ }))
68
+ : parsed.fieldErrors);
69
+ const formErrors = resolveMessage
70
+ ? parsed.formErrors.map((m) => resolveMessage(m, null))
71
+ : parsed.formErrors;
72
+ return { fieldErrors, formErrors, format };
73
+ }
74
+ catch {
75
+ return { fieldErrors: [], formErrors: [], format: null };
121
76
  }
122
- return true;
123
- }
124
- /** Drop unsafe field paths and cap the result before it leaves the library. */
125
- function finalize(result) {
126
- const safe = result.filter((e) => isSafeFieldPath(e.field));
127
- return safe.length > MAX_FIELD_ERRORS ? safe.slice(0, MAX_FIELD_ERRORS) : safe;
128
77
  }
129
- // ---------------------------------------------------------------------------
130
- // Public API
131
- // ---------------------------------------------------------------------------
132
78
  /**
133
79
  * Extract normalized field errors from an unknown API error response.
134
80
  *
135
81
  * Supports:
136
82
  * - RFC 7807 / RFC 9457 Problem Details (Spring Boot 3+) with `errors` map
137
83
  * - RFC 9457 top-level `detail` field as a root-level error
84
+ * - RFC 9457 `violations: [{ field, message }]` array
85
+ * - RFC 9457 `"invalid-params": [{ name, reason }]` array
86
+ * - JSON:API `errors: [{ source: { pointer }, detail }]` array
87
+ * - Laravel / DRF top-level field map `{ field: ["msg", ...] }`
138
88
  * - Spring Boot default validation format (array of `{ field, defaultMessage }`)
139
89
  * - Simple flat `{ field, message }` object
140
90
  * - Array of `{ field, message }` objects
141
91
  *
142
- * Use `statusCodes` to restrict extraction to specific HTTP status codes —
143
- * avoids parsing 404 or 500 bodies as field errors.
92
+ * Use `statusCodes` to restrict extraction to specific HTTP status codes.
93
+ *
94
+ * For a richer result that includes non-field errors and the matched format,
95
+ * use `extractErrors` instead.
144
96
  *
145
97
  * Never throws — returns an empty array for unrecognized shapes.
146
98
  */
@@ -148,66 +100,19 @@ export function extractFieldErrors(error, options) {
148
100
  const fallbackField = options?.fallbackField ?? 'root';
149
101
  const transformField = options?.transformField ?? ((f) => f);
150
102
  try {
151
- // Status-code filtering: if statusCodes is provided, check error.status
152
- // (or error.response.status for Axios-style errors) before doing anything.
153
- if (options?.statusCodes !== undefined) {
154
- let status;
155
- if (isObject(error)) {
156
- const e = error;
157
- if (typeof e['status'] === 'number') {
158
- status = e['status'];
159
- }
160
- else if (isObject(e['response'])) {
161
- const r = e['response'];
162
- if (typeof r['status'] === 'number')
163
- status = r['status'];
164
- }
165
- }
166
- if (status !== undefined && !options.statusCodes.includes(status)) {
167
- return [];
168
- }
169
- }
170
- // Unwrap common error wrapper shapes (e.g. Axios response, fetch response body)
171
- let body = error;
172
- // Support ApiError-style wrappers: { status: number, body: unknown }
173
- // Matches the ApiError class generated by @codewithagents/openapi-gen, letting
174
- // callers pass the thrown error directly: extractFieldErrors(apiError, { statusCodes: [422] })
175
- if (isObject(body) &&
176
- typeof body['status'] === 'number' &&
177
- Object.prototype.hasOwnProperty.call(body, 'body')) {
178
- body = body['body'];
179
- }
180
- // Support objects with a `response.data` shape (Axios-style)
181
- if (isObject(body) && isObject(body['response']) && body['response']['data'] !== undefined) {
182
- body = body['response']['data'];
183
- }
184
- // Support objects with a `data` property that contains the actual error body
185
- if (isObject(body) && isObject(body['data']) && !('field' in body) && !('errors' in body)) {
186
- body = body['data'];
187
- }
188
- // Array of flat error objects
189
- if (Array.isArray(body)) {
190
- return finalize(tryParseFlatArray(body, fallbackField, transformField) ?? []);
191
- }
192
- if (!isObject(body))
103
+ if (isStatusBlocked(error, options))
193
104
  return [];
194
- // Try RFC 7807 / Spring Boot 3 format first (object-style errors map)
195
- const rfc7807 = tryParseRfc7807(body, fallbackField, transformField);
196
- if (rfc7807 !== null)
197
- return finalize(rfc7807);
198
- // Try Spring Boot default format (array-style errors list)
199
- const springArray = tryParseSpringArray(body, fallbackField, transformField);
200
- if (springArray !== null)
201
- return finalize(springArray);
202
- // Try simple flat object
203
- const flat = tryParseFlatObject(body, fallbackField, transformField);
204
- if (flat !== null)
205
- return finalize(flat);
206
- // Try RFC 9457 top-level detail as a last-resort root error
207
- const rfc9457 = tryParseRfc9457Detail(body, fallbackField, transformField);
208
- if (rfc9457 !== null)
209
- return finalize(rfc9457);
210
- return [];
105
+ const match = matchBody(unwrapBody(error), fallbackField, transformField, options?.parsers);
106
+ if (match === null)
107
+ return [];
108
+ const { parsed } = match;
109
+ // In the legacy API, form-level errors fall back to fallbackField instead of
110
+ // being returned in a separate channel.
111
+ const fallbackErrors = parsed.formErrors.map((message) => ({
112
+ field: transformField(fallbackField),
113
+ message,
114
+ }));
115
+ return finalize([...parsed.fieldErrors, ...fallbackErrors]);
211
116
  }
212
117
  catch {
213
118
  return [];
@@ -234,4 +139,81 @@ export function mapApiErrors(error, setError, options) {
234
139
  setError(field, { type: 'server', message });
235
140
  }
236
141
  }
142
+ /**
143
+ * Vanilla (framework-agnostic) adapter.
144
+ *
145
+ * Extracts field errors from an unknown API error response and returns a plain
146
+ * `Record<string, string>` mapping field names to their first error message.
147
+ * Useful for any custom form library or imperative error handling.
148
+ *
149
+ * Only fieldErrors are included. For form-level (global) errors use `extractErrors`.
150
+ *
151
+ * @example
152
+ * ```ts
153
+ * const record = mapApiErrorsToRecord(error)
154
+ * // { email: "must not be blank", name: "required" }
155
+ * ```
156
+ */
157
+ export function mapApiErrorsToRecord(error, options) {
158
+ const fieldErrors = extractFieldErrors(error, options);
159
+ const record = {};
160
+ for (const { field, message } of fieldErrors) {
161
+ if (!(field in record)) {
162
+ record[field] = message;
163
+ }
164
+ }
165
+ return record;
166
+ }
167
+ /**
168
+ * Formik adapter.
169
+ *
170
+ * Extracts field errors from an unknown API error response and calls Formik's
171
+ * `setErrors` with a `Record<string, string>` of field -> first error message.
172
+ *
173
+ * No Formik import is required. The `setErrors` parameter is typed by its
174
+ * shape only (structural typing).
175
+ *
176
+ * @example
177
+ * ```ts
178
+ * try {
179
+ * await submitForm(values)
180
+ * } catch (error) {
181
+ * mapApiErrorsFormik(error, setErrors)
182
+ * }
183
+ * ```
184
+ */
185
+ export function mapApiErrorsFormik(error, setErrors, options) {
186
+ setErrors(mapApiErrorsToRecord(error, options));
187
+ }
188
+ /**
189
+ * TanStack Form v1 adapter.
190
+ *
191
+ * Extracts field errors from an unknown API error response and calls
192
+ * `form.setFieldMeta` for each field to inject server-side errors into the
193
+ * form state. The updater function merges errors and errorMap onto the
194
+ * existing field meta.
195
+ *
196
+ * No TanStack Form import is required. The `form` parameter is typed by its
197
+ * shape only (structural typing), so this adapter works without adding
198
+ * `@tanstack/form-core` as a dependency.
199
+ *
200
+ * @example
201
+ * ```ts
202
+ * try {
203
+ * await form.handleSubmit()
204
+ * } catch (error) {
205
+ * mapApiErrorsTanstack(error, form)
206
+ * }
207
+ * ```
208
+ */
209
+ export function mapApiErrorsTanstack(error, form, options) {
210
+ const record = mapApiErrorsToRecord(error, options);
211
+ for (const [field, message] of Object.entries(record)) {
212
+ form.setFieldMeta(field, (meta) => ({
213
+ ...meta,
214
+ errors: [message],
215
+ errorMap: { onChange: message },
216
+ }));
217
+ }
218
+ }
237
219
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { CustomParser, ErrorFormat, ParsedErrors } from './types.js';
2
+ /** Internal match result: parsed errors + the format that matched. */
3
+ export interface MatchResult {
4
+ parsed: ParsedErrors;
5
+ format: ErrorFormat;
6
+ }
7
+ /**
8
+ * Run all parsers (custom, array, object) against an already-unwrapped body.
9
+ * Returns the first match, or null if no parser recognized the shape.
10
+ */
11
+ export declare function matchBody(body: unknown, fallbackField: string, transformField: (f: string) => string, customParsers: ReadonlyArray<CustomParser> | undefined): MatchResult | null;
12
+ //# sourceMappingURL=dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/parsers/dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAYzE,sEAAsE;AACtE,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,YAAY,CAAA;IACpB,MAAM,EAAE,WAAW,CAAA;CACpB;AA6GD;;;GAGG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,OAAO,EACb,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EACrC,aAAa,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,SAAS,GACrD,WAAW,GAAG,IAAI,CAQpB"}