@codewithagents/api-errors 0.1.0 → 0.3.1
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/README.md +60 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -4
- package/dist/index.js.map +1 -1
- package/package.json +12 -8
- package/dist/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -161
- package/dist/index.test.js.map +0 -1
package/README.md
CHANGED
|
@@ -32,16 +32,42 @@ function SignupForm() {
|
|
|
32
32
|
<form onSubmit={handleSubmit(onSubmit)}>
|
|
33
33
|
<input {...register('email')} />
|
|
34
34
|
{errors.email && <p>{errors.email.message}</p>}
|
|
35
|
-
|
|
36
|
-
<input {...register('name')} />
|
|
37
|
-
{errors.name && <p>{errors.name.message}</p>}
|
|
38
|
-
|
|
39
35
|
<button type="submit">Sign up</button>
|
|
40
36
|
</form>
|
|
41
37
|
)
|
|
42
38
|
}
|
|
43
39
|
```
|
|
44
40
|
|
|
41
|
+
### With typed React Hook Form forms
|
|
42
|
+
|
|
43
|
+
`mapApiErrors` accepts any function matching `(field: string, error: { type: string; message: string }) => void`, which is compatible with RHF's `UseFormSetError<T>`. No casting needed:
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
type FormValues = { email: string; name: string }
|
|
47
|
+
|
|
48
|
+
const { setError } = useForm<FormValues>()
|
|
49
|
+
|
|
50
|
+
// ✅ works — setError is assignable to the expected signature
|
|
51
|
+
mapApiErrors(error, setError)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### With native `fetch` (no Axios)
|
|
55
|
+
|
|
56
|
+
Pass the parsed response body directly to `extractFieldErrors`:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { extractFieldErrors } from '@codewithagents/api-errors'
|
|
60
|
+
|
|
61
|
+
const res = await fetch('/api/signup', { method: 'POST', body: JSON.stringify(data) })
|
|
62
|
+
if (!res.ok) {
|
|
63
|
+
const body = await res.json()
|
|
64
|
+
const fieldErrors = extractFieldErrors(body)
|
|
65
|
+
for (const { field, message } of fieldErrors) {
|
|
66
|
+
setError(field, { type: 'server', message })
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
45
71
|
### Standalone with `extractFieldErrors`
|
|
46
72
|
|
|
47
73
|
Use `extractFieldErrors` when you need the normalized error list without a form library:
|
|
@@ -54,22 +80,31 @@ try {
|
|
|
54
80
|
} catch (error) {
|
|
55
81
|
const fieldErrors = extractFieldErrors(error)
|
|
56
82
|
// [{ field: 'email', message: 'must not be blank' }, ...]
|
|
57
|
-
|
|
58
83
|
for (const { field, message } of fieldErrors) {
|
|
59
84
|
console.warn(`${field}: ${message}`)
|
|
60
85
|
}
|
|
61
86
|
}
|
|
62
87
|
```
|
|
63
88
|
|
|
64
|
-
|
|
89
|
+
### Options
|
|
90
|
+
|
|
91
|
+
Both `extractFieldErrors` and `mapApiErrors` accept an options object:
|
|
65
92
|
|
|
66
93
|
```ts
|
|
67
94
|
const fieldErrors = extractFieldErrors(error, {
|
|
68
|
-
|
|
69
|
-
|
|
95
|
+
// Field name used when no field can be determined (default: 'root')
|
|
96
|
+
fallbackField: 'serverError',
|
|
97
|
+
|
|
98
|
+
// Transform field names — e.g. camelCase backend → dot.path for nested RHF fields
|
|
99
|
+
transformField: (f) => f.replace(/([A-Z])/g, '.$1').toLowerCase(),
|
|
70
100
|
})
|
|
101
|
+
|
|
102
|
+
// Options work on mapApiErrors too
|
|
103
|
+
mapApiErrors(error, setError, { fallbackField: 'root' })
|
|
71
104
|
```
|
|
72
105
|
|
|
106
|
+
> **Note:** `transformField` is also applied to `fallbackField`. If you transform `emailAddress` → `email.address`, the fallback field name is transformed the same way.
|
|
107
|
+
|
|
73
108
|
## Supported Error Formats
|
|
74
109
|
|
|
75
110
|
**RFC 7807 Problem Details** (Spring Boot 3+, standard):
|
|
@@ -99,11 +134,27 @@ const fieldErrors = extractFieldErrors(error, {
|
|
|
99
134
|
```json
|
|
100
135
|
{ "field": "email", "message": "Invalid email" }
|
|
101
136
|
```
|
|
102
|
-
|
|
137
|
+
|
|
138
|
+
**Array of flat objects:**
|
|
103
139
|
```json
|
|
104
140
|
[{ "field": "email", "message": "Invalid email" }]
|
|
105
141
|
```
|
|
106
142
|
|
|
143
|
+
Response wrappers are automatically unwrapped — both Axios-style `error.response.data` and generic `{ data: { ... } }` shapes.
|
|
144
|
+
|
|
145
|
+
## Known behaviour: multiple errors for the same field
|
|
146
|
+
|
|
147
|
+
When a backend returns multiple errors for the same field (e.g. in the flat array format), `extractFieldErrors` returns all of them. If you pass them all to React Hook Form's `setError`, the **last call wins** — only the last message is displayed. If you need to show all messages, collect them before calling `setError`:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
const fieldErrors = extractFieldErrors(error)
|
|
151
|
+
const grouped = Map.groupBy(fieldErrors, (e) => e.field)
|
|
152
|
+
|
|
153
|
+
for (const [field, errs] of grouped) {
|
|
154
|
+
setError(field, { type: 'server', message: errs.map((e) => e.message).join(', ') })
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
107
158
|
## TypeScript
|
|
108
159
|
|
|
109
160
|
This package is written in TypeScript and ships full type declarations. No `@types` package needed.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;CAC3C;
|
|
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;CAC3C;AAiID;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,mBAAmB,GAC5B,UAAU,EAAE,CAyCd;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"}
|
package/dist/index.js
CHANGED
|
@@ -29,10 +29,7 @@ function tryParseRfc7807(body, fallbackField, transformField) {
|
|
|
29
29
|
else if (typeof messages === 'string') {
|
|
30
30
|
result.push({ field, message: messages });
|
|
31
31
|
}
|
|
32
|
-
|
|
33
|
-
// Unknown value shape — use fallback field with stringified message
|
|
34
|
-
result.push({ field: transformField(fallbackField), message: String(messages) });
|
|
35
|
-
}
|
|
32
|
+
// null / unknown value shapes are skipped — no partial/garbage errors
|
|
36
33
|
}
|
|
37
34
|
return result.length > 0 ? result : null;
|
|
38
35
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAyBA,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;AAC7E,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,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,8EAA8E;AAC9E,6BAA6B;AAC7B,8EAA8E;AAE9E;;;GAGG;AACH,SAAS,eAAe,CACtB,IAA6B,EAC7B,aAAqB,EACrB,cAAyC;IAEzC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IACvB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAA;IAElC,MAAM,MAAM,GAAiB,EAAE,CAAA;IAE/B,KAAK,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1D,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAA;QACtC,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;YACjC,CAAC;QACH,CAAC;aAAM,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAA;QAC3C,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codewithagents/api-errors",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.3.1",
|
|
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",
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
"files": [
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"lint": "tsc --noEmit"
|
|
21
|
+
},
|
|
17
22
|
"keywords": [
|
|
18
23
|
"api",
|
|
19
24
|
"errors",
|
|
@@ -23,13 +28,12 @@
|
|
|
23
28
|
"typescript"
|
|
24
29
|
],
|
|
25
30
|
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/codewithagents/glue"
|
|
34
|
+
},
|
|
26
35
|
"devDependencies": {
|
|
27
|
-
"typescript": "^
|
|
36
|
+
"typescript": "^6.0.0",
|
|
28
37
|
"vitest": "^3.0.0"
|
|
29
|
-
},
|
|
30
|
-
"scripts": {
|
|
31
|
-
"build": "tsc",
|
|
32
|
-
"test": "vitest run",
|
|
33
|
-
"lint": "tsc --noEmit"
|
|
34
38
|
}
|
|
35
|
-
}
|
|
39
|
+
}
|
package/dist/index.test.d.ts
DELETED
package/dist/index.test.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|
package/dist/index.test.js
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { extractFieldErrors, mapApiErrors } from './index.js';
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
// extractFieldErrors
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
describe('extractFieldErrors', () => {
|
|
7
|
-
describe('RFC 7807 / Spring Boot 3+ format', () => {
|
|
8
|
-
it('maps a single field with one message', () => {
|
|
9
|
-
const error = { errors: { email: ['must not be blank'] } };
|
|
10
|
-
expect(extractFieldErrors(error)).toEqual([
|
|
11
|
-
{ field: 'email', message: 'must not be blank' },
|
|
12
|
-
]);
|
|
13
|
-
});
|
|
14
|
-
it('maps multiple fields', () => {
|
|
15
|
-
const error = {
|
|
16
|
-
errors: {
|
|
17
|
-
email: ['must not be blank'],
|
|
18
|
-
name: ['too short'],
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
|
-
const result = extractFieldErrors(error);
|
|
22
|
-
expect(result).toHaveLength(2);
|
|
23
|
-
expect(result).toContainEqual({ field: 'email', message: 'must not be blank' });
|
|
24
|
-
expect(result).toContainEqual({ field: 'name', message: 'too short' });
|
|
25
|
-
});
|
|
26
|
-
it('expands multiple messages per field into separate FieldErrors', () => {
|
|
27
|
-
const error = { errors: { email: ['must not be blank', 'invalid format'] } };
|
|
28
|
-
expect(extractFieldErrors(error)).toEqual([
|
|
29
|
-
{ field: 'email', message: 'must not be blank' },
|
|
30
|
-
{ field: 'email', message: 'invalid format' },
|
|
31
|
-
]);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
describe('Spring Boot default validation format (array)', () => {
|
|
35
|
-
it('maps field + defaultMessage', () => {
|
|
36
|
-
const error = {
|
|
37
|
-
status: 400,
|
|
38
|
-
errors: [{ field: 'email', defaultMessage: 'must not be blank' }],
|
|
39
|
-
};
|
|
40
|
-
expect(extractFieldErrors(error)).toEqual([
|
|
41
|
-
{ field: 'email', message: 'must not be blank' },
|
|
42
|
-
]);
|
|
43
|
-
});
|
|
44
|
-
it('falls back to message when defaultMessage is absent', () => {
|
|
45
|
-
const error = {
|
|
46
|
-
errors: [{ field: 'email', message: 'must not be blank' }],
|
|
47
|
-
};
|
|
48
|
-
expect(extractFieldErrors(error)).toEqual([
|
|
49
|
-
{ field: 'email', message: 'must not be blank' },
|
|
50
|
-
]);
|
|
51
|
-
});
|
|
52
|
-
it('maps multiple entries', () => {
|
|
53
|
-
const error = {
|
|
54
|
-
errors: [
|
|
55
|
-
{ field: 'email', defaultMessage: 'must not be blank' },
|
|
56
|
-
{ field: 'name', defaultMessage: 'too short' },
|
|
57
|
-
],
|
|
58
|
-
};
|
|
59
|
-
expect(extractFieldErrors(error)).toHaveLength(2);
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
describe('flat object format', () => {
|
|
63
|
-
it('maps { field, message } directly', () => {
|
|
64
|
-
const error = { field: 'email', message: 'Invalid email' };
|
|
65
|
-
expect(extractFieldErrors(error)).toEqual([
|
|
66
|
-
{ field: 'email', message: 'Invalid email' },
|
|
67
|
-
]);
|
|
68
|
-
});
|
|
69
|
-
it('uses fallbackField when field is absent', () => {
|
|
70
|
-
const error = { message: 'Something went wrong' };
|
|
71
|
-
expect(extractFieldErrors(error, { fallbackField: 'root' })).toEqual([
|
|
72
|
-
{ field: 'root', message: 'Something went wrong' },
|
|
73
|
-
]);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
describe('flat array format', () => {
|
|
77
|
-
it('maps an array of { field, message } objects', () => {
|
|
78
|
-
const error = [
|
|
79
|
-
{ field: 'email', message: 'Invalid' },
|
|
80
|
-
{ field: 'name', message: 'Required' },
|
|
81
|
-
];
|
|
82
|
-
expect(extractFieldErrors(error)).toEqual([
|
|
83
|
-
{ field: 'email', message: 'Invalid' },
|
|
84
|
-
{ field: 'name', message: 'Required' },
|
|
85
|
-
]);
|
|
86
|
-
});
|
|
87
|
-
it('skips entries without a message', () => {
|
|
88
|
-
const error = [{ field: 'email' }, { field: 'name', message: 'Required' }];
|
|
89
|
-
expect(extractFieldErrors(error)).toEqual([
|
|
90
|
-
{ field: 'name', message: 'Required' },
|
|
91
|
-
]);
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
describe('Axios-style response wrapper', () => {
|
|
95
|
-
it('unwraps response.data before parsing', () => {
|
|
96
|
-
const error = {
|
|
97
|
-
response: {
|
|
98
|
-
data: { errors: { email: ['must not be blank'] } },
|
|
99
|
-
},
|
|
100
|
-
};
|
|
101
|
-
expect(extractFieldErrors(error)).toEqual([
|
|
102
|
-
{ field: 'email', message: 'must not be blank' },
|
|
103
|
-
]);
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
describe('unrecognized / unknown shapes', () => {
|
|
107
|
-
it('returns [] for an unrecognized object', () => {
|
|
108
|
-
expect(extractFieldErrors({ foo: 'bar' })).toEqual([]);
|
|
109
|
-
});
|
|
110
|
-
it('returns [] for null', () => {
|
|
111
|
-
expect(extractFieldErrors(null)).toEqual([]);
|
|
112
|
-
});
|
|
113
|
-
it('returns [] for undefined', () => {
|
|
114
|
-
expect(extractFieldErrors(undefined)).toEqual([]);
|
|
115
|
-
});
|
|
116
|
-
it('returns [] for a plain string', () => {
|
|
117
|
-
expect(extractFieldErrors('something went wrong')).toEqual([]);
|
|
118
|
-
});
|
|
119
|
-
it('never throws', () => {
|
|
120
|
-
expect(() => extractFieldErrors({ deeply: { nested: { evil: true } } })).not.toThrow();
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
describe('options', () => {
|
|
124
|
-
it('uses fallbackField for errors without a field name', () => {
|
|
125
|
-
const error = { message: 'Unauthorised' };
|
|
126
|
-
const result = extractFieldErrors(error, { fallbackField: 'serverError' });
|
|
127
|
-
expect(result).toEqual([{ field: 'serverError', message: 'Unauthorised' }]);
|
|
128
|
-
});
|
|
129
|
-
it('applies transformField to every resolved field name', () => {
|
|
130
|
-
const error = { errors: { emailAddress: ['invalid'] } };
|
|
131
|
-
const result = extractFieldErrors(error, {
|
|
132
|
-
transformField: (f) => f.replace(/([A-Z])/g, '.$1').toLowerCase(),
|
|
133
|
-
});
|
|
134
|
-
expect(result).toEqual([{ field: 'email.address', message: 'invalid' }]);
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
// ---------------------------------------------------------------------------
|
|
139
|
-
// mapApiErrors
|
|
140
|
-
// ---------------------------------------------------------------------------
|
|
141
|
-
describe('mapApiErrors', () => {
|
|
142
|
-
it('calls setError for each field error with type "server"', () => {
|
|
143
|
-
const setError = vi.fn();
|
|
144
|
-
const error = { errors: { email: ['must not be blank'], name: ['too short'] } };
|
|
145
|
-
mapApiErrors(error, setError);
|
|
146
|
-
expect(setError).toHaveBeenCalledTimes(2);
|
|
147
|
-
expect(setError).toHaveBeenCalledWith('email', { type: 'server', message: 'must not be blank' });
|
|
148
|
-
expect(setError).toHaveBeenCalledWith('name', { type: 'server', message: 'too short' });
|
|
149
|
-
});
|
|
150
|
-
it('never calls setError for unrecognized errors', () => {
|
|
151
|
-
const setError = vi.fn();
|
|
152
|
-
mapApiErrors({ foo: 'bar' }, setError);
|
|
153
|
-
expect(setError).not.toHaveBeenCalled();
|
|
154
|
-
});
|
|
155
|
-
it('never calls setError for null', () => {
|
|
156
|
-
const setError = vi.fn();
|
|
157
|
-
mapApiErrors(null, setError);
|
|
158
|
-
expect(setError).not.toHaveBeenCalled();
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
//# sourceMappingURL=index.test.js.map
|
package/dist/index.test.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE7D,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAChD,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,KAAK,GAAG,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,mBAAmB,CAAC,EAAE,EAAE,CAAA;YAC1D,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;gBACxC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE;aACjD,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;YAC9B,MAAM,KAAK,GAAG;gBACZ,MAAM,EAAE;oBACN,KAAK,EAAE,CAAC,mBAAmB,CAAC;oBAC5B,IAAI,EAAE,CAAC,WAAW,CAAC;iBACpB;aACF,CAAA;YACD,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;YACxC,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;YAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAA;YAC/E,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAA;QACxE,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;YACvE,MAAM,KAAK,GAAG,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,EAAE,EAAE,CAAA;YAC5E,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;gBACxC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE;gBAChD,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE;aAC9C,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,+CAA+C,EAAE,GAAG,EAAE;QAC7D,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,MAAM,KAAK,GAAG;gBACZ,MAAM,EAAE,GAAG;gBACX,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,CAAC;aAClE,CAAA;YACD,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;gBACxC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE;aACjD,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;YAC7D,MAAM,KAAK,GAAG;gBACZ,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC;aAC3D,CAAA;YACD,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;gBACxC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE;aACjD,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;YAC/B,MAAM,KAAK,GAAG;gBACZ,MAAM,EAAE;oBACN,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE;oBACvD,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE;iBAC/C;aACF,CAAA;YACD,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QACnD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,MAAM,KAAK,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,CAAA;YAC1D,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;gBACxC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE;aAC7C,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,MAAM,KAAK,GAAG,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAA;YACjD,MAAM,CAAC,kBAAkB,CAAC,KAAK,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;gBACnE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,EAAE;aACnD,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;YACrD,MAAM,KAAK,GAAG;gBACZ,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE;gBACtC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE;aACvC,CAAA;YACD,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;gBACxC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE;gBACtC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE;aACvC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,KAAK,GAAG,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAA;YAC1E,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;gBACxC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE;aACvC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;QAC5C,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,KAAK,GAAG;gBACZ,QAAQ,EAAE;oBACR,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,mBAAmB,CAAC,EAAE,EAAE;iBACnD;aACF,CAAA;YACD,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;gBACxC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE;aACjD,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;QAC7C,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;YAC/C,MAAM,CAAC,kBAAkB,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACxD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;YAC7B,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAC9C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;YAClC,MAAM,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACnD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;YACvC,MAAM,CAAC,kBAAkB,CAAC,sBAAsB,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAChE,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE;YACtB,MAAM,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAA;QACxF,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;QACvB,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC5D,MAAM,KAAK,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,CAAA;YACzC,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC,CAAA;YAC1E,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC,CAAA;QAC7E,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;YAC7D,MAAM,KAAK,GAAG,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,CAAA;YACvD,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE;gBACvC,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE;aAClE,CAAC,CAAA;YACF,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,CAAA;QAC1E,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAE9E,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;QACxB,MAAM,KAAK,GAAG,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,mBAAmB,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,CAAA;QAC/E,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;QAC7B,MAAM,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAA;QACzC,MAAM,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAA;QAChG,MAAM,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAA;IACzF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;QACxB,YAAY,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,QAAQ,CAAC,CAAA;QACtC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAA;IACzC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;QACxB,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;QAC5B,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAA;IACzC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|