@devp0nt/error0 1.0.0-next.4 → 1.0.0-next.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +342 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +173 -415
- package/dist/esm/index.d.ts +173 -415
- package/dist/esm/index.js +268 -351
- package/dist/esm/index.js.map +1 -1
- package/package.json +45 -22
- package/src/index.test.ts +295 -478
- package/src/index.ts +566 -508
- package/dist/cjs/index.js +0 -435
- package/dist/cjs/index.js.map +0 -1
package/src/index.ts
CHANGED
|
@@ -1,585 +1,643 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// TODO: remove defaults prop from getPropsFromUnknown
|
|
11
|
-
// TODO: code has enum type, fn to check if code exists
|
|
12
|
-
|
|
13
|
-
export interface Error0Input {
|
|
14
|
-
message?: string
|
|
15
|
-
tag?: string
|
|
16
|
-
code?: string
|
|
17
|
-
httpStatus?: HttpStatusCode | HttpStatusCodeString
|
|
18
|
-
expected?: boolean | ExpectedFn
|
|
19
|
-
clientMessage?: string
|
|
20
|
-
cause?: Error0Cause
|
|
21
|
-
stack?: string
|
|
22
|
-
meta?: Meta0.Meta0OrValueTypeNullish
|
|
23
|
-
zodError?: ZodError
|
|
24
|
-
axiosError?: AxiosError
|
|
1
|
+
export type ErrorExtensionPropOptions<TInputValue, TOutputValue, TError extends Error0 = Error0> = {
|
|
2
|
+
init: (input: TInputValue) => TOutputValue
|
|
3
|
+
resolve: (options: {
|
|
4
|
+
value: TOutputValue | undefined
|
|
5
|
+
flow: Array<TOutputValue | undefined>
|
|
6
|
+
error: TError
|
|
7
|
+
}) => TOutputValue | undefined
|
|
8
|
+
serialize: (options: { value: TOutputValue; error: TError; isPublic: boolean }) => unknown
|
|
9
|
+
deserialize: (options: { value: unknown; serialized: Record<string, unknown> }) => TOutputValue | undefined
|
|
25
10
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
axiosError?: AxiosError
|
|
11
|
+
export type ErrorExtensionMethodFn<
|
|
12
|
+
TOutputValue,
|
|
13
|
+
TArgs extends unknown[] = unknown[],
|
|
14
|
+
TError extends Error0 = Error0,
|
|
15
|
+
> = (error: TError, ...args: TArgs) => TOutputValue
|
|
16
|
+
export type ErrorExtensionRefineResult<TOutputProps extends Record<string, unknown>> = Partial<TOutputProps> | undefined
|
|
17
|
+
export type ErrorExtensionRefineFn<
|
|
18
|
+
TError extends Error0 = Error0,
|
|
19
|
+
TOutputProps extends Record<string, unknown> = Record<never, never>,
|
|
20
|
+
> = ((error: TError) => void) | ((error: TError) => ErrorExtensionRefineResult<TOutputProps>)
|
|
21
|
+
type ErrorMethodRecord = {
|
|
22
|
+
args: unknown[]
|
|
23
|
+
output: unknown
|
|
40
24
|
}
|
|
41
25
|
|
|
42
|
-
type
|
|
43
|
-
type
|
|
44
|
-
type ExpectedFn = (error: Error0GeneralProps) => boolean | undefined
|
|
45
|
-
|
|
46
|
-
const isFilled = <T>(value: T): value is NonNullable<T> => value !== null && value !== undefined && value !== ''
|
|
26
|
+
export type ErrorExtensionProps = { [key: string]: ErrorExtensionPropOptions<any, any> }
|
|
27
|
+
export type ErrorExtensionMethods = { [key: string]: ErrorExtensionMethodFn<any, any[]> }
|
|
47
28
|
|
|
48
|
-
export
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
29
|
+
export type ErrorExtension<
|
|
30
|
+
TProps extends ErrorExtensionProps = Record<never, never>,
|
|
31
|
+
TMethods extends ErrorExtensionMethods = Record<never, never>,
|
|
32
|
+
> = {
|
|
33
|
+
props?: TProps
|
|
34
|
+
methods?: TMethods
|
|
35
|
+
refine?: Array<ErrorExtensionRefineFn<Error0, ExtensionOutputProps<TProps>>>
|
|
36
|
+
}
|
|
37
|
+
type AddPropToExtensionProps<
|
|
38
|
+
TProps extends ErrorExtensionProps,
|
|
39
|
+
TKey extends string,
|
|
40
|
+
TInputValue,
|
|
41
|
+
TOutputValue,
|
|
42
|
+
> = TProps & Record<TKey, ErrorExtensionPropOptions<TInputValue, TOutputValue>>
|
|
43
|
+
type AddMethodToExtensionMethods<
|
|
44
|
+
TMethods extends ErrorExtensionMethods,
|
|
45
|
+
TKey extends string,
|
|
46
|
+
TArgs extends unknown[],
|
|
47
|
+
TOutputValue,
|
|
48
|
+
> = TMethods & Record<TKey, ErrorExtensionMethodFn<TOutputValue, TArgs>>
|
|
49
|
+
type ExtensionOutputProps<TProps extends ErrorExtensionProps> = {
|
|
50
|
+
[TKey in keyof TProps]: TProps[TKey] extends ErrorExtensionPropOptions<any, infer TOutputValue> ? TOutputValue : never
|
|
51
|
+
}
|
|
52
|
+
export type ErrorExtensionsMap = {
|
|
53
|
+
props: Record<string, { init: unknown; resolve: unknown }>
|
|
54
|
+
methods: Record<string, ErrorMethodRecord>
|
|
55
|
+
}
|
|
56
|
+
export type IsEmptyObject<T> = keyof T extends never ? true : false
|
|
57
|
+
export type ErrorInputBase = {
|
|
58
|
+
cause?: unknown
|
|
59
|
+
}
|
|
60
|
+
export type ErrorInput<TExtensionsMap extends ErrorExtensionsMap> =
|
|
61
|
+
IsEmptyObject<TExtensionsMap['props']> extends true
|
|
62
|
+
? ErrorInputBase
|
|
63
|
+
: ErrorInputBase &
|
|
64
|
+
Partial<{
|
|
65
|
+
[TKey in keyof TExtensionsMap['props']]: TExtensionsMap['props'][TKey]['init']
|
|
66
|
+
}>
|
|
67
|
+
|
|
68
|
+
type ErrorOutputProps<TExtensionsMap extends ErrorExtensionsMap> = {
|
|
69
|
+
[TKey in keyof TExtensionsMap['props']]?: TExtensionsMap['props'][TKey]['resolve']
|
|
70
|
+
}
|
|
71
|
+
type ErrorOutputMethods<TExtensionsMap extends ErrorExtensionsMap> = {
|
|
72
|
+
[TKey in keyof TExtensionsMap['methods']]: TExtensionsMap['methods'][TKey] extends {
|
|
73
|
+
args: infer TArgs extends unknown[]
|
|
74
|
+
output: infer TOutput
|
|
75
|
+
}
|
|
76
|
+
? (...args: TArgs) => TOutput
|
|
77
|
+
: never
|
|
78
|
+
}
|
|
79
|
+
export type ErrorOutput<TExtensionsMap extends ErrorExtensionsMap> = ErrorOutputProps<TExtensionsMap> &
|
|
80
|
+
ErrorOutputMethods<TExtensionsMap>
|
|
96
81
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
})
|
|
102
|
-
const causesProps = (this.constructor as typeof Error0)._getCausesPropsFromError0Props(
|
|
103
|
-
this.propsOriginal,
|
|
104
|
-
(this.constructor as typeof Error0).defaultMaxLevel,
|
|
105
|
-
)
|
|
106
|
-
const propsFloated = (this.constructor as typeof Error0)._getSelfPropsFloated(causesProps)
|
|
107
|
-
this.tag = propsFloated.tag
|
|
108
|
-
this.code = propsFloated.code
|
|
109
|
-
this.httpStatus = propsFloated.httpStatus
|
|
110
|
-
this.expected = propsFloated.expected
|
|
111
|
-
this.clientMessage = propsFloated.clientMessage
|
|
112
|
-
this.cause = propsFloated.cause
|
|
113
|
-
this.stack = propsFloated.stack
|
|
114
|
-
this.meta = propsFloated.meta
|
|
115
|
-
this.zodError = propsFloated.zodError
|
|
116
|
-
this.axiosError = propsFloated.axiosError
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// settings
|
|
120
|
-
|
|
121
|
-
static defaultMaxLevel = 10
|
|
122
|
-
|
|
123
|
-
// props
|
|
124
|
-
|
|
125
|
-
public static _safeParseInput(error0Input: Record<string, unknown>): Error0Input {
|
|
126
|
-
const result: Error0Input = {}
|
|
127
|
-
result.message = typeof error0Input.message === 'string' ? error0Input.message : undefined
|
|
128
|
-
result.tag = typeof error0Input.tag === 'string' ? error0Input.tag : undefined
|
|
129
|
-
result.code = typeof error0Input.code === 'string' ? error0Input.code : undefined
|
|
130
|
-
result.httpStatus =
|
|
131
|
-
typeof error0Input.httpStatus === 'number' || typeof error0Input.httpStatus === 'string'
|
|
132
|
-
? (error0Input.httpStatus as never)
|
|
133
|
-
: undefined
|
|
134
|
-
result.expected =
|
|
135
|
-
typeof error0Input.expected === 'function' || typeof error0Input.expected === 'boolean'
|
|
136
|
-
? (error0Input.expected as never)
|
|
137
|
-
: undefined
|
|
138
|
-
result.clientMessage = typeof error0Input.clientMessage === 'string' ? error0Input.clientMessage : undefined
|
|
139
|
-
result.cause = error0Input.cause
|
|
140
|
-
result.stack = typeof error0Input.stack === 'string' ? error0Input.stack : undefined
|
|
141
|
-
// result.meta0 =
|
|
142
|
-
// error0Input.meta0 instanceof Meta0 ? error0Input.meta0 : undefined
|
|
143
|
-
// result.meta =
|
|
144
|
-
// typeof error0Input.meta === "object" && error0Input.meta !== null
|
|
145
|
-
// ? error0Input.meta
|
|
146
|
-
// : undefined
|
|
147
|
-
result.meta =
|
|
148
|
-
error0Input.meta instanceof Meta0
|
|
149
|
-
? error0Input.meta
|
|
150
|
-
: typeof error0Input.meta === 'object' && error0Input.meta !== null
|
|
151
|
-
? (error0Input.meta as Meta0.ValueType)
|
|
152
|
-
: undefined
|
|
153
|
-
result.zodError = error0Input.zodError instanceof ZodError ? error0Input.zodError : undefined
|
|
154
|
-
result.axiosError = isAxiosError(error0Input.axiosError) ? error0Input.axiosError : undefined
|
|
155
|
-
return result
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
public static _getSelfGeneralProps({
|
|
159
|
-
error0Input,
|
|
160
|
-
message,
|
|
161
|
-
stack,
|
|
162
|
-
}: {
|
|
163
|
-
error0Input: Error0Input
|
|
164
|
-
message: string
|
|
165
|
-
stack: Error0GeneralProps['stack']
|
|
166
|
-
}): Error0GeneralProps {
|
|
167
|
-
// const meta = Meta0.merge(error0Input.meta0, error0Input.meta).value
|
|
168
|
-
const meta0 = Meta0.extend(error0Input.meta, this.defaultMeta)
|
|
169
|
-
const meta = meta0.getValue()
|
|
170
|
-
const finalTag = meta0.getFinalTag(error0Input.tag)
|
|
171
|
-
const clientMessage = error0Input.clientMessage || this.defaultClientMessage
|
|
172
|
-
const result: Error0GeneralProps = {
|
|
173
|
-
message: error0Input.message || this.defaultMessage,
|
|
174
|
-
tag: finalTag,
|
|
175
|
-
code: error0Input.code || meta.code || this.defaultCode,
|
|
176
|
-
httpStatus:
|
|
177
|
-
typeof error0Input.httpStatus === 'number'
|
|
178
|
-
? error0Input.httpStatus
|
|
179
|
-
: error0Input.httpStatus &&
|
|
180
|
-
typeof error0Input.httpStatus === 'string' &&
|
|
181
|
-
error0Input.httpStatus in HttpStatusCode
|
|
182
|
-
? HttpStatusCode[error0Input.httpStatus]
|
|
183
|
-
: meta.httpStatus || this.defaultHttpStatus,
|
|
184
|
-
expected: undefined,
|
|
185
|
-
clientMessage,
|
|
186
|
-
anyMessage: clientMessage || message,
|
|
187
|
-
cause: error0Input.cause,
|
|
188
|
-
stack: undefined,
|
|
189
|
-
meta,
|
|
190
|
-
zodError: error0Input.zodError,
|
|
191
|
-
axiosError: error0Input.axiosError,
|
|
192
|
-
}
|
|
193
|
-
result.expected = this._normalizeSelfExpected(
|
|
194
|
-
result,
|
|
195
|
-
typeof error0Input.expected === 'boolean' || typeof error0Input.expected === 'function'
|
|
196
|
-
? error0Input.expected
|
|
197
|
-
: meta.expected || this.defaultExpected,
|
|
198
|
-
)
|
|
199
|
-
result.stack = this._removeConstructorStackPart(stack)
|
|
200
|
-
return result
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
public static _getSelfPropsFloated(causesProps: Error0GeneralProps[]): Error0GeneralProps {
|
|
204
|
-
const cause = this._getClosestPropValue(causesProps, 'cause')
|
|
205
|
-
const stack = this._mergeStack(causesProps[1]?.stack, causesProps[0]?.stack)
|
|
206
|
-
const closestTag = this._getClosestPropValue(causesProps, 'tag')
|
|
207
|
-
const meta = this._getMergedMetaValue(causesProps)
|
|
208
|
-
const tag = Meta0.getFinalTag(meta, closestTag)
|
|
209
|
-
const propsFloated: Error0GeneralProps = {
|
|
210
|
-
message: this._getClosestPropValue(causesProps, 'message'),
|
|
211
|
-
tag,
|
|
212
|
-
code: this._getClosestPropValue(causesProps, 'code'),
|
|
213
|
-
httpStatus: this._getClosestPropValue(causesProps, 'httpStatus'),
|
|
214
|
-
expected: this._isExpected(causesProps),
|
|
215
|
-
clientMessage: this._getClosestPropValue(causesProps, 'clientMessage'),
|
|
216
|
-
cause,
|
|
217
|
-
stack,
|
|
218
|
-
anyMessage: causesProps[0].anyMessage,
|
|
219
|
-
meta,
|
|
220
|
-
zodError: this._getClosestPropValue(causesProps, 'zodError'),
|
|
221
|
-
axiosError: this._getClosestPropValue(causesProps, 'axiosError'),
|
|
222
|
-
}
|
|
223
|
-
return propsFloated
|
|
82
|
+
type ErrorStaticMethods<TExtensionsMap extends ErrorExtensionsMap> = {
|
|
83
|
+
[TKey in keyof TExtensionsMap['methods']]: TExtensionsMap['methods'][TKey] extends {
|
|
84
|
+
args: infer TArgs extends unknown[]
|
|
85
|
+
output: infer TOutput
|
|
224
86
|
}
|
|
87
|
+
? (error: unknown, ...args: TArgs) => TOutput
|
|
88
|
+
: never
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
type EmptyExtensionsMap = {
|
|
92
|
+
props: Record<never, { init: never; resolve: never }>
|
|
93
|
+
methods: Record<never, ErrorMethodRecord>
|
|
94
|
+
}
|
|
225
95
|
|
|
226
|
-
|
|
96
|
+
type ErrorExtensionResolved = {
|
|
97
|
+
props: Record<string, ErrorExtensionPropOptions<unknown, unknown>>
|
|
98
|
+
methods: Record<string, ErrorExtensionMethodFn<unknown>>
|
|
99
|
+
refine: Array<ErrorExtensionRefineFn<Error0, Record<string, unknown>>>
|
|
100
|
+
}
|
|
227
101
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
102
|
+
type ExtensionPropsMapOf<TExtension extends ErrorExtension> = {
|
|
103
|
+
[TKey in keyof NonNullable<TExtension['props']>]: NonNullable<
|
|
104
|
+
TExtension['props']
|
|
105
|
+
>[TKey] extends ErrorExtensionPropOptions<infer TInputValue, infer TOutputValue>
|
|
106
|
+
? { init: TInputValue; resolve: TOutputValue }
|
|
107
|
+
: never
|
|
108
|
+
}
|
|
109
|
+
type ExtensionMethodsMapOf<TExtension extends ErrorExtension> = {
|
|
110
|
+
[TKey in keyof NonNullable<TExtension['methods']>]: NonNullable<TExtension['methods']>[TKey] extends (
|
|
111
|
+
error: Error0,
|
|
112
|
+
...args: infer TArgs extends unknown[]
|
|
113
|
+
) => infer TOutput
|
|
114
|
+
? { args: TArgs; output: TOutput }
|
|
115
|
+
: never
|
|
116
|
+
}
|
|
117
|
+
type ErrorExtensionsMapOfExtension<TExtension extends ErrorExtension> = {
|
|
118
|
+
props: ExtensionPropsMapOf<TExtension>
|
|
119
|
+
methods: ExtensionMethodsMapOf<TExtension>
|
|
120
|
+
}
|
|
121
|
+
type ExtendErrorExtensionsMap<TMap extends ErrorExtensionsMap, TExtension extends ErrorExtension> = {
|
|
122
|
+
props: TMap['props'] & ErrorExtensionsMapOfExtension<TExtension>['props']
|
|
123
|
+
methods: TMap['methods'] & ErrorExtensionsMapOfExtension<TExtension>['methods']
|
|
124
|
+
}
|
|
125
|
+
type ExtendErrorExtensionsMapWithProp<
|
|
126
|
+
TMap extends ErrorExtensionsMap,
|
|
127
|
+
TKey extends string,
|
|
128
|
+
TInputValue,
|
|
129
|
+
TOutputValue,
|
|
130
|
+
> = ExtendErrorExtensionsMap<TMap, ErrorExtension<Record<TKey, ErrorExtensionPropOptions<TInputValue, TOutputValue>>>>
|
|
131
|
+
type ExtendErrorExtensionsMapWithMethod<
|
|
132
|
+
TMap extends ErrorExtensionsMap,
|
|
133
|
+
TKey extends string,
|
|
134
|
+
TArgs extends unknown[],
|
|
135
|
+
TOutputValue,
|
|
136
|
+
> = ExtendErrorExtensionsMap<
|
|
137
|
+
TMap,
|
|
138
|
+
ErrorExtension<Record<never, never>, Record<TKey, ErrorExtensionMethodFn<TOutputValue, TArgs>>>
|
|
139
|
+
>
|
|
140
|
+
|
|
141
|
+
type ExtensionsMapOf<TClass> = TClass extends { __extensionsMap?: infer TExtensionsMap }
|
|
142
|
+
? TExtensionsMap extends ErrorExtensionsMap
|
|
143
|
+
? TExtensionsMap
|
|
144
|
+
: EmptyExtensionsMap
|
|
145
|
+
: EmptyExtensionsMap
|
|
146
|
+
|
|
147
|
+
type ExtensionsMapFromParts<
|
|
148
|
+
TProps extends ErrorExtensionProps,
|
|
149
|
+
TMethods extends ErrorExtensionMethods,
|
|
150
|
+
> = ErrorExtensionsMapOfExtension<ErrorExtension<TProps, TMethods>>
|
|
151
|
+
type ErrorInstanceOfMap<TMap extends ErrorExtensionsMap> = Error0 & ErrorOutput<TMap>
|
|
152
|
+
type BuilderError0<TProps extends ErrorExtensionProps, TMethods extends ErrorExtensionMethods> = Error0 &
|
|
153
|
+
ErrorOutput<ExtensionsMapFromParts<TProps, TMethods>>
|
|
154
|
+
|
|
155
|
+
type ExtensionOfBuilder<TBuilder> =
|
|
156
|
+
TBuilder extends ExtensionError0<infer TProps, infer TMethods> ? ErrorExtension<TProps, TMethods> : never
|
|
157
|
+
|
|
158
|
+
export class ExtensionError0<
|
|
159
|
+
TProps extends ErrorExtensionProps = Record<never, never>,
|
|
160
|
+
TMethods extends ErrorExtensionMethods = Record<never, never>,
|
|
161
|
+
> {
|
|
162
|
+
private readonly _extension: ErrorExtension<ErrorExtensionProps, ErrorExtensionMethods>
|
|
163
|
+
|
|
164
|
+
readonly Infer = undefined as unknown as {
|
|
165
|
+
props: TProps
|
|
166
|
+
methods: TMethods
|
|
232
167
|
}
|
|
233
168
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
try {
|
|
240
|
-
return JSON.stringify(axiosError.response?.data)
|
|
241
|
-
} catch {
|
|
242
|
-
return undefined
|
|
243
|
-
}
|
|
244
|
-
})(),
|
|
245
|
-
axiosStatus: axiosError.response?.status,
|
|
246
|
-
},
|
|
169
|
+
constructor(extension?: ErrorExtension<ErrorExtensionProps, ErrorExtensionMethods>) {
|
|
170
|
+
this._extension = {
|
|
171
|
+
props: { ...(extension?.props ?? {}) },
|
|
172
|
+
methods: { ...(extension?.methods ?? {}) },
|
|
173
|
+
refine: [...(extension?.refine ?? [])],
|
|
247
174
|
}
|
|
248
175
|
}
|
|
249
176
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
):
|
|
254
|
-
|
|
255
|
-
Object.assign(error0Props, extraError0Props, { meta: metaValue })
|
|
177
|
+
prop<TKey extends string, TInputValue, TOutputValue>(
|
|
178
|
+
key: TKey,
|
|
179
|
+
value: ErrorExtensionPropOptions<TInputValue, TOutputValue, BuilderError0<TProps, TMethods>>,
|
|
180
|
+
): ExtensionError0<AddPropToExtensionProps<TProps, TKey, TInputValue, TOutputValue>, TMethods> {
|
|
181
|
+
return this.extend('prop', key, value)
|
|
256
182
|
}
|
|
257
183
|
|
|
258
|
-
|
|
184
|
+
method<TKey extends string, TArgs extends unknown[], TOutputValue>(
|
|
185
|
+
key: TKey,
|
|
186
|
+
value: ErrorExtensionMethodFn<TOutputValue, TArgs, BuilderError0<TProps, TMethods>>,
|
|
187
|
+
): ExtensionError0<TProps, AddMethodToExtensionMethods<TMethods, TKey, TArgs, TOutputValue>> {
|
|
188
|
+
return this.extend('method', key, value)
|
|
189
|
+
}
|
|
259
190
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if (typeof expectedProvided === 'function') {
|
|
265
|
-
return expectedProvided(error0Props)
|
|
266
|
-
}
|
|
267
|
-
return expectedProvided
|
|
191
|
+
refine(
|
|
192
|
+
value: ErrorExtensionRefineFn<BuilderError0<TProps, TMethods>, ExtensionOutputProps<TProps>>,
|
|
193
|
+
): ExtensionError0<TProps, TMethods> {
|
|
194
|
+
return this.extend('refine', value)
|
|
268
195
|
}
|
|
269
196
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
197
|
+
extend<TKey extends string, TInputValue, TOutputValue>(
|
|
198
|
+
kind: 'prop',
|
|
199
|
+
key: TKey,
|
|
200
|
+
value: ErrorExtensionPropOptions<TInputValue, TOutputValue, BuilderError0<TProps, TMethods>>,
|
|
201
|
+
): ExtensionError0<AddPropToExtensionProps<TProps, TKey, TInputValue, TOutputValue>, TMethods>
|
|
202
|
+
extend<TKey extends string, TArgs extends unknown[], TOutputValue>(
|
|
203
|
+
kind: 'method',
|
|
204
|
+
key: TKey,
|
|
205
|
+
value: ErrorExtensionMethodFn<TOutputValue, TArgs, BuilderError0<TProps, TMethods>>,
|
|
206
|
+
): ExtensionError0<TProps, AddMethodToExtensionMethods<TMethods, TKey, TArgs, TOutputValue>>
|
|
207
|
+
extend(
|
|
208
|
+
kind: 'refine',
|
|
209
|
+
value: ErrorExtensionRefineFn<BuilderError0<TProps, TMethods>, ExtensionOutputProps<TProps>>,
|
|
210
|
+
): ExtensionError0<TProps, TMethods>
|
|
211
|
+
extend(
|
|
212
|
+
kind: 'prop' | 'method' | 'refine',
|
|
213
|
+
keyOrValue: string | ErrorExtensionRefineFn<any, any>,
|
|
214
|
+
value?: ErrorExtensionPropOptions<unknown, unknown, any> | ErrorExtensionMethodFn<unknown, unknown[], any>,
|
|
215
|
+
): ExtensionError0<any, any> {
|
|
216
|
+
const nextProps: ErrorExtensionProps = { ...(this._extension.props ?? {}) }
|
|
217
|
+
const nextMethods: ErrorExtensionMethods = { ...(this._extension.methods ?? {}) }
|
|
218
|
+
const nextRefine: Array<ErrorExtensionRefineFn<Error0, Record<string, unknown>>> = [
|
|
219
|
+
...(this._extension.refine ?? []),
|
|
220
|
+
]
|
|
221
|
+
if (kind === 'prop') {
|
|
222
|
+
const key = keyOrValue as string
|
|
223
|
+
if (value === undefined) {
|
|
224
|
+
throw new Error('ExtensionError0.extend("prop", key, value) requires value')
|
|
275
225
|
}
|
|
276
|
-
|
|
277
|
-
|
|
226
|
+
nextProps[key] = value as ErrorExtensionPropOptions<any, any>
|
|
227
|
+
} else if (kind === 'method') {
|
|
228
|
+
const key = keyOrValue as string
|
|
229
|
+
if (value === undefined) {
|
|
230
|
+
throw new Error('ExtensionError0.extend("method", key, value) requires value')
|
|
278
231
|
}
|
|
232
|
+
nextMethods[key] = value as ErrorExtensionMethodFn<any, any[]>
|
|
233
|
+
} else {
|
|
234
|
+
nextRefine.push(keyOrValue as ErrorExtensionRefineFn<Error0, Record<string, unknown>>)
|
|
279
235
|
}
|
|
280
|
-
return
|
|
236
|
+
return new ExtensionError0({
|
|
237
|
+
props: nextProps,
|
|
238
|
+
methods: nextMethods,
|
|
239
|
+
refine: nextRefine,
|
|
240
|
+
})
|
|
281
241
|
}
|
|
242
|
+
}
|
|
282
243
|
|
|
283
|
-
|
|
244
|
+
export type ClassError0<TExtensionsMap extends ErrorExtensionsMap = EmptyExtensionsMap> = {
|
|
245
|
+
new (message: string, input?: ErrorInput<TExtensionsMap>): Error0 & ErrorOutput<TExtensionsMap>
|
|
246
|
+
new (input: { message: string } & ErrorInput<TExtensionsMap>): Error0 & ErrorOutput<TExtensionsMap>
|
|
247
|
+
readonly __extensionsMap?: TExtensionsMap
|
|
248
|
+
from: (error: unknown) => Error0 & ErrorOutput<TExtensionsMap>
|
|
249
|
+
serialize: (error: unknown, isPublic?: boolean) => Record<string, unknown>
|
|
250
|
+
prop: <TKey extends string, TInputValue, TOutputValue>(
|
|
251
|
+
key: TKey,
|
|
252
|
+
value: ErrorExtensionPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<TExtensionsMap>>,
|
|
253
|
+
) => ClassError0<ExtendErrorExtensionsMapWithProp<TExtensionsMap, TKey, TInputValue, TOutputValue>>
|
|
254
|
+
method: <TKey extends string, TArgs extends unknown[], TOutputValue>(
|
|
255
|
+
key: TKey,
|
|
256
|
+
value: ErrorExtensionMethodFn<TOutputValue, TArgs, ErrorInstanceOfMap<TExtensionsMap>>,
|
|
257
|
+
) => ClassError0<ExtendErrorExtensionsMapWithMethod<TExtensionsMap, TKey, TArgs, TOutputValue>>
|
|
258
|
+
refine: (
|
|
259
|
+
value: ErrorExtensionRefineFn<ErrorInstanceOfMap<TExtensionsMap>, ErrorOutputProps<TExtensionsMap>>,
|
|
260
|
+
) => ClassError0<TExtensionsMap>
|
|
261
|
+
extend: {
|
|
262
|
+
<TBuilder extends ExtensionError0>(
|
|
263
|
+
extension: TBuilder,
|
|
264
|
+
): ClassError0<ExtendErrorExtensionsMap<TExtensionsMap, ExtensionOfBuilder<TBuilder>>>
|
|
265
|
+
<TKey extends string, TInputValue, TOutputValue>(
|
|
266
|
+
kind: 'prop',
|
|
267
|
+
key: TKey,
|
|
268
|
+
value: ErrorExtensionPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<TExtensionsMap>>,
|
|
269
|
+
): ClassError0<ExtendErrorExtensionsMapWithProp<TExtensionsMap, TKey, TInputValue, TOutputValue>>
|
|
270
|
+
<TKey extends string, TArgs extends unknown[], TOutputValue>(
|
|
271
|
+
kind: 'method',
|
|
272
|
+
key: TKey,
|
|
273
|
+
value: ErrorExtensionMethodFn<TOutputValue, TArgs, ErrorInstanceOfMap<TExtensionsMap>>,
|
|
274
|
+
): ClassError0<ExtendErrorExtensionsMapWithMethod<TExtensionsMap, TKey, TArgs, TOutputValue>>
|
|
275
|
+
(
|
|
276
|
+
kind: 'refine',
|
|
277
|
+
value: ErrorExtensionRefineFn<ErrorInstanceOfMap<TExtensionsMap>, ErrorOutputProps<TExtensionsMap>>,
|
|
278
|
+
): ClassError0<TExtensionsMap>
|
|
279
|
+
}
|
|
280
|
+
extension: () => ExtensionError0
|
|
281
|
+
} & ErrorStaticMethods<TExtensionsMap>
|
|
284
282
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
clientMessage: undefined,
|
|
294
|
-
anyMessage: this.defaultMessage,
|
|
295
|
-
cause: undefined,
|
|
296
|
-
stack: undefined,
|
|
297
|
-
zodError: undefined,
|
|
298
|
-
axiosError: undefined,
|
|
299
|
-
meta: {},
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
const message = 'message' in error && typeof error.message === 'string' ? error.message : undefined
|
|
303
|
-
const clientMessage =
|
|
304
|
-
'clientMessage' in error && typeof error.clientMessage === 'string'
|
|
305
|
-
? error.clientMessage
|
|
306
|
-
: defaults?.clientMessage || undefined
|
|
307
|
-
const result: Error0GeneralProps = {
|
|
308
|
-
message,
|
|
309
|
-
code: 'code' in error && typeof error.code === 'string' ? error.code : defaults?.code || undefined,
|
|
310
|
-
clientMessage,
|
|
311
|
-
anyMessage: clientMessage || message || this.defaultMessage,
|
|
312
|
-
expected: undefined,
|
|
313
|
-
stack: 'stack' in error && typeof error.stack === 'string' ? error.stack : undefined,
|
|
314
|
-
tag: 'tag' in error && typeof error.tag === 'string' ? error.tag : defaults?.tag || undefined,
|
|
315
|
-
cause: 'cause' in error ? error.cause : defaults?.cause || undefined,
|
|
316
|
-
meta:
|
|
317
|
-
'meta' in error && typeof error.meta === 'object' && error.meta !== null
|
|
318
|
-
? Meta0.getValue(error.meta as Meta0.ValueType)
|
|
319
|
-
: Meta0.getValue(defaults?.meta) || {},
|
|
320
|
-
httpStatus:
|
|
321
|
-
'httpStatus' in error && typeof error.httpStatus === 'number' && error.httpStatus in HttpStatusCode
|
|
322
|
-
? error.httpStatus
|
|
323
|
-
: typeof defaults?.httpStatus === 'string'
|
|
324
|
-
? HttpStatusCode[defaults.httpStatus]
|
|
325
|
-
: defaults?.httpStatus,
|
|
326
|
-
zodError:
|
|
327
|
-
'zodError' in error && error.zodError instanceof ZodError
|
|
328
|
-
? error.zodError
|
|
329
|
-
: error instanceof ZodError
|
|
330
|
-
? error
|
|
331
|
-
: defaults?.zodError,
|
|
332
|
-
axiosError:
|
|
333
|
-
'axiosError' in error && isAxiosError(error.axiosError)
|
|
334
|
-
? error.axiosError
|
|
335
|
-
: isAxiosError(error)
|
|
336
|
-
? error
|
|
337
|
-
: defaults?.axiosError,
|
|
338
|
-
}
|
|
339
|
-
result.expected = this._normalizeSelfExpected(
|
|
340
|
-
result,
|
|
341
|
-
'expected' in error && (typeof error.expected === 'boolean' || typeof error.expected === 'function')
|
|
342
|
-
? (error.expected as ExpectedFn)
|
|
343
|
-
: defaults?.expected || undefined,
|
|
344
|
-
)
|
|
345
|
-
if (result.zodError) {
|
|
346
|
-
this._assignError0Props(result, this._getExtraError0PropsByZodError(result.zodError))
|
|
347
|
-
}
|
|
348
|
-
if (result.axiosError) {
|
|
349
|
-
this._assignError0Props(result, this._getExtraError0PropsByAxiosError(result.axiosError))
|
|
350
|
-
}
|
|
351
|
-
return result
|
|
283
|
+
export class Error0 extends Error {
|
|
284
|
+
static readonly __extensionsMap?: EmptyExtensionsMap
|
|
285
|
+
protected static _extensions: ErrorExtension[] = []
|
|
286
|
+
|
|
287
|
+
private static readonly _emptyExtension: ErrorExtensionResolved = {
|
|
288
|
+
props: {},
|
|
289
|
+
methods: {},
|
|
290
|
+
refine: [],
|
|
352
291
|
}
|
|
353
292
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
293
|
+
private static _getResolvedExtension(this: typeof Error0): ErrorExtensionResolved {
|
|
294
|
+
const resolved: ErrorExtensionResolved = {
|
|
295
|
+
props: {},
|
|
296
|
+
methods: {},
|
|
297
|
+
refine: [],
|
|
357
298
|
}
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
299
|
+
for (const extension of this._extensions) {
|
|
300
|
+
Object.assign(resolved.props, extension.props ?? this._emptyExtension.props)
|
|
301
|
+
Object.assign(resolved.methods, extension.methods ?? this._emptyExtension.methods)
|
|
302
|
+
resolved.refine.push(...(extension.refine ?? this._emptyExtension.refine))
|
|
362
303
|
}
|
|
363
|
-
|
|
364
|
-
causesProps.push(...this._getCausesPropsFromUnknown(this._getPropsFromUnknown(causeProps.cause), maxLevel - 1))
|
|
365
|
-
}
|
|
366
|
-
return causesProps
|
|
304
|
+
return resolved
|
|
367
305
|
}
|
|
368
306
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
307
|
+
constructor(message: string, input?: ErrorInput<EmptyExtensionsMap>)
|
|
308
|
+
constructor(input: { message: string } & ErrorInput<EmptyExtensionsMap>)
|
|
309
|
+
constructor(
|
|
310
|
+
...args:
|
|
311
|
+
| [message: string, input?: ErrorInput<EmptyExtensionsMap>]
|
|
312
|
+
| [{ message: string } & ErrorInput<EmptyExtensionsMap>]
|
|
313
|
+
) {
|
|
314
|
+
const [first, second] = args
|
|
315
|
+
const input = typeof first === 'string' ? { message: first, ...(second ?? {}) } : first
|
|
316
|
+
|
|
317
|
+
super(input.message, { cause: input.cause })
|
|
318
|
+
this.name = 'Error0'
|
|
375
319
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
320
|
+
const ctor = this.constructor as typeof Error0
|
|
321
|
+
const extension = ctor._getResolvedExtension()
|
|
322
|
+
|
|
323
|
+
for (const [key, prop] of Object.entries(extension.props)) {
|
|
324
|
+
if (key in input) {
|
|
325
|
+
const ownValue = (input as Record<string, unknown>)[key]
|
|
326
|
+
;(this as Record<string, unknown>)[key] = prop.init(ownValue)
|
|
327
|
+
} else {
|
|
328
|
+
Object.defineProperty(this, key, {
|
|
329
|
+
get: () => prop.resolve({ value: undefined, flow: this.flow(key), error: this }),
|
|
330
|
+
set: (value) => {
|
|
331
|
+
Object.defineProperty(this, key, {
|
|
332
|
+
value,
|
|
333
|
+
writable: true,
|
|
334
|
+
enumerable: true,
|
|
335
|
+
configurable: true,
|
|
336
|
+
})
|
|
337
|
+
},
|
|
338
|
+
enumerable: true,
|
|
339
|
+
configurable: true,
|
|
340
|
+
})
|
|
384
341
|
}
|
|
385
342
|
}
|
|
386
|
-
return undefined
|
|
387
343
|
}
|
|
388
344
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
// }
|
|
398
|
-
// }
|
|
399
|
-
// return undefined
|
|
400
|
-
// }
|
|
401
|
-
|
|
402
|
-
public static _getFilledPropValues<TPropKey extends keyof Error0Input>(
|
|
403
|
-
causesProps: Error0GeneralProps[],
|
|
404
|
-
propKey: TPropKey,
|
|
405
|
-
): NonNullable<Error0GeneralProps[TPropKey]>[] {
|
|
406
|
-
const values: NonNullable<Error0GeneralProps[TPropKey]>[] = []
|
|
407
|
-
for (const causeProps of causesProps) {
|
|
408
|
-
const propValue = causeProps[propKey]
|
|
409
|
-
if (isFilled(propValue)) {
|
|
410
|
-
values.push(propValue as NonNullable<Error0GeneralProps[TPropKey]>)
|
|
345
|
+
private static readonly isSelfProperty = (object: object, key: string): boolean => {
|
|
346
|
+
const d = Object.getOwnPropertyDescriptor(object, key)
|
|
347
|
+
if (!d) return false
|
|
348
|
+
if (typeof d.get === 'function' || typeof d.set === 'function') {
|
|
349
|
+
if ('name' in object && object.name === 'Error0') {
|
|
350
|
+
return false
|
|
351
|
+
} else {
|
|
352
|
+
return true
|
|
411
353
|
}
|
|
412
354
|
}
|
|
413
|
-
return
|
|
355
|
+
return true
|
|
414
356
|
}
|
|
415
357
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
return {}
|
|
420
|
-
} else if (metas.length === 1) {
|
|
421
|
-
return metas[0]
|
|
422
|
-
} else {
|
|
423
|
-
return Meta0.mergeValues(metas[0], ...metas.slice(1))
|
|
358
|
+
static own(error: object, key: string): unknown {
|
|
359
|
+
if (this.isSelfProperty(error, key)) {
|
|
360
|
+
return (error as Record<string, unknown>)[key]
|
|
424
361
|
}
|
|
362
|
+
return undefined
|
|
363
|
+
}
|
|
364
|
+
own(key: string): unknown {
|
|
365
|
+
const ctor = this.constructor as typeof Error0
|
|
366
|
+
return ctor.own(this, key)
|
|
425
367
|
}
|
|
426
368
|
|
|
427
|
-
|
|
369
|
+
static flow(error: object, key: string): unknown[] {
|
|
370
|
+
return this.causes(error, true).map((cause) => {
|
|
371
|
+
return this.own(cause, key)
|
|
372
|
+
})
|
|
373
|
+
}
|
|
374
|
+
flow(key: string): unknown[] {
|
|
375
|
+
const ctor = this.constructor as typeof Error0
|
|
376
|
+
return ctor.flow(this, key)
|
|
377
|
+
}
|
|
428
378
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
379
|
+
static causes(error: unknown, instancesOnly?: false): unknown[]
|
|
380
|
+
static causes<T extends typeof Error0>(this: T, error: unknown, instancesOnly: true): Array<InstanceType<T>>
|
|
381
|
+
static causes(error: unknown, instancesOnly?: boolean): unknown[] {
|
|
382
|
+
const causes: unknown[] = []
|
|
383
|
+
let current: unknown = error
|
|
384
|
+
const maxDepth = 99
|
|
385
|
+
const seen = new Set<unknown>()
|
|
386
|
+
for (let depth = 0; depth < maxDepth; depth += 1) {
|
|
387
|
+
if (seen.has(current)) {
|
|
388
|
+
break
|
|
389
|
+
}
|
|
390
|
+
seen.add(current)
|
|
391
|
+
if (!instancesOnly || this.is(current)) {
|
|
392
|
+
causes.push(current)
|
|
393
|
+
}
|
|
394
|
+
if (!current || typeof current !== 'object') {
|
|
395
|
+
break
|
|
396
|
+
}
|
|
397
|
+
current = (current as { cause?: unknown }).cause
|
|
432
398
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
399
|
+
return causes
|
|
400
|
+
}
|
|
401
|
+
causes<T extends typeof Error0>(this: T, instancesOnly?: false): [InstanceType<T>, ...unknown[]]
|
|
402
|
+
causes<T extends typeof Error0>(this: T, instancesOnly: true): [InstanceType<T>, ...Array<InstanceType<T>>]
|
|
403
|
+
causes(instancesOnly?: boolean): unknown[] {
|
|
404
|
+
const ctor = this.constructor as typeof Error0
|
|
405
|
+
if (instancesOnly) {
|
|
406
|
+
return ctor.causes(this, true)
|
|
436
407
|
}
|
|
437
|
-
|
|
438
|
-
removeAllLinesContains('at _toError0')
|
|
439
|
-
removeAllLinesContains('at Error0.from')
|
|
440
|
-
removeAllLinesContains('at Error0._toError0')
|
|
441
|
-
return lines.join('\n')
|
|
408
|
+
return ctor.causes(this)
|
|
442
409
|
}
|
|
443
410
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
nextStack: Error0GeneralProps['stack'],
|
|
447
|
-
): Error0GeneralProps['stack'] {
|
|
448
|
-
return [nextStack, prevStack].filter(Boolean).join('\n\n') || undefined
|
|
411
|
+
static is<T extends typeof Error0>(this: T, error: unknown): error is InstanceType<T> {
|
|
412
|
+
return error instanceof this
|
|
449
413
|
}
|
|
450
414
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
static isError0(error: unknown): error is Error0 {
|
|
454
|
-
return error instanceof Error0
|
|
415
|
+
static isSerialized(error: unknown): error is Record<string, unknown> {
|
|
416
|
+
return !this.is(error) && typeof error === 'object' && error !== null && 'name' in error && error.name === 'Error0'
|
|
455
417
|
}
|
|
456
418
|
|
|
457
|
-
static
|
|
458
|
-
if (error
|
|
459
|
-
return
|
|
419
|
+
static from(error: unknown): Error0 {
|
|
420
|
+
if (this.is(error)) {
|
|
421
|
+
return error
|
|
460
422
|
}
|
|
423
|
+
if (this.isSerialized(error)) {
|
|
424
|
+
return this._fromSerialized(error)
|
|
425
|
+
}
|
|
426
|
+
return this._fromNonError0(error)
|
|
427
|
+
}
|
|
461
428
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
429
|
+
private static _applyRefine(error: Error0): Error0 {
|
|
430
|
+
const extension = this._getResolvedExtension()
|
|
431
|
+
for (const refine of extension.refine) {
|
|
432
|
+
const refined = refine(error as any)
|
|
433
|
+
if (refined && typeof refined === 'object') {
|
|
434
|
+
Object.assign(error as unknown as Record<string, unknown>, refined)
|
|
465
435
|
}
|
|
466
436
|
}
|
|
467
|
-
|
|
468
|
-
return false
|
|
437
|
+
return error
|
|
469
438
|
}
|
|
470
439
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
440
|
+
private static _fromSerialized(error: unknown): Error0 {
|
|
441
|
+
const message = this._extractMessage(error)
|
|
442
|
+
if (typeof error !== 'object' || error === null) {
|
|
443
|
+
return this._applyRefine(new this(message, { cause: error }))
|
|
474
444
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
445
|
+
const errorRecord = error as Record<string, unknown>
|
|
446
|
+
const recreated = new this(message)
|
|
447
|
+
const extension = this._getResolvedExtension()
|
|
448
|
+
const propsEntries = Object.entries(extension.props)
|
|
449
|
+
for (const [key, prop] of propsEntries) {
|
|
450
|
+
if (!(key in errorRecord)) {
|
|
451
|
+
continue
|
|
452
|
+
}
|
|
453
|
+
try {
|
|
454
|
+
const value = prop.deserialize({ value: errorRecord[key], serialized: errorRecord })
|
|
455
|
+
;(recreated as unknown as Record<string, unknown>)[key] = value
|
|
456
|
+
} catch {
|
|
457
|
+
// ignore
|
|
458
|
+
}
|
|
478
459
|
}
|
|
460
|
+
// we do not serialize causes
|
|
461
|
+
// ;(recreated as unknown as { cause?: unknown }).cause = errorRecord.cause
|
|
462
|
+
const isStackInProps = propsEntries.some(([key]) => key === 'stack')
|
|
463
|
+
if (typeof errorRecord.stack === 'string' && !isStackInProps) {
|
|
464
|
+
recreated.stack = errorRecord.stack
|
|
465
|
+
}
|
|
466
|
+
return recreated
|
|
467
|
+
}
|
|
479
468
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
469
|
+
private static _fromNonError0(error: unknown): Error0 {
|
|
470
|
+
const message = this._extractMessage(error)
|
|
471
|
+
return this._applyRefine(new this(message, { cause: error }))
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
private static _extractMessage(error: unknown): string {
|
|
475
|
+
return (
|
|
476
|
+
(typeof error === 'string'
|
|
477
|
+
? error
|
|
478
|
+
: typeof error === 'object' && error !== null && 'message' in error && typeof error.message === 'string'
|
|
479
|
+
? error.message
|
|
480
|
+
: undefined) || 'Unknown error'
|
|
481
|
+
)
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
private static _extendWithExtension(
|
|
485
|
+
this: typeof Error0,
|
|
486
|
+
extension: ErrorExtension<ErrorExtensionProps, ErrorExtensionMethods>,
|
|
487
|
+
): ClassError0 {
|
|
488
|
+
const Base = this as unknown as typeof Error0
|
|
489
|
+
const Error0Extended = class Error0 extends Base {}
|
|
490
|
+
;(Error0Extended as typeof Error0)._extensions = [...Base._extensions, extension]
|
|
491
|
+
|
|
492
|
+
const resolved = (Error0Extended as typeof Error0)._getResolvedExtension()
|
|
493
|
+
for (const [key, method] of Object.entries(resolved.methods)) {
|
|
494
|
+
Object.defineProperty((Error0Extended as typeof Error0).prototype, key, {
|
|
495
|
+
value: function (...args: unknown[]) {
|
|
496
|
+
return method(this as Error0, ...args)
|
|
497
|
+
},
|
|
498
|
+
writable: true,
|
|
499
|
+
enumerable: true,
|
|
500
|
+
configurable: true,
|
|
501
|
+
})
|
|
502
|
+
Object.defineProperty(Error0Extended, key, {
|
|
503
|
+
value: function (error: unknown, ...args: unknown[]) {
|
|
504
|
+
return method(this.from(error), ...args)
|
|
505
|
+
},
|
|
506
|
+
writable: true,
|
|
507
|
+
enumerable: true,
|
|
508
|
+
configurable: true,
|
|
484
509
|
})
|
|
485
510
|
}
|
|
486
511
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
512
|
+
return Error0Extended as unknown as ClassError0
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
private static _extensionFromBuilder(
|
|
516
|
+
extension: ExtensionError0,
|
|
517
|
+
): ErrorExtension<ErrorExtensionProps, ErrorExtensionMethods> {
|
|
518
|
+
const extensionRecord = extension as unknown as {
|
|
519
|
+
_extension: ErrorExtension<ErrorExtensionProps, ErrorExtensionMethods>
|
|
492
520
|
}
|
|
521
|
+
return {
|
|
522
|
+
props: { ...(extensionRecord._extension.props ?? {}) },
|
|
523
|
+
methods: { ...(extensionRecord._extension.methods ?? {}) },
|
|
524
|
+
refine: [...(extensionRecord._extension.refine ?? [])],
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
static prop<TThis extends typeof Error0, TKey extends string, TInputValue, TOutputValue>(
|
|
529
|
+
this: TThis,
|
|
530
|
+
key: TKey,
|
|
531
|
+
value: ErrorExtensionPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<ExtensionsMapOf<TThis>>>,
|
|
532
|
+
): ClassError0<ExtendErrorExtensionsMapWithProp<ExtensionsMapOf<TThis>, TKey, TInputValue, TOutputValue>> {
|
|
533
|
+
return this.extend('prop', key, value)
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
static method<TThis extends typeof Error0, TKey extends string, TArgs extends unknown[], TOutputValue>(
|
|
537
|
+
this: TThis,
|
|
538
|
+
key: TKey,
|
|
539
|
+
value: ErrorExtensionMethodFn<TOutputValue, TArgs, ErrorInstanceOfMap<ExtensionsMapOf<TThis>>>,
|
|
540
|
+
): ClassError0<ExtendErrorExtensionsMapWithMethod<ExtensionsMapOf<TThis>, TKey, TArgs, TOutputValue>> {
|
|
541
|
+
return this.extend('method', key, value)
|
|
542
|
+
}
|
|
493
543
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
544
|
+
static refine<TThis extends typeof Error0>(
|
|
545
|
+
this: TThis,
|
|
546
|
+
value: ErrorExtensionRefineFn<ErrorInstanceOfMap<ExtensionsMapOf<TThis>>, ErrorOutputProps<ExtensionsMapOf<TThis>>>,
|
|
547
|
+
): ClassError0<ExtensionsMapOf<TThis>> {
|
|
548
|
+
return this.extend('refine', value)
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
static extend<TThis extends typeof Error0, TBuilder extends ExtensionError0>(
|
|
552
|
+
this: TThis,
|
|
553
|
+
extension: TBuilder,
|
|
554
|
+
): ClassError0<ExtendErrorExtensionsMap<ExtensionsMapOf<TThis>, ExtensionOfBuilder<TBuilder>>>
|
|
555
|
+
static extend<TThis extends typeof Error0, TKey extends string, TInputValue, TOutputValue>(
|
|
556
|
+
this: TThis,
|
|
557
|
+
kind: 'prop',
|
|
558
|
+
key: TKey,
|
|
559
|
+
value: ErrorExtensionPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<ExtensionsMapOf<TThis>>>,
|
|
560
|
+
): ClassError0<ExtendErrorExtensionsMapWithProp<ExtensionsMapOf<TThis>, TKey, TInputValue, TOutputValue>>
|
|
561
|
+
static extend<TThis extends typeof Error0, TKey extends string, TArgs extends unknown[], TOutputValue>(
|
|
562
|
+
this: TThis,
|
|
563
|
+
kind: 'method',
|
|
564
|
+
key: TKey,
|
|
565
|
+
value: ErrorExtensionMethodFn<TOutputValue, TArgs, ErrorInstanceOfMap<ExtensionsMapOf<TThis>>>,
|
|
566
|
+
): ClassError0<ExtendErrorExtensionsMapWithMethod<ExtensionsMapOf<TThis>, TKey, TArgs, TOutputValue>>
|
|
567
|
+
static extend<TThis extends typeof Error0>(
|
|
568
|
+
this: TThis,
|
|
569
|
+
kind: 'refine',
|
|
570
|
+
value: ErrorExtensionRefineFn<ErrorInstanceOfMap<ExtensionsMapOf<TThis>>, ErrorOutputProps<ExtensionsMapOf<TThis>>>,
|
|
571
|
+
): ClassError0<ExtensionsMapOf<TThis>>
|
|
572
|
+
static extend(
|
|
573
|
+
this: typeof Error0,
|
|
574
|
+
first: ExtensionError0 | 'prop' | 'method' | 'refine',
|
|
575
|
+
key?: string | ErrorExtensionRefineFn<any, any>,
|
|
576
|
+
value?: ErrorExtensionPropOptions<unknown, unknown> | ErrorExtensionMethodFn<unknown>,
|
|
577
|
+
): ClassError0 {
|
|
578
|
+
if (first instanceof ExtensionError0) {
|
|
579
|
+
return this._extendWithExtension(this._extensionFromBuilder(first))
|
|
580
|
+
}
|
|
581
|
+
if (first === 'refine') {
|
|
582
|
+
if (typeof key !== 'function') {
|
|
583
|
+
throw new Error('Error0.extend("refine", value) requires refine function')
|
|
498
584
|
}
|
|
585
|
+
return this._extendWithExtension({
|
|
586
|
+
refine: [key],
|
|
587
|
+
})
|
|
588
|
+
}
|
|
589
|
+
if (typeof key !== 'string' || value === undefined) {
|
|
590
|
+
throw new Error('Error0.extend(kind, key, value) requires key and value')
|
|
499
591
|
}
|
|
500
592
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
return this._toError0(error, inputOverride)
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
static extend(props: {
|
|
509
|
-
defaultMessage?: Error0GeneralProps['message']
|
|
510
|
-
defaultCode?: Error0GeneralProps['code']
|
|
511
|
-
defaultHttpStatus?: Error0GeneralProps['httpStatus']
|
|
512
|
-
defaultExpected?: Error0GeneralProps['expected']
|
|
513
|
-
defaultClientMessage?: Error0GeneralProps['clientMessage']
|
|
514
|
-
defaultMeta?: Meta0.Meta0OrValueTypeNullish
|
|
515
|
-
}) {
|
|
516
|
-
const parent = this
|
|
517
|
-
return class Error0 extends parent {
|
|
518
|
-
static override defaultMessage = props.defaultMessage ?? parent.defaultMessage
|
|
519
|
-
static override defaultCode = props.defaultCode ?? parent.defaultCode
|
|
520
|
-
static override defaultHttpStatus = props.defaultHttpStatus ?? parent.defaultHttpStatus
|
|
521
|
-
static override defaultExpected = props.defaultExpected ?? parent.defaultExpected
|
|
522
|
-
static override defaultClientMessage = props.defaultClientMessage ?? parent.defaultClientMessage
|
|
523
|
-
static override defaultMeta = Meta0.extend(props.defaultMeta, parent.defaultMeta)
|
|
593
|
+
if (first === 'prop') {
|
|
594
|
+
return this._extendWithExtension({
|
|
595
|
+
props: { [key]: value as ErrorExtensionPropOptions<unknown, unknown> },
|
|
596
|
+
})
|
|
524
597
|
}
|
|
598
|
+
return this._extendWithExtension({
|
|
599
|
+
methods: { [key]: value as ErrorExtensionMethodFn<unknown> },
|
|
600
|
+
})
|
|
525
601
|
}
|
|
526
602
|
|
|
527
|
-
static
|
|
528
|
-
|
|
529
|
-
props: {
|
|
530
|
-
defaultMessage?: Error0GeneralProps['message']
|
|
531
|
-
defaultCode?: Error0GeneralProps['code']
|
|
532
|
-
defaultHttpStatus?: Error0GeneralProps['httpStatus']
|
|
533
|
-
defaultExpected?: Error0GeneralProps['expected']
|
|
534
|
-
defaultClientMessage?: Error0GeneralProps['clientMessage']
|
|
535
|
-
defaultMeta?: Meta0.Meta0OrValueTypeNullish
|
|
536
|
-
},
|
|
537
|
-
): T {
|
|
538
|
-
return Object.fromEntries(Object.entries(classes).map(([name, Class]) => [name, Class.extend(props)])) as T
|
|
603
|
+
static extension(): ExtensionError0 {
|
|
604
|
+
return new ExtensionError0()
|
|
539
605
|
}
|
|
540
606
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
clientMessage: this.clientMessage,
|
|
549
|
-
anyMessage: this.anyMessage,
|
|
550
|
-
cause: this.cause,
|
|
551
|
-
meta: Meta0.getValue(this.meta),
|
|
552
|
-
stack: this.stack,
|
|
553
|
-
__I_AM_ERROR_0: this.__I_AM_ERROR_0,
|
|
607
|
+
static serialize(error: unknown, isPublic = true): Record<string, unknown> {
|
|
608
|
+
const error0 = this.from(error)
|
|
609
|
+
const json: Record<string, unknown> = {
|
|
610
|
+
name: error0.name,
|
|
611
|
+
message: error0.message,
|
|
612
|
+
// we do not serialize causes, it is enough that we have floated props and refine helper
|
|
613
|
+
// cause: error0.cause,
|
|
554
614
|
}
|
|
615
|
+
|
|
616
|
+
const extension = this._getResolvedExtension()
|
|
617
|
+
const propsEntries = Object.entries(extension.props)
|
|
618
|
+
for (const [key, prop] of propsEntries) {
|
|
619
|
+
try {
|
|
620
|
+
const value = prop.resolve({ value: error0.own(key), flow: error0.flow(key), error: error0 })
|
|
621
|
+
const jsonValue = prop.serialize({ value, error: error0, isPublic })
|
|
622
|
+
if (jsonValue !== undefined) {
|
|
623
|
+
json[key] = jsonValue
|
|
624
|
+
}
|
|
625
|
+
} catch {
|
|
626
|
+
// ignore
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
const isStackInProps = propsEntries.some(([key]) => key === 'stack')
|
|
630
|
+
if (!isStackInProps && typeof error0.stack === 'string') {
|
|
631
|
+
json.stack = error0.stack
|
|
632
|
+
}
|
|
633
|
+
return Object.fromEntries(Object.entries(json).filter(([, value]) => value !== undefined)) as Record<
|
|
634
|
+
string,
|
|
635
|
+
unknown
|
|
636
|
+
>
|
|
555
637
|
}
|
|
556
|
-
static toJSON(error: unknown, inputOverride?: Error0Input) {
|
|
557
|
-
const error0 = this.from(error, inputOverride)
|
|
558
|
-
return error0.toJSON()
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
toResponse(data?: Record<string, unknown>) {
|
|
562
|
-
return Response.json(
|
|
563
|
-
{
|
|
564
|
-
...this.toJSON(),
|
|
565
|
-
...data,
|
|
566
|
-
},
|
|
567
|
-
{
|
|
568
|
-
status: this.httpStatus,
|
|
569
|
-
statusText: this.message,
|
|
570
|
-
},
|
|
571
|
-
)
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
638
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
639
|
+
serialize(isPublic = true): object {
|
|
640
|
+
const ctor = this.constructor as typeof Error0
|
|
641
|
+
return ctor.serialize(this, isPublic)
|
|
642
|
+
}
|
|
578
643
|
}
|
|
579
|
-
|
|
580
|
-
export const e0s = {
|
|
581
|
-
Default: Error0,
|
|
582
|
-
Expected: Error0.extend({
|
|
583
|
-
defaultExpected: true,
|
|
584
|
-
}) as typeof Error0,
|
|
585
|
-
} satisfies Error0.Collection
|