@codewithagents/api-errors 1.1.0 → 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 +61 -41
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +81 -420
  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 +1 -1
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Normalized representation of a single field-level error.
3
+ */
4
+ export interface FieldError {
5
+ field: string;
6
+ message: string;
7
+ }
8
+ /**
9
+ * Raw parse result used internally and returned by custom parsers.
10
+ * Both arrays may be empty if the shape was recognized but contained no errors.
11
+ */
12
+ export interface ParsedErrors {
13
+ fieldErrors: FieldError[];
14
+ formErrors: string[];
15
+ }
16
+ /**
17
+ * The format/shape that was recognized when parsing an error body.
18
+ *
19
+ * - `'rfc7807-map'` - RFC 7807 / RFC 9457 `errors` map: `{ errors: { field: [...] } }`
20
+ * - `'spring-array'` - Spring Boot array: `{ errors: [{ field, defaultMessage }] }`
21
+ * - `'violations'` - RFC 9457 / Spring `violations` array: `{ violations: [{ field, message }] }`
22
+ * - `'invalid-params'` - RFC 9457 `invalid-params` array: `{ "invalid-params": [{ name, reason }] }`
23
+ * - `'json-api'` - JSON:API errors array: `{ errors: [{ source: { pointer }, detail }] }`
24
+ * - `'graphql-extensions'` - GraphQL errors array: `{ errors: [{ message, extensions?: { field?, path? } }] }`
25
+ * - `'zod-flatten'` - Zod flatten shape: `{ fieldErrors: { field: [...] }, formErrors: [...] }`
26
+ * - `'laravel-drf'` - Laravel / DRF top-level field map: `{ field: ["msg1", ...] }`
27
+ * - `'flat-object'` - Simple flat object: `{ field, message }`
28
+ * - `'flat-array'` - Array of flat objects: `[{ field, message }]`
29
+ * - `'rfc9457-detail'` - RFC 9457 top-level `detail` string (last-resort fallback)
30
+ * - `'custom'` - Matched a caller-provided custom parser
31
+ */
32
+ export type ErrorFormat = 'rfc7807-map' | 'spring-array' | 'violations' | 'invalid-params' | 'json-api' | 'graphql-extensions' | 'zod-flatten' | 'laravel-drf' | 'flat-object' | 'flat-array' | 'rfc9457-detail' | 'custom';
33
+ /**
34
+ * A custom parser that callers can register to handle application-specific
35
+ * error shapes not covered by the built-in parsers.
36
+ *
37
+ * Return `null` to indicate "not recognized" and let the next parser try.
38
+ * Return a `ParsedErrors` object (even if both arrays are empty) to signal
39
+ * that this shape was recognized.
40
+ */
41
+ export interface CustomParser {
42
+ (body: unknown): ParsedErrors | null;
43
+ }
44
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/parsers/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,WAAW,GACnB,aAAa,GACb,cAAc,GACd,YAAY,GACZ,gBAAgB,GAChB,UAAU,GACV,oBAAoB,GACpB,aAAa,GACb,aAAa,GACb,aAAa,GACb,YAAY,GACZ,gBAAgB,GAChB,QAAQ,CAAA;AAEZ;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAAA;CACrC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/parsers/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ /** Run all three unwrap steps in sequence to get the raw error body. */
2
+ export declare function unwrapBody(error: unknown): unknown;
3
+ //# sourceMappingURL=unwrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unwrap.d.ts","sourceRoot":"","sources":["../../src/parsers/unwrap.ts"],"names":[],"mappings":"AA8BA,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAElD"}
@@ -0,0 +1,29 @@
1
+ import { isObject } from './utils.js';
2
+ /** Unwrap `{ status: number, body: unknown }` (ApiError from generated client). */
3
+ function unwrapApiError(value) {
4
+ if (isObject(value) &&
5
+ typeof value['status'] === 'number' &&
6
+ Object.prototype.hasOwnProperty.call(value, 'body')) {
7
+ return value['body'];
8
+ }
9
+ return value;
10
+ }
11
+ /** Unwrap `{ response: { data: ... } }` (Axios-style errors). */
12
+ function unwrapAxiosResponse(value) {
13
+ if (isObject(value) && isObject(value['response']) && value['response']['data'] !== undefined) {
14
+ return value['response']['data'];
15
+ }
16
+ return value;
17
+ }
18
+ /** Unwrap `{ data: { ... } }` top-level data envelopes (no field/errors at root). */
19
+ function unwrapDataEnvelope(value) {
20
+ if (isObject(value) && isObject(value['data']) && !('field' in value) && !('errors' in value)) {
21
+ return value['data'];
22
+ }
23
+ return value;
24
+ }
25
+ /** Run all three unwrap steps in sequence to get the raw error body. */
26
+ export function unwrapBody(error) {
27
+ return unwrapDataEnvelope(unwrapAxiosResponse(unwrapApiError(error)));
28
+ }
29
+ //# sourceMappingURL=unwrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unwrap.js","sourceRoot":"","sources":["../../src/parsers/unwrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAErC,mFAAmF;AACnF,SAAS,cAAc,CAAC,KAAc;IACpC,IACE,QAAQ,CAAC,KAAK,CAAC;QACf,OAAQ,KAAiC,CAAC,QAAQ,CAAC,KAAK,QAAQ;QAChE,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,EACnD,CAAC;QACD,OAAQ,KAAiC,CAAC,MAAM,CAAC,CAAA;IACnD,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,iEAAiE;AACjE,SAAS,mBAAmB,CAAC,KAAc;IACzC,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAAK,SAAS,EAAE,CAAC;QAC9F,OAAO,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,qFAAqF;AACrF,SAAS,kBAAkB,CAAC,KAAc;IACxC,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,CAAC;QAC9F,OAAO,KAAK,CAAC,MAAM,CAAC,CAAA;IACtB,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,kBAAkB,CAAC,mBAAmB,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AACvE,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { FieldError, ParsedErrors } from './types.js';
2
+ export declare function isObject(value: unknown): value is Record<string, unknown>;
3
+ export declare function isStringArray(value: unknown): value is string[];
4
+ /**
5
+ * Parse an array of objects where each item carries a field key and a message key.
6
+ * Items whose field value is absent or empty are treated as global (form-level) errors.
7
+ * Items without a message value are silently skipped.
8
+ */
9
+ export declare function parseKeyedArray(items: unknown[], fieldKey: string, messageKey: string): ParsedErrors;
10
+ /** Drop unsafe field paths and cap the result before it leaves the library. */
11
+ export declare function finalize(result: FieldError[]): FieldError[];
12
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/parsers/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE1D,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,EAAE,CAE/D;AAeD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,YAAY,CAgBpG;AA0BD,+EAA+E;AAC/E,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAG3D"}
@@ -0,0 +1,65 @@
1
+ export function isObject(value) {
2
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
3
+ }
4
+ export function isStringArray(value) {
5
+ return Array.isArray(value) && value.every((v) => typeof v === 'string');
6
+ }
7
+ /** Extract field + message from a single keyed-array item. Returns null when message is absent. */
8
+ function parseKeyedItem(item, fieldKey, messageKey) {
9
+ const message = typeof item[messageKey] === 'string' ? item[messageKey] : null;
10
+ if (message === null)
11
+ return null;
12
+ const field = typeof item[fieldKey] === 'string' && item[fieldKey] !== '' ? item[fieldKey] : null;
13
+ return { field, message };
14
+ }
15
+ /**
16
+ * Parse an array of objects where each item carries a field key and a message key.
17
+ * Items whose field value is absent or empty are treated as global (form-level) errors.
18
+ * Items without a message value are silently skipped.
19
+ */
20
+ export function parseKeyedArray(items, fieldKey, messageKey) {
21
+ const fieldErrors = [];
22
+ const formErrors = [];
23
+ for (const item of items) {
24
+ if (!isObject(item))
25
+ continue;
26
+ const parsed = parseKeyedItem(item, fieldKey, messageKey);
27
+ if (parsed === null)
28
+ continue;
29
+ if (parsed.field !== null) {
30
+ fieldErrors.push({ field: parsed.field, message: parsed.message });
31
+ }
32
+ else {
33
+ formErrors.push(parsed.message);
34
+ }
35
+ }
36
+ return { fieldErrors, formErrors };
37
+ }
38
+ /**
39
+ * Field-path segments that must never be forwarded to a path-aware setter.
40
+ * A path-aware setter (e.g. React Hook Form's `setError`) splits the field name
41
+ * on `.`/`[]` and walks/creates nested objects, so a malicious field like
42
+ * `__proto__.polluted` from an untrusted error body would otherwise become a
43
+ * prototype-pollution write in the consuming app.
44
+ */
45
+ const FORBIDDEN_FIELD_SEGMENTS = new Set(['__proto__', 'constructor', 'prototype']);
46
+ /**
47
+ * Upper bound on the number of field errors returned. A hostile body with a huge
48
+ * `errors` map or array would otherwise produce an unbounded list (and an equal
49
+ * number of `setError` calls / re-renders downstream).
50
+ */
51
+ const MAX_FIELD_ERRORS = 1000;
52
+ /** True if no path segment of `field` is a prototype-pollution gadget key. */
53
+ function isSafeFieldPath(field) {
54
+ for (const segment of field.split(/[.[\]]+/)) {
55
+ if (FORBIDDEN_FIELD_SEGMENTS.has(segment))
56
+ return false;
57
+ }
58
+ return true;
59
+ }
60
+ /** Drop unsafe field paths and cap the result before it leaves the library. */
61
+ export function finalize(result) {
62
+ const safe = result.filter((e) => isSafeFieldPath(e.field));
63
+ return safe.length > MAX_FIELD_ERRORS ? safe.slice(0, MAX_FIELD_ERRORS) : safe;
64
+ }
65
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/parsers/utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;AAC7E,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAA;AAC1E,CAAC;AAED,mGAAmG;AACnG,SAAS,cAAc,CACrB,IAA6B,EAC7B,QAAgB,EAChB,UAAkB;IAElB,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,IAAI,CAAC,UAAU,CAAY,CAAC,CAAC,CAAC,IAAI,CAAA;IAC1F,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IACjC,MAAM,KAAK,GACT,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAE,IAAI,CAAC,QAAQ,CAAY,CAAC,CAAC,CAAC,IAAI,CAAA;IACjG,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;AAC3B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAAgB,EAAE,QAAgB,EAAE,UAAkB;IACpF,MAAM,WAAW,GAAiB,EAAE,CAAA;IACpC,MAAM,UAAU,GAAa,EAAE,CAAA;IAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,SAAQ;QAC7B,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAA;QACzD,IAAI,MAAM,KAAK,IAAI;YAAE,SAAQ;QAC7B,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YAC1B,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAA;QACpE,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACjC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,CAAA;AACpC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC,CAAA;AAEnF;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,IAAI,CAAA;AAE7B,8EAA8E;AAC9E,SAAS,eAAe,CAAC,KAAa;IACpC,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7C,IAAI,wBAAwB,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,OAAO,KAAK,CAAA;IACzD,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,QAAQ,CAAC,MAAoB;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;IAC3D,OAAO,IAAI,CAAC,MAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAChF,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { ParsedErrors } from './types.js';
2
+ /**
3
+ * RFC 9457 violations array (also used by some Spring Boot setups):
4
+ * { "violations": [{ "field": "email", "message": "must not be blank" }] }
5
+ */
6
+ export declare function tryParseViolations(body: Record<string, unknown>): ParsedErrors | null;
7
+ //# sourceMappingURL=violations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"violations.d.ts","sourceRoot":"","sources":["../../src/parsers/violations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAG9C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,GAAG,IAAI,CAIrF"}
@@ -0,0 +1,12 @@
1
+ import { parseKeyedArray } from './utils.js';
2
+ /**
3
+ * RFC 9457 violations array (also used by some Spring Boot setups):
4
+ * { "violations": [{ "field": "email", "message": "must not be blank" }] }
5
+ */
6
+ export function tryParseViolations(body) {
7
+ const { violations } = body;
8
+ if (!Array.isArray(violations))
9
+ return null;
10
+ return parseKeyedArray(violations, 'field', 'message');
11
+ }
12
+ //# sourceMappingURL=violations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"violations.js","sourceRoot":"","sources":["../../src/parsers/violations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE5C;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAA6B;IAC9D,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAA;IAC3B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAA;IAC3C,OAAO,eAAe,CAAC,UAAU,EAAE,OAAO,EAAE,SAAS,CAAC,CAAA;AACxD,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { ParsedErrors } from './types.js';
2
+ /**
3
+ * Zod `.flatten()` output shape:
4
+ * { fieldErrors: { email: ["must not be blank"], name: ["required"] }, formErrors: ["Global error"] }
5
+ *
6
+ * Guard: body must have at least one of `fieldErrors` or `formErrors`.
7
+ * `fieldErrors` must be a plain object (not null, not array).
8
+ * `formErrors` must be an array of strings.
9
+ */
10
+ export declare function tryParseZodFlatten(body: Record<string, unknown>): ParsedErrors | null;
11
+ //# sourceMappingURL=zod-flatten.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zod-flatten.d.ts","sourceRoot":"","sources":["../../src/parsers/zod-flatten.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,YAAY,EAAE,MAAM,YAAY,CAAA;AAG1D;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,GAAG,IAAI,CA+BrF"}
@@ -0,0 +1,37 @@
1
+ import { isObject, isStringArray } from './utils.js';
2
+ /**
3
+ * Zod `.flatten()` output shape:
4
+ * { fieldErrors: { email: ["must not be blank"], name: ["required"] }, formErrors: ["Global error"] }
5
+ *
6
+ * Guard: body must have at least one of `fieldErrors` or `formErrors`.
7
+ * `fieldErrors` must be a plain object (not null, not array).
8
+ * `formErrors` must be an array of strings.
9
+ */
10
+ export function tryParseZodFlatten(body) {
11
+ const rawFieldErrors = body['fieldErrors'];
12
+ const rawFormErrors = body['formErrors'];
13
+ const hasFieldErrors = rawFieldErrors !== undefined;
14
+ const hasFormErrors = rawFormErrors !== undefined;
15
+ // At least one key must be present.
16
+ if (!hasFieldErrors && !hasFormErrors)
17
+ return null;
18
+ // If fieldErrors is present, it must be a plain object (not null, not array).
19
+ if (hasFieldErrors && !isObject(rawFieldErrors))
20
+ return null;
21
+ // If formErrors is present, it must be a string array (empty is allowed).
22
+ if (hasFormErrors && !isStringArray(rawFormErrors))
23
+ return null;
24
+ const fieldErrors = [];
25
+ if (hasFieldErrors && isObject(rawFieldErrors)) {
26
+ for (const [field, messages] of Object.entries(rawFieldErrors)) {
27
+ if (isStringArray(messages)) {
28
+ for (const message of messages) {
29
+ fieldErrors.push({ field, message });
30
+ }
31
+ }
32
+ }
33
+ }
34
+ const formErrors = isStringArray(rawFormErrors) ? rawFormErrors : [];
35
+ return { fieldErrors, formErrors };
36
+ }
37
+ //# sourceMappingURL=zod-flatten.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zod-flatten.js","sourceRoot":"","sources":["../../src/parsers/zod-flatten.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAEpD;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAA6B;IAC9D,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC,CAAA;IAC1C,MAAM,aAAa,GAAG,IAAI,CAAC,YAAY,CAAC,CAAA;IAExC,MAAM,cAAc,GAAG,cAAc,KAAK,SAAS,CAAA;IACnD,MAAM,aAAa,GAAG,aAAa,KAAK,SAAS,CAAA;IAEjD,oCAAoC;IACpC,IAAI,CAAC,cAAc,IAAI,CAAC,aAAa;QAAE,OAAO,IAAI,CAAA;IAElD,8EAA8E;IAC9E,IAAI,cAAc,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC;QAAE,OAAO,IAAI,CAAA;IAE5D,0EAA0E;IAC1E,IAAI,aAAa,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC;QAAE,OAAO,IAAI,CAAA;IAE/D,MAAM,WAAW,GAAiB,EAAE,CAAA;IAEpC,IAAI,cAAc,IAAI,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QAC/C,KAAK,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;YAC/D,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC5B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;oBAC/B,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;gBACtC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAa,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAE,aAA0B,CAAC,CAAC,CAAC,EAAE,CAAA;IAE5F,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,CAAA;AACpC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codewithagents/api-errors",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Map backend API errors to form field errors. Framework-agnostic core with React Hook Form adapter.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",