@jfdevelops/create-error 0.1.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/LICENSE +21 -0
- package/README.md +294 -0
- package/dist/create-error.cjs +135 -0
- package/dist/create-error.cjs.map +1 -0
- package/dist/create-error.d.cts +101 -0
- package/dist/create-error.d.cts.map +1 -0
- package/dist/create-error.d.mts +101 -0
- package/dist/create-error.d.mts.map +1 -0
- package/dist/create-error.mjs +134 -0
- package/dist/create-error.mjs.map +1 -0
- package/dist/index.cjs +3 -0
- package/dist/index.d.cts +3 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.mjs +3 -0
- package/dist/types.d.cts +291 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +291 -0
- package/dist/types.d.mts.map +1 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Joey F.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# @jfdevelops/create-error
|
|
2
|
+
|
|
3
|
+
Create strongly typed, configurable error families from any synchronous
|
|
4
|
+
[Standard Schema](https://standardschema.dev/schema) object.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
pnpm add @jfdevelops/create-error
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Bring your own Standard Schema-compatible validation library, such as Zod,
|
|
13
|
+
Valibot, or ArkType. `create-error` does not bundle one.
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createError } from '@jfdevelops/create-error';
|
|
19
|
+
import { z } from 'zod';
|
|
20
|
+
|
|
21
|
+
const createFormError = createError({
|
|
22
|
+
definition: z.object({
|
|
23
|
+
code: z.string(),
|
|
24
|
+
scope: z.string(),
|
|
25
|
+
}),
|
|
26
|
+
data: {
|
|
27
|
+
property: 'context',
|
|
28
|
+
resolve({ definition, input }) {
|
|
29
|
+
return { ...input, scope: definition.scope };
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
message({ definition, data, implementation }) {
|
|
33
|
+
return implementation({
|
|
34
|
+
context: data,
|
|
35
|
+
scope: definition.scope,
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
properties({ definition, data, implementation }) {
|
|
39
|
+
return {
|
|
40
|
+
code: definition.code,
|
|
41
|
+
scope: definition.scope,
|
|
42
|
+
context: data,
|
|
43
|
+
renderMessage(renderer = implementation) {
|
|
44
|
+
return renderer({
|
|
45
|
+
context: data,
|
|
46
|
+
scope: definition.scope,
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
toJSON(error) {
|
|
52
|
+
return {
|
|
53
|
+
name: error.name,
|
|
54
|
+
code: error.code,
|
|
55
|
+
scope: error.scope,
|
|
56
|
+
message: error.message,
|
|
57
|
+
context: error.context,
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export const FormError = createFormError.Error;
|
|
63
|
+
|
|
64
|
+
export class InvalidFieldError extends createFormError({
|
|
65
|
+
code: 'invalidField',
|
|
66
|
+
scope: 'field',
|
|
67
|
+
})
|
|
68
|
+
.defineContext(
|
|
69
|
+
z.object({
|
|
70
|
+
field: z.string(),
|
|
71
|
+
scope: z.literal('field'),
|
|
72
|
+
}),
|
|
73
|
+
)
|
|
74
|
+
.implement(
|
|
75
|
+
({ code, context }) => `${code}: ${context.field} is invalid`,
|
|
76
|
+
) {}
|
|
77
|
+
|
|
78
|
+
const error = new InvalidFieldError({ field: 'email' });
|
|
79
|
+
|
|
80
|
+
error.code; // "invalidField"
|
|
81
|
+
error.scope; // "field"
|
|
82
|
+
error.context; // { field: string; scope: "field" }
|
|
83
|
+
error instanceof Error; // true
|
|
84
|
+
error instanceof FormError; // true
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
No explicit generic arguments or `as const` assertions are needed. Definition
|
|
88
|
+
inputs are checked by the schema, and definition-derived fields use its parsed
|
|
89
|
+
output type so transformations remain type-safe.
|
|
90
|
+
|
|
91
|
+
For reusable or separately declared configurations, the package exports a
|
|
92
|
+
common `CreateErrorConfig` type:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { createError, type CreateErrorConfig } from '@jfdevelops/create-error';
|
|
96
|
+
|
|
97
|
+
const definition = z.object({ code: z.string() });
|
|
98
|
+
|
|
99
|
+
const config = {
|
|
100
|
+
definition,
|
|
101
|
+
data: {
|
|
102
|
+
property: 'context',
|
|
103
|
+
resolve: ({ input }) => input,
|
|
104
|
+
},
|
|
105
|
+
message: ({ data, implementation }) => implementation(data),
|
|
106
|
+
} satisfies CreateErrorConfig<typeof definition>;
|
|
107
|
+
|
|
108
|
+
const createDomainError = createError(config);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## How the factory works
|
|
112
|
+
|
|
113
|
+
The API has four stages:
|
|
114
|
+
|
|
115
|
+
1. `createError(blueprint)` configures a family and returns a factory.
|
|
116
|
+
2. `factory(definition)` validates and captures one definition.
|
|
117
|
+
3. The returned builder optionally selects a context schema with
|
|
118
|
+
`defineContext(schema)`.
|
|
119
|
+
4. `implement(callback)` captures the implementation and produces an
|
|
120
|
+
extendable concrete error class.
|
|
121
|
+
|
|
122
|
+
The definition builder exposes both `defineContext` and `implement`.
|
|
123
|
+
`defineContext` returns a narrower builder that exposes only `implement`, so a
|
|
124
|
+
context schema can be selected only once. Calling `implement` directly keeps
|
|
125
|
+
context schemas optional. Every implementation receives exactly one argument;
|
|
126
|
+
the blueprint decides its shape when it calls `implementation(argument)`. When
|
|
127
|
+
that argument is a constructed object, the concrete definition fields are added
|
|
128
|
+
automatically, so implementations can read values such as `code` without the
|
|
129
|
+
blueprint repeating them. Forwarding opaque data directly preserves its original
|
|
130
|
+
scalar, tuple, object, or class-instance shape.
|
|
131
|
+
|
|
132
|
+
The `definition` option must implement Standard Schema V1 and must produce an
|
|
133
|
+
object. Validation runs when `factory(definition)` is called. Because class
|
|
134
|
+
creation is synchronous, a schema whose `validate` method returns a promise is
|
|
135
|
+
rejected with a `TypeError`.
|
|
136
|
+
|
|
137
|
+
## What `data` and `properties` do
|
|
138
|
+
|
|
139
|
+
`data` defines the constructor-input lifecycle. Its `resolve` callback receives
|
|
140
|
+
the concrete definition and the value passed to `new ErrorClass(input)`. The
|
|
141
|
+
callback can preserve that input, normalize it, or combine it with definition
|
|
142
|
+
values. After optional `defineContext` validation, the final value is stored on
|
|
143
|
+
the instance using `data.property`.
|
|
144
|
+
|
|
145
|
+
`properties` defines the rest of the instance API. It can expose definition
|
|
146
|
+
values such as a stable error code, derive fields from the resolved data, or add
|
|
147
|
+
methods and getters. It does not participate in input validation or
|
|
148
|
+
transformation.
|
|
149
|
+
|
|
150
|
+
For a small error family, the constructor input can pass straight through and
|
|
151
|
+
`properties` can be omitted entirely:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
const createLookupError = createError({
|
|
155
|
+
definition: z.object({ code: z.string() }),
|
|
156
|
+
data: {
|
|
157
|
+
property: 'resourceId',
|
|
158
|
+
resolve: ({ input }) => input,
|
|
159
|
+
},
|
|
160
|
+
message: ({ data, implementation }) => implementation(data),
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
class MissingUserError extends createLookupError({ code: 'missingUser' })
|
|
164
|
+
.defineContext(z.string())
|
|
165
|
+
.implement((resourceId) => `User ${resourceId} was not found`) {}
|
|
166
|
+
|
|
167
|
+
const error = new MissingUserError('user_123');
|
|
168
|
+
error.resourceId; // string
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Use both options when constructor input needs normalization and the error should
|
|
172
|
+
present a richer public API:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
const createValidationError = createError({
|
|
176
|
+
definition: z.object({
|
|
177
|
+
code: z.string(),
|
|
178
|
+
section: z.string(),
|
|
179
|
+
}),
|
|
180
|
+
data: {
|
|
181
|
+
property: 'context',
|
|
182
|
+
resolve: ({ definition, input }) => ({
|
|
183
|
+
...input,
|
|
184
|
+
section: definition.section,
|
|
185
|
+
}),
|
|
186
|
+
},
|
|
187
|
+
message: ({ data, implementation }) => implementation(data),
|
|
188
|
+
properties: ({ definition, data }) => ({
|
|
189
|
+
code: definition.code,
|
|
190
|
+
section: definition.section,
|
|
191
|
+
describe: () => `${definition.code} in ${data.section}`,
|
|
192
|
+
}),
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
class InvalidEmailError extends createValidationError({
|
|
196
|
+
code: 'invalidEmail',
|
|
197
|
+
section: 'profile',
|
|
198
|
+
})
|
|
199
|
+
.defineContext(
|
|
200
|
+
z.object({
|
|
201
|
+
field: z.string(),
|
|
202
|
+
section: z.literal('profile'),
|
|
203
|
+
}),
|
|
204
|
+
)
|
|
205
|
+
.implement(({ field }) => `${field} is invalid`) {}
|
|
206
|
+
|
|
207
|
+
const error = new InvalidEmailError({ field: 'email' });
|
|
208
|
+
error.context; // { field: string; section: "profile" }
|
|
209
|
+
error.code; // "invalidEmail"
|
|
210
|
+
error.describe(); // "invalidEmail in profile"
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Use schema-native restrictions when definitions have a closed set of values:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
const createHttpError = createError({
|
|
217
|
+
definition: z.object({
|
|
218
|
+
code: z.enum(['notFound', 'unauthorized']),
|
|
219
|
+
scope: z.literal('request'),
|
|
220
|
+
}),
|
|
221
|
+
data: {
|
|
222
|
+
property: 'details',
|
|
223
|
+
resolve: ({ input }) => input,
|
|
224
|
+
},
|
|
225
|
+
message: ({ implementation, data }) => implementation(data),
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const NotFoundError = createHttpError({
|
|
229
|
+
code: 'notFound',
|
|
230
|
+
scope: 'request',
|
|
231
|
+
})
|
|
232
|
+
.defineContext(z.object({ resource: z.string() }))
|
|
233
|
+
.implement((details) => `${details.resource} was not found`);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Data and behavior
|
|
237
|
+
|
|
238
|
+
`data.resolve` can return any value: objects, scalars, tuples, unions, class
|
|
239
|
+
instances, `null`, and `undefined` are all supported. When `defineContext` is
|
|
240
|
+
used, its Standard Schema validates the resolved data, its input type determines
|
|
241
|
+
the concrete error constructor input, and its output type is passed to the
|
|
242
|
+
implementation and stored on the error. Without a context schema, the last
|
|
243
|
+
parameter of the consumer implementation determines those types.
|
|
244
|
+
|
|
245
|
+
For each new error instance, callbacks run in this order:
|
|
246
|
+
|
|
247
|
+
1. `data.resolve`
|
|
248
|
+
2. Context validation and transformation, when configured
|
|
249
|
+
3. `message`
|
|
250
|
+
4. `properties`, when configured
|
|
251
|
+
|
|
252
|
+
Exceptions thrown by a schema or callback are not wrapped. Native `Error`
|
|
253
|
+
behavior is preserved, including stack traces, subclass names, prototypes, and
|
|
254
|
+
the optional `cause` passed as the second constructor argument.
|
|
255
|
+
|
|
256
|
+
Every family exposes its shared base as `factory.Error`. Concrete classes and
|
|
257
|
+
named subclasses also inherit a lazy invariant helper:
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
InvalidFieldError.invariant(
|
|
261
|
+
formIsValid,
|
|
262
|
+
() => ({ field: 'email' }),
|
|
263
|
+
{ cause },
|
|
264
|
+
);
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
The input function runs only when the condition is falsy.
|
|
268
|
+
|
|
269
|
+
When `toJSON` is configured, it is installed once on the family prototype and
|
|
270
|
+
used by `JSON.stringify`. Its callback can read native error fields, configured
|
|
271
|
+
properties, and the resolved data property; each concrete error's `toJSON()`
|
|
272
|
+
return type preserves parsed definition output and context-schema output. When
|
|
273
|
+
omitted, the family does not add a `toJSON` method.
|
|
274
|
+
|
|
275
|
+
## Property safety
|
|
276
|
+
|
|
277
|
+
`properties` may add fields, methods, getters, symbols, and other own property
|
|
278
|
+
descriptors. It cannot replace `name`, `message`, `stack`, `cause`,
|
|
279
|
+
`constructor`, or `prototype`. The configured data property may only be
|
|
280
|
+
repeated with the exact resolved value. Collisions throw a `TypeError`.
|
|
281
|
+
|
|
282
|
+
The library always creates the family base class. Customize a family through
|
|
283
|
+
the blueprint instead of supplying a separate `BaseError`.
|
|
284
|
+
|
|
285
|
+
## Releasing
|
|
286
|
+
|
|
287
|
+
This project uses Changesets for versioning and changelogs. Add a changeset
|
|
288
|
+
with `pnpm changeset` whenever a package change should be released. Maintainers
|
|
289
|
+
can consume pending changesets with `pnpm version-packages`, review the updated
|
|
290
|
+
version and changelog, then publish with `pnpm release`.
|
|
291
|
+
|
|
292
|
+
## License
|
|
293
|
+
|
|
294
|
+
MIT
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/create-error.ts
|
|
3
|
+
const protectedPropertyNames = new Set([
|
|
4
|
+
"name",
|
|
5
|
+
"message",
|
|
6
|
+
"stack",
|
|
7
|
+
"cause",
|
|
8
|
+
"constructor",
|
|
9
|
+
"prototype"
|
|
10
|
+
]);
|
|
11
|
+
function isObjectLike(value) {
|
|
12
|
+
return value !== null && (typeof value === "object" || typeof value === "function");
|
|
13
|
+
}
|
|
14
|
+
function isPlainObject(value) {
|
|
15
|
+
if (!isObjectLike(value)) return false;
|
|
16
|
+
const prototype = Object.getPrototypeOf(value);
|
|
17
|
+
return prototype === Object.prototype || prototype === null;
|
|
18
|
+
}
|
|
19
|
+
function includeDefinition(argument, definition) {
|
|
20
|
+
if (!isPlainObject(argument)) return argument;
|
|
21
|
+
return {
|
|
22
|
+
...definition,
|
|
23
|
+
...argument
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function validateStandardSchema(schema, subject) {
|
|
27
|
+
if (!isObjectLike(schema)) throw new TypeError(`${subject} must be a Standard Schema object`);
|
|
28
|
+
const standard = Reflect.get(schema, "~standard");
|
|
29
|
+
if (!isObjectLike(standard) || Reflect.get(standard, "version") !== 1 || typeof Reflect.get(standard, "vendor") !== "string" || typeof Reflect.get(standard, "validate") !== "function") throw new TypeError(`${subject} must implement Standard Schema V1`);
|
|
30
|
+
}
|
|
31
|
+
function validateBlueprint(config) {
|
|
32
|
+
validateStandardSchema(config.definition, "definition");
|
|
33
|
+
if (typeof config.data.property !== "string" || config.data.property.length === 0) throw new TypeError("data.property must be a non-empty string");
|
|
34
|
+
if (protectedPropertyNames.has(config.data.property)) throw new TypeError(`data.property cannot overwrite protected property "${config.data.property}"`);
|
|
35
|
+
}
|
|
36
|
+
function formatIssuePath(path) {
|
|
37
|
+
if (!path?.length) return "";
|
|
38
|
+
return `${path.map((segment) => typeof segment === "object" ? segment.key : segment).map(String).join(".")}: `;
|
|
39
|
+
}
|
|
40
|
+
function parseSchema(schema, input, subject) {
|
|
41
|
+
const result = schema["~standard"].validate(input);
|
|
42
|
+
if (result instanceof Promise) throw new TypeError(`${subject} schema validation must be synchronous`);
|
|
43
|
+
if (result.issues) {
|
|
44
|
+
const details = result.issues.map((issue) => `${formatIssuePath(issue.path)}${issue.message}`).join("; ");
|
|
45
|
+
throw new TypeError(`Invalid error ${subject}: ${details}`);
|
|
46
|
+
}
|
|
47
|
+
return result.value;
|
|
48
|
+
}
|
|
49
|
+
function parseDefinition(schema, definition) {
|
|
50
|
+
const parsedDefinition = parseSchema(schema, definition, "definition");
|
|
51
|
+
if (!isObjectLike(parsedDefinition)) throw new TypeError("definition schema must produce an object");
|
|
52
|
+
return parsedDefinition;
|
|
53
|
+
}
|
|
54
|
+
function assignProperties(error, properties, dataProperty, data) {
|
|
55
|
+
for (const key of Reflect.ownKeys(properties)) {
|
|
56
|
+
if (typeof key === "string" && protectedPropertyNames.has(key)) throw new TypeError(`Cannot overwrite protected error property "${key}"`);
|
|
57
|
+
const descriptor = Object.getOwnPropertyDescriptor(properties, key);
|
|
58
|
+
if (!descriptor) continue;
|
|
59
|
+
if (key === dataProperty && (!("value" in descriptor) || descriptor.value !== data)) throw new TypeError(`Cannot overwrite resolved data property "${dataProperty}"`);
|
|
60
|
+
Object.defineProperty(error, key, descriptor);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function createError(config) {
|
|
64
|
+
validateBlueprint(config);
|
|
65
|
+
class FamilyError extends Error {
|
|
66
|
+
static invariant(condition, input, options) {
|
|
67
|
+
if (condition) return;
|
|
68
|
+
const resolvedInput = typeof input === "function" ? input() : input;
|
|
69
|
+
throw new this(resolvedInput, options);
|
|
70
|
+
}
|
|
71
|
+
constructor(message, options) {
|
|
72
|
+
super(message, options);
|
|
73
|
+
const name = new.target.name;
|
|
74
|
+
if (name) this.name = name;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (config.toJSON) Object.defineProperty(FamilyError.prototype, "toJSON", {
|
|
78
|
+
configurable: true,
|
|
79
|
+
value: function toJSON() {
|
|
80
|
+
return config.toJSON?.(this);
|
|
81
|
+
},
|
|
82
|
+
writable: true
|
|
83
|
+
});
|
|
84
|
+
function createDefinition(definition) {
|
|
85
|
+
const parsedDefinition = parseDefinition(config.definition, definition);
|
|
86
|
+
function createImplementation(implementation, contextSchema) {
|
|
87
|
+
return class extends FamilyError {
|
|
88
|
+
constructor(input, options) {
|
|
89
|
+
const resolvedData = config.data.resolve({
|
|
90
|
+
definition: parsedDefinition,
|
|
91
|
+
input
|
|
92
|
+
});
|
|
93
|
+
const data = contextSchema ? parseSchema(contextSchema, resolvedData, "context") : resolvedData;
|
|
94
|
+
const implementationWithDefinition = (argument) => implementation(argument === data ? argument : includeDefinition(argument, parsedDefinition));
|
|
95
|
+
const message = config.message({
|
|
96
|
+
data,
|
|
97
|
+
definition: parsedDefinition,
|
|
98
|
+
implementation: implementationWithDefinition
|
|
99
|
+
});
|
|
100
|
+
super(message, options);
|
|
101
|
+
Object.defineProperty(this, config.data.property, {
|
|
102
|
+
configurable: true,
|
|
103
|
+
enumerable: true,
|
|
104
|
+
value: data,
|
|
105
|
+
writable: true
|
|
106
|
+
});
|
|
107
|
+
const properties = config.properties?.({
|
|
108
|
+
data,
|
|
109
|
+
definition: parsedDefinition,
|
|
110
|
+
implementation: implementationWithDefinition
|
|
111
|
+
});
|
|
112
|
+
if (properties) assignProperties(this, properties, config.data.property, data);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function implement(implementation) {
|
|
117
|
+
return createImplementation(implementation);
|
|
118
|
+
}
|
|
119
|
+
function defineContext(contextSchema) {
|
|
120
|
+
validateStandardSchema(contextSchema, "context");
|
|
121
|
+
return { implement(implementation) {
|
|
122
|
+
return createImplementation(implementation, contextSchema);
|
|
123
|
+
} };
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
defineContext,
|
|
127
|
+
implement
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
return Object.assign(createDefinition, { Error: FamilyError });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
//#endregion
|
|
134
|
+
exports.createError = createError;
|
|
135
|
+
//# sourceMappingURL=create-error.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-error.cjs","names":["implementationWithDefinition: RuntimeImplementation"],"sources":["../src/create-error.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec';\r\n\r\nimport type {\r\n BlueprintContext,\r\n BlueprintErrorTemplate,\r\n CreateErrorConfig,\r\n ErrorFamilyFactory,\r\n} from './types.js';\r\n\r\ntype RuntimeImplementation = (argument: unknown) => string;\r\n\r\ntype ErrorConfigBody<\r\n Schema extends StandardSchemaV1,\r\n DataConfig extends CreateErrorConfig<Schema>['data'],\r\n MessageCallback extends CreateErrorConfig<Schema>['message'],\r\n> = {\r\n data: DataConfig;\r\n message: MessageCallback;\r\n};\r\n\r\ntype ErrorConfigWithProperties<\r\n Schema extends StandardSchemaV1,\r\n DataConfig extends CreateErrorConfig<Schema>['data'],\r\n MessageCallback extends CreateErrorConfig<Schema>['message'],\r\n Properties extends object,\r\n> = ErrorConfigBody<Schema, DataConfig, MessageCallback> & {\r\n properties(context: BlueprintContext<Schema>): Properties;\r\n};\r\n\r\ntype ErrorConfigWithoutProperties<\r\n Schema extends StandardSchemaV1,\r\n DataConfig extends CreateErrorConfig<Schema>['data'],\r\n MessageCallback extends CreateErrorConfig<Schema>['message'],\r\n> = ErrorConfigBody<Schema, DataConfig, MessageCallback> & {\r\n properties?: never;\r\n};\r\n\r\ntype ExactCreateErrorConfig<\r\n Schema extends StandardSchemaV1,\r\n Config extends object,\r\n> = {\r\n definition: Schema;\r\n} & Config &\r\n (StandardSchemaV1.InferOutput<Schema> extends object\r\n ? unknown\r\n : { definition: never });\r\n\r\ntype SerializedCreateErrorConfig<\r\n Schema extends StandardSchemaV1,\r\n Config extends object,\r\n Json,\r\n> = ExactCreateErrorConfig<\r\n Schema,\r\n Config & {\r\n toJSON(error: BlueprintErrorTemplate<NoInfer<Config>>): Json;\r\n }\r\n>;\r\n\r\nconst protectedPropertyNames = new Set([\r\n 'name',\r\n 'message',\r\n 'stack',\r\n 'cause',\r\n 'constructor',\r\n 'prototype',\r\n]);\r\n\r\nfunction isObjectLike(value: unknown): value is object {\r\n return (\r\n value !== null && (typeof value === 'object' || typeof value === 'function')\r\n );\r\n}\r\n\r\nfunction isPlainObject(value: unknown): value is Record<PropertyKey, unknown> {\r\n if (!isObjectLike(value)) {\r\n return false;\r\n }\r\n\r\n const prototype = Object.getPrototypeOf(value);\r\n\r\n return prototype === Object.prototype || prototype === null;\r\n}\r\n\r\nfunction includeDefinition(\r\n argument: unknown,\r\n definition: object,\r\n): unknown {\r\n if (!isPlainObject(argument)) {\r\n return argument;\r\n }\r\n\r\n return { ...definition, ...argument };\r\n}\r\n\r\nfunction validateStandardSchema(schema: unknown, subject: string) {\r\n if (!isObjectLike(schema)) {\r\n throw new TypeError(`${subject} must be a Standard Schema object`);\r\n }\r\n\r\n const standard = Reflect.get(schema, '~standard') as unknown;\r\n\r\n if (\r\n !isObjectLike(standard) ||\r\n Reflect.get(standard, 'version') !== 1 ||\r\n typeof Reflect.get(standard, 'vendor') !== 'string' ||\r\n typeof Reflect.get(standard, 'validate') !== 'function'\r\n ) {\r\n throw new TypeError(`${subject} must implement Standard Schema V1`);\r\n }\r\n}\r\n\r\nfunction validateBlueprint(config: CreateErrorConfig<StandardSchemaV1>) {\r\n validateStandardSchema(config.definition, 'definition');\r\n\r\n if (\r\n typeof config.data.property !== 'string' ||\r\n config.data.property.length === 0\r\n ) {\r\n throw new TypeError('data.property must be a non-empty string');\r\n }\r\n\r\n if (protectedPropertyNames.has(config.data.property)) {\r\n throw new TypeError(\r\n `data.property cannot overwrite protected property \"${config.data.property}\"`,\r\n );\r\n }\r\n}\r\n\r\nfunction formatIssuePath(path: StandardSchemaV1.Issue['path']) {\r\n if (!path?.length) {\r\n return '';\r\n }\r\n\r\n const keys = path.map((segment) =>\r\n typeof segment === 'object' ? segment.key : segment,\r\n );\r\n\r\n return `${keys.map(String).join('.')}: `;\r\n}\r\n\r\nfunction parseSchema<Schema extends StandardSchemaV1>(\r\n schema: Schema,\r\n input: StandardSchemaV1.InferInput<Schema>,\r\n subject: string,\r\n) {\r\n const result = schema['~standard'].validate(input);\r\n\r\n if (result instanceof Promise) {\r\n throw new TypeError(`${subject} schema validation must be synchronous`);\r\n }\r\n\r\n if (result.issues) {\r\n const details = result.issues\r\n .map((issue) => `${formatIssuePath(issue.path)}${issue.message}`)\r\n .join('; ');\r\n\r\n throw new TypeError(`Invalid error ${subject}: ${details}`);\r\n }\r\n\r\n return result.value;\r\n}\r\n\r\nfunction parseDefinition<Schema extends StandardSchemaV1>(\r\n schema: Schema,\r\n definition: StandardSchemaV1.InferInput<Schema>,\r\n) {\r\n const parsedDefinition = parseSchema(schema, definition, 'definition');\r\n\r\n if (!isObjectLike(parsedDefinition)) {\r\n throw new TypeError('definition schema must produce an object');\r\n }\r\n\r\n return parsedDefinition;\r\n}\r\n\r\nfunction assignProperties(\r\n error: Error & Record<string, unknown>,\r\n properties: object,\r\n dataProperty: string,\r\n data: unknown,\r\n) {\r\n for (const key of Reflect.ownKeys(properties)) {\r\n if (typeof key === 'string' && protectedPropertyNames.has(key)) {\r\n throw new TypeError(`Cannot overwrite protected error property \"${key}\"`);\r\n }\r\n\r\n const descriptor = Object.getOwnPropertyDescriptor(properties, key);\r\n\r\n if (!descriptor) {\r\n continue;\r\n }\r\n\r\n if (\r\n key === dataProperty &&\r\n (!('value' in descriptor) || descriptor.value !== data)\r\n ) {\r\n throw new TypeError(`Cannot overwrite resolved data property \"${dataProperty}\"`);\r\n }\r\n\r\n Object.defineProperty(error, key, descriptor);\r\n }\r\n}\r\n\r\n/**\r\n * Creates an error family with additional instance properties and typed JSON\r\n * serialization.\r\n *\r\n * @param config Defines the family, its public properties, and its serialized\r\n * representation.\r\n * @returns A callable factory with a shared `.Error` base class.\r\n *\r\n * @example\r\n * ```ts\r\n * const createApiError = createError({\r\n * definition: z.object({ code: z.string() }),\r\n * data: {\r\n * property: 'context',\r\n * resolve: ({ input }) => input,\r\n * },\r\n * message: ({ data, implementation }) => implementation(data),\r\n * properties: ({ definition }) => ({ code: definition.code }),\r\n * toJSON: (error) => ({\r\n * code: error.code,\r\n * context: error.context,\r\n * message: error.message,\r\n * }),\r\n * });\r\n * ```\r\n */\r\nexport function createError<\r\n const Schema extends StandardSchemaV1,\r\n const DataConfig extends CreateErrorConfig<Schema>['data'],\r\n const MessageCallback extends CreateErrorConfig<Schema>['message'],\r\n const Properties extends object,\r\n Json,\r\n>(\r\n config: SerializedCreateErrorConfig<\r\n Schema,\r\n ErrorConfigWithProperties<\r\n Schema,\r\n DataConfig,\r\n MessageCallback,\r\n Properties\r\n >,\r\n Json\r\n >,\r\n): ErrorFamilyFactory<Schema, typeof config>;\r\n\r\n/**\r\n * Creates an error family with typed JSON serialization and no additional\r\n * instance properties.\r\n *\r\n * @param config Defines the family and its serialized representation.\r\n * @returns A callable factory with a shared `.Error` base class.\r\n *\r\n * @example\r\n * ```ts\r\n * const createLogError = createError({\r\n * definition: z.object({ code: z.string() }),\r\n * data: {\r\n * property: 'details',\r\n * resolve: ({ input }) => input,\r\n * },\r\n * message: ({ data, implementation }) => implementation(data),\r\n * toJSON: (error) => ({\r\n * details: error.details,\r\n * message: error.message,\r\n * }),\r\n * });\r\n * ```\r\n */\r\nexport function createError<\r\n const Schema extends StandardSchemaV1,\r\n const DataConfig extends CreateErrorConfig<Schema>['data'],\r\n const MessageCallback extends CreateErrorConfig<Schema>['message'],\r\n Json,\r\n>(\r\n config: SerializedCreateErrorConfig<\r\n Schema,\r\n ErrorConfigWithoutProperties<Schema, DataConfig, MessageCallback>,\r\n Json\r\n >,\r\n): ErrorFamilyFactory<Schema, typeof config>;\r\n\r\n/**\r\n * Creates a configurable family of strongly typed error classes.\r\n *\r\n * Callback execution order is `data.resolve`, optional context validation,\r\n * `message`, then `properties`. Parsed definition output and constructor data\r\n * are inferred without explicit generic arguments or `as const`.\r\n *\r\n * @param config Defines the family's schema, data lifecycle, message, and\r\n * optional public properties.\r\n * @returns A callable factory with a shared `.Error` base class.\r\n *\r\n * @example\r\n * ```ts\r\n * const createRequestError = createError({\r\n * definition: z.object({ code: z.string() }),\r\n * data: {\r\n * property: 'context',\r\n * resolve: ({ input }) => input,\r\n * },\r\n * message: ({ data, implementation }) => implementation(data),\r\n * properties: ({ definition }) => ({ code: definition.code }),\r\n * });\r\n * ```\r\n */\r\nexport function createError<\r\n const Schema extends StandardSchemaV1,\r\n const Config extends Omit<CreateErrorConfig<Schema>, 'definition'>,\r\n>(\r\n config: ExactCreateErrorConfig<Schema, Config>,\r\n): ErrorFamilyFactory<Schema, typeof config>;\r\nexport function createError<\r\n const Schema extends StandardSchemaV1,\r\n const Config extends Omit<CreateErrorConfig<Schema>, 'definition'>,\r\n>(\r\n config: ExactCreateErrorConfig<Schema, Config>,\r\n): ErrorFamilyFactory<Schema, typeof config> {\r\n validateBlueprint(config as CreateErrorConfig<StandardSchemaV1>);\r\n\r\n class FamilyError extends Error {\r\n static invariant<Condition, Input>(\r\n this: new (input: Input, options?: ErrorOptions) => Error,\r\n condition: Condition,\r\n input: Input | (() => Input),\r\n options?: ErrorOptions,\r\n ): asserts condition {\r\n if (condition) {\r\n return;\r\n }\r\n\r\n const resolvedInput =\r\n typeof input === 'function' ? (input as () => Input)() : input;\r\n\r\n throw new this(resolvedInput, options);\r\n }\r\n\r\n constructor(message: string, options?: ErrorOptions) {\r\n super(message, options);\r\n const name = new.target.name;\r\n if (name) {\r\n this.name = name;\r\n }\r\n }\r\n }\r\n\r\n if (config.toJSON) {\r\n Object.defineProperty(FamilyError.prototype, 'toJSON', {\r\n configurable: true,\r\n value: function toJSON(this: Error & Record<string, unknown>) {\r\n return config.toJSON?.(this as never);\r\n },\r\n writable: true,\r\n });\r\n }\r\n\r\n function createDefinition<\r\n const Definition extends StandardSchemaV1.InferInput<Schema>,\r\n >(definition: Definition) {\r\n const parsedDefinition = parseDefinition(config.definition, definition);\r\n\r\n function createImplementation(\r\n implementation: RuntimeImplementation,\r\n contextSchema?: StandardSchemaV1,\r\n ) {\r\n return class extends FamilyError {\r\n constructor(input: unknown, options?: ErrorOptions) {\r\n const resolvedData = config.data.resolve({\r\n definition: parsedDefinition,\r\n input,\r\n } as never);\r\n const data = contextSchema\r\n ? parseSchema(contextSchema, resolvedData, 'context')\r\n : resolvedData;\r\n const implementationWithDefinition: RuntimeImplementation = (\r\n argument,\r\n ) =>\r\n implementation(\r\n argument === data\r\n ? argument\r\n : includeDefinition(argument, parsedDefinition),\r\n );\r\n const message = config.message({\r\n data,\r\n definition: parsedDefinition,\r\n implementation: implementationWithDefinition,\r\n } as never);\r\n\r\n super(message, options);\r\n\r\n Object.defineProperty(this, config.data.property, {\r\n configurable: true,\r\n enumerable: true,\r\n value: data,\r\n writable: true,\r\n });\r\n\r\n const properties = config.properties?.({\r\n data,\r\n definition: parsedDefinition,\r\n implementation: implementationWithDefinition,\r\n } as never);\r\n\r\n if (properties) {\r\n assignProperties(\r\n this as Error & Record<string, unknown>,\r\n properties,\r\n config.data.property,\r\n data,\r\n );\r\n }\r\n }\r\n };\r\n }\r\n\r\n function implement(implementation: RuntimeImplementation) {\r\n return createImplementation(implementation);\r\n }\r\n\r\n function defineContext<ContextSchema extends StandardSchemaV1>(\r\n contextSchema: ContextSchema,\r\n ) {\r\n validateStandardSchema(contextSchema, 'context');\r\n\r\n return {\r\n implement(implementation: RuntimeImplementation) {\r\n return createImplementation(implementation, contextSchema);\r\n },\r\n };\r\n }\r\n\r\n return {\r\n defineContext,\r\n implement,\r\n };\r\n }\r\n\r\n return Object.assign(createDefinition, {\r\n Error: FamilyError,\r\n }) as unknown as ErrorFamilyFactory<Schema, typeof config>;\r\n}\r\n"],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { BlueprintContext, BlueprintErrorTemplate, CreateErrorConfig, ErrorFamilyFactory } from "./types.cjs";
|
|
2
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
+
|
|
4
|
+
//#region src/create-error.d.ts
|
|
5
|
+
type ErrorConfigBody<Schema extends StandardSchemaV1, DataConfig extends CreateErrorConfig<Schema>['data'], MessageCallback extends CreateErrorConfig<Schema>['message']> = {
|
|
6
|
+
data: DataConfig;
|
|
7
|
+
message: MessageCallback;
|
|
8
|
+
};
|
|
9
|
+
type ErrorConfigWithProperties<Schema extends StandardSchemaV1, DataConfig extends CreateErrorConfig<Schema>['data'], MessageCallback extends CreateErrorConfig<Schema>['message'], Properties extends object> = ErrorConfigBody<Schema, DataConfig, MessageCallback> & {
|
|
10
|
+
properties(context: BlueprintContext<Schema>): Properties;
|
|
11
|
+
};
|
|
12
|
+
type ErrorConfigWithoutProperties<Schema extends StandardSchemaV1, DataConfig extends CreateErrorConfig<Schema>['data'], MessageCallback extends CreateErrorConfig<Schema>['message']> = ErrorConfigBody<Schema, DataConfig, MessageCallback> & {
|
|
13
|
+
properties?: never;
|
|
14
|
+
};
|
|
15
|
+
type ExactCreateErrorConfig<Schema extends StandardSchemaV1, Config extends object> = {
|
|
16
|
+
definition: Schema;
|
|
17
|
+
} & Config & (StandardSchemaV1.InferOutput<Schema> extends object ? unknown : {
|
|
18
|
+
definition: never;
|
|
19
|
+
});
|
|
20
|
+
type SerializedCreateErrorConfig<Schema extends StandardSchemaV1, Config extends object, Json> = ExactCreateErrorConfig<Schema, Config & {
|
|
21
|
+
toJSON(error: BlueprintErrorTemplate<NoInfer<Config>>): Json;
|
|
22
|
+
}>;
|
|
23
|
+
/**
|
|
24
|
+
* Creates an error family with additional instance properties and typed JSON
|
|
25
|
+
* serialization.
|
|
26
|
+
*
|
|
27
|
+
* @param config Defines the family, its public properties, and its serialized
|
|
28
|
+
* representation.
|
|
29
|
+
* @returns A callable factory with a shared `.Error` base class.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* const createApiError = createError({
|
|
34
|
+
* definition: z.object({ code: z.string() }),
|
|
35
|
+
* data: {
|
|
36
|
+
* property: 'context',
|
|
37
|
+
* resolve: ({ input }) => input,
|
|
38
|
+
* },
|
|
39
|
+
* message: ({ data, implementation }) => implementation(data),
|
|
40
|
+
* properties: ({ definition }) => ({ code: definition.code }),
|
|
41
|
+
* toJSON: (error) => ({
|
|
42
|
+
* code: error.code,
|
|
43
|
+
* context: error.context,
|
|
44
|
+
* message: error.message,
|
|
45
|
+
* }),
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
declare function createError<const Schema extends StandardSchemaV1, const DataConfig extends CreateErrorConfig<Schema>['data'], const MessageCallback extends CreateErrorConfig<Schema>['message'], const Properties extends object, Json>(config: SerializedCreateErrorConfig<Schema, ErrorConfigWithProperties<Schema, DataConfig, MessageCallback, Properties>, Json>): ErrorFamilyFactory<Schema, typeof config>;
|
|
50
|
+
/**
|
|
51
|
+
* Creates an error family with typed JSON serialization and no additional
|
|
52
|
+
* instance properties.
|
|
53
|
+
*
|
|
54
|
+
* @param config Defines the family and its serialized representation.
|
|
55
|
+
* @returns A callable factory with a shared `.Error` base class.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* const createLogError = createError({
|
|
60
|
+
* definition: z.object({ code: z.string() }),
|
|
61
|
+
* data: {
|
|
62
|
+
* property: 'details',
|
|
63
|
+
* resolve: ({ input }) => input,
|
|
64
|
+
* },
|
|
65
|
+
* message: ({ data, implementation }) => implementation(data),
|
|
66
|
+
* toJSON: (error) => ({
|
|
67
|
+
* details: error.details,
|
|
68
|
+
* message: error.message,
|
|
69
|
+
* }),
|
|
70
|
+
* });
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
declare function createError<const Schema extends StandardSchemaV1, const DataConfig extends CreateErrorConfig<Schema>['data'], const MessageCallback extends CreateErrorConfig<Schema>['message'], Json>(config: SerializedCreateErrorConfig<Schema, ErrorConfigWithoutProperties<Schema, DataConfig, MessageCallback>, Json>): ErrorFamilyFactory<Schema, typeof config>;
|
|
74
|
+
/**
|
|
75
|
+
* Creates a configurable family of strongly typed error classes.
|
|
76
|
+
*
|
|
77
|
+
* Callback execution order is `data.resolve`, optional context validation,
|
|
78
|
+
* `message`, then `properties`. Parsed definition output and constructor data
|
|
79
|
+
* are inferred without explicit generic arguments or `as const`.
|
|
80
|
+
*
|
|
81
|
+
* @param config Defines the family's schema, data lifecycle, message, and
|
|
82
|
+
* optional public properties.
|
|
83
|
+
* @returns A callable factory with a shared `.Error` base class.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* const createRequestError = createError({
|
|
88
|
+
* definition: z.object({ code: z.string() }),
|
|
89
|
+
* data: {
|
|
90
|
+
* property: 'context',
|
|
91
|
+
* resolve: ({ input }) => input,
|
|
92
|
+
* },
|
|
93
|
+
* message: ({ data, implementation }) => implementation(data),
|
|
94
|
+
* properties: ({ definition }) => ({ code: definition.code }),
|
|
95
|
+
* });
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
declare function createError<const Schema extends StandardSchemaV1, const Config extends Omit<CreateErrorConfig<Schema>, 'definition'>>(config: ExactCreateErrorConfig<Schema, Config>): ErrorFamilyFactory<Schema, typeof config>;
|
|
99
|
+
//#endregion
|
|
100
|
+
export { createError };
|
|
101
|
+
//# sourceMappingURL=create-error.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-error.d.cts","names":[],"sources":["../src/create-error.ts"],"sourcesContent":[],"mappings":";;;;KAWK,+BACY,qCACI,kBAAkB,yCACb,kBAAkB;QAEpC;EALH,OAAA,EAMM,eANS;CACH;KAQZ,yBAPkC,CAAA,eAQtB,gBARsB,EAAA,mBASlB,iBATkB,CASA,MATA,CAAA,CAAA,MAAA,CAAA,EAAA,wBAUb,iBAVa,CAUK,MAVL,CAAA,CAAA,SAAA,CAAA,EAAA,mBAAA,MAAA,CAAA,GAYnC,eAZmC,CAYnB,MAZmB,EAYX,UAZW,EAYC,eAZD,CAAA,GAAA;EAAlB,UAAA,CAAA,OAAA,EAaC,gBAbD,CAakB,MAblB,CAAA,CAAA,EAa4B,UAb5B;CACuB;KAevC,4BAfqB,CAAA,eAgBT,gBAhBS,EAAA,mBAiBL,iBAjBK,CAiBa,MAjBb,CAAA,CAAA,MAAA,CAAA,EAAA,wBAkBA,iBAlBA,CAkBkB,MAlBlB,CAAA,CAAA,SAAA,CAAA,CAAA,GAmBtB,eAnBsB,CAmBN,MAnBM,EAmBE,UAnBF,EAmBc,eAnBd,CAAA,GAAA;EAElB,UAAA,CAAA,EAAA,KAAA;CACG;KAoBN,sBApBqB,CAAA,eAqBT,gBArBS,EAAA,eAAA,MAAA,CAAA,GAAA;EAGrB,UAAA,EAqBS,MArBT;CACY,GAqBb,MArBa,GAAA,CAsBd,gBAAA,CAAiB,WAtBH,CAsBe,MAtBf,CAAA,SAAA,MAAA,GAAA,OAAA,GAAA;EACsB,UAAA,EAAA,KAAA;CAAlB,CAAA;KAyBhB,2BAxBuC,CAAA,eAyB3B,gBAzB2B,EAAA,eAAA,MAAA,EAAA,IAAA,CAAA,GA4BxC,sBA5BwC,CA6B1C,MA7B0C,EA8B1C,MA9B0C,GAAA;EAAlB,MAAA,CAAA,KAAA,EA+BR,sBA/BQ,CA+Be,OA/Bf,CA+BuB,MA/BvB,CAAA,CAAA,CAAA,EA+BkC,IA/BlC;CAEN,CAAA;;;;;;;;AACuC;;;;;;;;;;;AAOxC;;;;;;;AAUY;AAKd,iBAqLD,WArLC,CAAA,qBAsLM,gBAtLN,EAAA,yBAuLU,iBAvLV,CAuL4B,MAvL5B,CAAA,CAAA,MAAA,CAAA,EAAA,8BAwLe,iBAxLf,CAwLiC,MAxLjC,CAAA,CAAA,SAAA,CAAA,EAAA,yBAAA,MAAA,EAAA,IAAA,CAAA,CAAA,MAAA,EA4LP,2BA5LO,CA6Lb,MA7La,EA8Lb,yBA9La,CA+LX,MA/LW,EAgMX,UAhMW,EAiMX,eAjMW,EAkMX,UAlMW,CAAA,EAoMb,IApMa,CAAA,CAAA,EAsMd,kBAtMc,CAsMK,MAtML,EAAA,OAsMoB,MAtMpB,CAAA;;;;;;;;;AAqLjB;;;;;;;;;;;;;;;AAiBqC,iBAyBrB,WAzBqB,CAAA,qBA0Bd,gBA1Bc,EAAA,yBA2BV,iBA3BU,CA2BQ,MA3BR,CAAA,CAAA,MAAA,CAAA,EAAA,8BA4BL,iBA5BK,CA4Ba,MA5Bb,CAAA,CAAA,SAAA,CAAA,EAAA,IAAA,CAAA,CAAA,MAAA,EA+B3B,2BA/B2B,CAgCjC,MAhCiC,EAiCjC,4BAjCiC,CAiCJ,MAjCI,EAiCI,UAjCJ,EAiCgB,eAjChB,CAAA,EAkCjC,IAlCiC,CAAA,CAAA,EAoClC,kBApCkC,CAoCf,MApCe,EAAA,OAoCA,MApCA,CAAA;;;AAyBrC;;;;;;;;;;;;;;;;;AAqCA;;;;;AAIiC,iBAJjB,WAIiB,CAAA,qBAHV,gBAGU,EAAA,qBAFV,IAEU,CAFL,iBAEK,CAFa,MAEb,CAAA,EAAA,YAAA,CAAA,CAAA,CAAA,MAAA,EAAvB,sBAAuB,CAAA,MAAA,EAAQ,MAAR,CAAA,CAAA,EAC9B,kBAD8B,CACX,MADW,EAAA,OACI,MADJ,CAAA"}
|