@devp0nt/error0 1.0.0-next.5 → 1.0.0-next.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/cjs/index.cjs +614 -0
  2. package/dist/cjs/index.cjs.map +1 -0
  3. package/dist/cjs/index.d.cts +345 -414
  4. package/dist/cjs/plugins/cause.cjs +63 -0
  5. package/dist/cjs/plugins/cause.cjs.map +1 -0
  6. package/dist/cjs/plugins/cause.d.cts +15 -0
  7. package/dist/cjs/plugins/code.cjs +46 -0
  8. package/dist/cjs/plugins/code.cjs.map +1 -0
  9. package/dist/cjs/plugins/code.d.cts +8 -0
  10. package/dist/cjs/plugins/expected.cjs +67 -0
  11. package/dist/cjs/plugins/expected.cjs.map +1 -0
  12. package/dist/cjs/plugins/expected.d.cts +37 -0
  13. package/dist/cjs/plugins/message-merge.cjs +39 -0
  14. package/dist/cjs/plugins/message-merge.cjs.map +1 -0
  15. package/dist/cjs/plugins/message-merge.d.cts +8 -0
  16. package/dist/cjs/plugins/meta.cjs +78 -0
  17. package/dist/cjs/plugins/meta.cjs.map +1 -0
  18. package/dist/cjs/plugins/meta.d.cts +7 -0
  19. package/dist/cjs/plugins/stack-merge.cjs +42 -0
  20. package/dist/cjs/plugins/stack-merge.cjs.map +1 -0
  21. package/dist/cjs/plugins/stack-merge.d.cts +8 -0
  22. package/dist/cjs/plugins/status.cjs +60 -0
  23. package/dist/cjs/plugins/status.cjs.map +1 -0
  24. package/dist/cjs/plugins/status.d.cts +9 -0
  25. package/dist/cjs/plugins/tags.cjs +73 -0
  26. package/dist/cjs/plugins/tags.cjs.map +1 -0
  27. package/dist/cjs/plugins/tags.d.cts +12 -0
  28. package/dist/esm/index.d.ts +345 -414
  29. package/dist/esm/index.js +530 -341
  30. package/dist/esm/index.js.map +1 -1
  31. package/dist/esm/plugins/cause.d.ts +15 -0
  32. package/dist/esm/plugins/cause.js +39 -0
  33. package/dist/esm/plugins/cause.js.map +1 -0
  34. package/dist/esm/plugins/code.d.ts +8 -0
  35. package/dist/esm/plugins/code.js +22 -0
  36. package/dist/esm/plugins/code.js.map +1 -0
  37. package/dist/esm/plugins/expected.d.ts +37 -0
  38. package/dist/esm/plugins/expected.js +43 -0
  39. package/dist/esm/plugins/expected.js.map +1 -0
  40. package/dist/esm/plugins/message-merge.d.ts +8 -0
  41. package/dist/esm/plugins/message-merge.js +15 -0
  42. package/dist/esm/plugins/message-merge.js.map +1 -0
  43. package/dist/esm/plugins/meta.d.ts +7 -0
  44. package/dist/esm/plugins/meta.js +54 -0
  45. package/dist/esm/plugins/meta.js.map +1 -0
  46. package/dist/esm/plugins/stack-merge.d.ts +8 -0
  47. package/dist/esm/plugins/stack-merge.js +18 -0
  48. package/dist/esm/plugins/stack-merge.js.map +1 -0
  49. package/dist/esm/plugins/status.d.ts +9 -0
  50. package/dist/esm/plugins/status.js +36 -0
  51. package/dist/esm/plugins/status.js.map +1 -0
  52. package/dist/esm/plugins/tags.d.ts +12 -0
  53. package/dist/esm/plugins/tags.js +49 -0
  54. package/dist/esm/plugins/tags.js.map +1 -0
  55. package/package.json +53 -23
  56. package/src/index.test.ts +696 -452
  57. package/src/index.ts +1178 -502
  58. package/src/plugins/cause.test.ts +106 -0
  59. package/src/plugins/cause.ts +45 -0
  60. package/src/plugins/code.test.ts +27 -0
  61. package/src/plugins/code.ts +20 -0
  62. package/src/plugins/expected.test.ts +66 -0
  63. package/src/plugins/expected.ts +48 -0
  64. package/src/plugins/message-merge.test.ts +32 -0
  65. package/src/plugins/message-merge.ts +19 -0
  66. package/src/plugins/meta.test.ts +32 -0
  67. package/src/plugins/meta.ts +59 -0
  68. package/src/plugins/stack-merge.test.ts +57 -0
  69. package/src/plugins/stack-merge.ts +20 -0
  70. package/src/plugins/status.test.ts +54 -0
  71. package/src/plugins/status.ts +35 -0
  72. package/src/plugins/tags.test.ts +74 -0
  73. package/src/plugins/tags.ts +51 -0
  74. package/dist/cjs/index.js +0 -435
  75. package/dist/cjs/index.js.map +0 -1
package/src/index.ts CHANGED
@@ -1,585 +1,1261 @@
1
- import { Meta0 } from '@devp0nt/meta0'
2
- import { type AxiosError, HttpStatusCode, isAxiosError } from 'axios'
3
- import get from 'lodash/get.js'
4
- import { ZodError } from 'zod'
5
-
6
- // TODO: В эррор0 добавить ориджинал
7
- // TODO: store tags as array from all causes
8
- // TODO: not use self stack if toError0
9
- // TODO: fix default message in extended error0, should be used in constuctor of Error0
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
+ type IsUnknown<T> = unknown extends T ? ([T] extends [unknown] ? true : false) : false
2
+ type NormalizeUnknownToUndefined<T> = IsUnknown<T> extends true ? undefined : T
3
+ type IsOnlyUndefined<T> = [Exclude<T, undefined>] extends [never] ? true : false
4
+ type InferFirstArg<TFn> = TFn extends (...args: infer TArgs) => unknown
5
+ ? TArgs extends [infer TFirst, ...unknown[]]
6
+ ? TFirst
7
+ : undefined
8
+ : undefined
9
+ type InferPluginPropInput<TProp extends ErrorPluginPropOptions<any, any, any, any>> = TProp extends {
10
+ init: infer TInit
25
11
  }
12
+ ? NormalizeUnknownToUndefined<InferFirstArg<TInit>>
13
+ : undefined
14
+ type ErrorPluginPropInit<TInputValue, TOutputValue> = ((input: TInputValue) => TOutputValue) | (() => TOutputValue)
15
+ type ErrorPluginPropSerializeOptions<
16
+ TOutputValue,
17
+ TError extends Error0,
18
+ TResolveValue extends TOutputValue | undefined,
19
+ > = {
20
+ own: TOutputValue | undefined
21
+ flow: Array<TOutputValue | undefined>
22
+ resolved: TResolveValue
23
+ error: TError
24
+ isPublic: boolean
25
+ }
26
+ type ErrorPluginPropSerialize<TOutputValue, TError extends Error0, TResolveValue extends TOutputValue | undefined> =
27
+ | ((options: ErrorPluginPropSerializeOptions<TOutputValue, TError, TResolveValue>) => unknown)
28
+ | false
29
+ type ErrorPluginPropDeserialize<TOutputValue> =
30
+ | ((options: { value: unknown; record: Record<string, unknown> }) => TOutputValue | undefined)
31
+ | false
32
+ type ErrorPluginPropOptionsResolveOptions<TOutputValue, TError extends Error0> = {
33
+ own: TOutputValue | undefined
34
+ flow: Array<TOutputValue | undefined>
35
+ error: TError
36
+ }
37
+ type ErrorPluginPropOptionsBase<TOutputValue, TError extends Error0, TResolveValue extends TOutputValue | undefined> = {
38
+ resolve: (options: ErrorPluginPropOptionsResolveOptions<TOutputValue, TError>) => TResolveValue
39
+ serialize: ErrorPluginPropSerialize<TOutputValue, TError, TResolveValue>
40
+ deserialize: ErrorPluginPropDeserialize<TOutputValue>
41
+ }
42
+ type ErrorPluginPropOptionsWithInit<
43
+ TInputValue,
44
+ TOutputValue,
45
+ TError extends Error0,
46
+ TResolveValue extends TOutputValue | undefined,
47
+ > = ErrorPluginPropOptionsBase<TOutputValue, TError, TResolveValue> & {
48
+ init: ErrorPluginPropInit<TInputValue, TOutputValue>
49
+ }
50
+ type ErrorPluginPropOptionsWithoutInit<
51
+ TOutputValue,
52
+ TError extends Error0,
53
+ TResolveValue extends TOutputValue | undefined,
54
+ > = ErrorPluginPropOptionsBase<TOutputValue, TError, TResolveValue> & {
55
+ init?: undefined
56
+ }
57
+ export type ErrorPluginPropOptions<
58
+ TInputValue = undefined,
59
+ TOutputValue = unknown,
60
+ TError extends Error0 = Error0,
61
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
62
+ > =
63
+ | ErrorPluginPropOptionsWithInit<TInputValue, TOutputValue, TError, TResolveValue>
64
+ | ErrorPluginPropOptionsWithoutInit<TOutputValue, TError, TResolveValue>
65
+ export type ErrorPluginMethodFn<TOutputValue, TArgs extends unknown[] = unknown[], TError extends Error0 = Error0> = (
66
+ error: TError,
67
+ ...args: TArgs
68
+ ) => TOutputValue
69
+ type ErrorPluginAnyMethodFn = (error: any, ...args: any[]) => any
70
+ export type ErrorPluginAdaptResult<TOutputProps extends Record<string, unknown>> = Partial<TOutputProps> | undefined
71
+ export type ErrorPluginAdaptFn<
72
+ TError extends Error0 = Error0,
73
+ TOutputProps extends Record<string, unknown> = Record<never, never>,
74
+ > = ((error: TError) => void) | ((error: TError) => ErrorPluginAdaptResult<TOutputProps>)
75
+ export type ErrorPluginStackSerialize<TError extends Error0> = (options: {
76
+ value: string | undefined
77
+ error: TError
78
+ isPublic: boolean
79
+ }) => unknown
80
+ export type ErrorPluginStack<TError extends Error0 = Error0> = { serialize: ErrorPluginStackSerialize<TError> }
81
+ export type ErrorPluginCauseSerialize<TError extends Error0> = (options: {
82
+ cause: unknown
83
+ error: TError
84
+ isPublic: boolean
85
+ is: (cause: unknown) => boolean
86
+ serialize: (cause: unknown) => Record<string, unknown>
87
+ }) => unknown
88
+ export type ErrorPluginCauseDeserialize = (options: {
89
+ cause: unknown
90
+ error: Record<string, unknown>
91
+ isSerialized: (serializedCause: unknown) => boolean
92
+ fromSerialized: (serializedCause: unknown) => Error0
93
+ }) => unknown
94
+ export type ErrorPluginCause<TError extends Error0 = Error0> = {
95
+ serialize: ErrorPluginCauseSerialize<TError>
96
+ deserialize: ErrorPluginCauseDeserialize
97
+ }
98
+ export type ErrorPluginMessageSerialize<TError extends Error0> = (options: {
99
+ value: string
100
+ error: TError
101
+ isPublic: boolean
102
+ }) => unknown
103
+ export type ErrorPluginMessage<TError extends Error0 = Error0> = { serialize: ErrorPluginMessageSerialize<TError> }
104
+ type ErrorMethodRecord = { fn: ErrorPluginAnyMethodFn }
105
+
106
+ export type ErrorPluginProps = { [key: string]: ErrorPluginPropOptions<any, any> }
107
+ export type ErrorPluginMethods = { [key: string]: ErrorPluginAnyMethodFn }
26
108
 
27
- interface Error0GeneralProps {
28
- message: Error0Input['message']
29
- tag: Error0Input['tag']
30
- code: Error0Input['code']
31
- httpStatus: number | undefined
32
- expected: boolean | undefined
33
- clientMessage: Error0Input['clientMessage']
34
- anyMessage: string | undefined
35
- cause: Error0Input['cause']
36
- stack: Error['stack']
37
- meta: Meta0.ValueType
38
- zodError?: ZodError
39
- axiosError?: AxiosError
109
+ export type ErrorPlugin<
110
+ TProps extends ErrorPluginProps = Record<never, never>,
111
+ TMethods extends ErrorPluginMethods = Record<never, never>,
112
+ > = {
113
+ props?: TProps
114
+ methods?: TMethods
115
+ adapt?: Array<ErrorPluginAdaptFn<Error0, PluginOutputProps<TProps>>>
116
+ stack?: ErrorPluginStack
117
+ cause?: ErrorPluginCause
118
+ message?: ErrorPluginMessage
40
119
  }
120
+ type AddPropToPluginProps<
121
+ TProps extends ErrorPluginProps,
122
+ TKey extends string,
123
+ TInputValue,
124
+ TOutputValue,
125
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
126
+ > = TProps & Record<TKey, ErrorPluginPropOptions<TInputValue, TOutputValue, Error0, TResolveValue>>
127
+ type AddMethodToPluginMethods<
128
+ TMethods extends ErrorPluginMethods,
129
+ TKey extends string,
130
+ TMethod extends ErrorPluginAnyMethodFn,
131
+ > = TMethods & Record<TKey, TMethod>
132
+ type PluginOutputProps<TProps extends ErrorPluginProps> = {
133
+ [TKey in keyof TProps]: TProps[TKey] extends ErrorPluginPropOptions<any, any, any, infer TResolveValue>
134
+ ? TResolveValue
135
+ : never
136
+ }
137
+ export type ErrorPluginsMap = {
138
+ props: Record<string, { init: unknown; output: unknown; resolve: unknown }>
139
+ methods: Record<string, ErrorMethodRecord>
140
+ }
141
+ export type IsEmptyObject<T> = keyof T extends never ? true : false
142
+ export type ErrorInputBase = {
143
+ cause?: unknown
144
+ }
145
+ type ErrorInputPluginProps<TPluginsMap extends ErrorPluginsMap> = {
146
+ [TKey in keyof TPluginsMap['props'] as IsOnlyUndefined<TPluginsMap['props'][TKey]['init']> extends true
147
+ ? never
148
+ : TKey]?: TPluginsMap['props'][TKey]['init']
149
+ }
150
+ export type ErrorInput<TPluginsMap extends ErrorPluginsMap> =
151
+ IsEmptyObject<TPluginsMap['props']> extends true
152
+ ? ErrorInputBase
153
+ : ErrorInputBase & ErrorInputPluginProps<TPluginsMap>
41
154
 
42
- type HttpStatusCodeString = keyof typeof HttpStatusCode
43
- type Error0Cause = Error | Error0 | unknown
44
- type ExpectedFn = (error: Error0GeneralProps) => boolean | undefined
155
+ type ErrorResolvedProps<TPluginsMap extends ErrorPluginsMap> = {
156
+ [TKey in keyof TPluginsMap['props']]: TPluginsMap['props'][TKey]['resolve']
157
+ }
158
+ type ErrorOwnProps<TPluginsMap extends ErrorPluginsMap> = {
159
+ [TKey in keyof TPluginsMap['props']]: TPluginsMap['props'][TKey]['output'] | undefined
160
+ }
161
+ type ErrorOwnMethods<TPluginsMap extends ErrorPluginsMap> = {
162
+ own: {
163
+ (): ErrorOwnProps<TPluginsMap>
164
+ <TKey extends keyof TPluginsMap['props'] & string>(key: TKey): ErrorOwnProps<TPluginsMap>[TKey]
165
+ }
166
+ flow: <TKey extends keyof TPluginsMap['props'] & string>(key: TKey) => Array<ErrorOwnProps<TPluginsMap>[TKey]>
167
+ }
168
+ type ErrorResolveMethods<TPluginsMap extends ErrorPluginsMap> = {
169
+ resolve: () => ErrorResolvedProps<TPluginsMap>
170
+ }
171
+ type BindInstanceMethod<TMethod> = TMethod extends {
172
+ (error: any, ...args: infer TArgs1): infer TOutput1
173
+ (error: any, ...args: infer TArgs2): infer TOutput2
174
+ (error: any, ...args: infer TArgs3): infer TOutput3
175
+ (error: any, ...args: infer TArgs4): infer TOutput4
176
+ }
177
+ ? {
178
+ (...args: TArgs1): TOutput1
179
+ (...args: TArgs2): TOutput2
180
+ (...args: TArgs3): TOutput3
181
+ (...args: TArgs4): TOutput4
182
+ }
183
+ : TMethod extends {
184
+ (error: any, ...args: infer TArgs1): infer TOutput1
185
+ (error: any, ...args: infer TArgs2): infer TOutput2
186
+ (error: any, ...args: infer TArgs3): infer TOutput3
187
+ }
188
+ ? {
189
+ (...args: TArgs1): TOutput1
190
+ (...args: TArgs2): TOutput2
191
+ (...args: TArgs3): TOutput3
192
+ }
193
+ : TMethod extends {
194
+ (error: any, ...args: infer TArgs1): infer TOutput1
195
+ (error: any, ...args: infer TArgs2): infer TOutput2
196
+ }
197
+ ? {
198
+ (...args: TArgs1): TOutput1
199
+ (...args: TArgs2): TOutput2
200
+ }
201
+ : TMethod extends (error: any, ...args: infer TArgs) => infer TOutput
202
+ ? (...args: TArgs) => TOutput
203
+ : never
204
+ type BindStaticMethod<TMethod> = TMethod extends {
205
+ (error: any, ...args: infer TArgs1): infer TOutput1
206
+ (error: any, ...args: infer TArgs2): infer TOutput2
207
+ (error: any, ...args: infer TArgs3): infer TOutput3
208
+ (error: any, ...args: infer TArgs4): infer TOutput4
209
+ }
210
+ ? {
211
+ (error: unknown, ...args: TArgs1): TOutput1
212
+ (error: unknown, ...args: TArgs2): TOutput2
213
+ (error: unknown, ...args: TArgs3): TOutput3
214
+ (error: unknown, ...args: TArgs4): TOutput4
215
+ }
216
+ : TMethod extends {
217
+ (error: any, ...args: infer TArgs1): infer TOutput1
218
+ (error: any, ...args: infer TArgs2): infer TOutput2
219
+ (error: any, ...args: infer TArgs3): infer TOutput3
220
+ }
221
+ ? {
222
+ (error: unknown, ...args: TArgs1): TOutput1
223
+ (error: unknown, ...args: TArgs2): TOutput2
224
+ (error: unknown, ...args: TArgs3): TOutput3
225
+ }
226
+ : TMethod extends {
227
+ (error: any, ...args: infer TArgs1): infer TOutput1
228
+ (error: any, ...args: infer TArgs2): infer TOutput2
229
+ }
230
+ ? {
231
+ (error: unknown, ...args: TArgs1): TOutput1
232
+ (error: unknown, ...args: TArgs2): TOutput2
233
+ }
234
+ : TMethod extends (error: any, ...args: infer TArgs) => infer TOutput
235
+ ? (error: unknown, ...args: TArgs) => TOutput
236
+ : never
237
+ type ErrorMethods<TPluginsMap extends ErrorPluginsMap> = {
238
+ [TKey in keyof TPluginsMap['methods']]: BindInstanceMethod<TPluginsMap['methods'][TKey]['fn']>
239
+ }
240
+ export type ErrorResolved<TPluginsMap extends ErrorPluginsMap> = ErrorResolvedProps<TPluginsMap> &
241
+ ErrorMethods<TPluginsMap>
45
242
 
46
- const isFilled = <T>(value: T): value is NonNullable<T> => value !== null && value !== undefined && value !== ''
243
+ type ErrorStaticMethods<TPluginsMap extends ErrorPluginsMap> = {
244
+ [TKey in keyof TPluginsMap['methods']]: BindStaticMethod<TPluginsMap['methods'][TKey]['fn']>
245
+ }
47
246
 
48
- export class Error0 extends Error {
49
- public readonly __I_AM_ERROR_0: true = true
50
-
51
- public readonly tag?: Error0GeneralProps['tag']
52
- public readonly code?: Error0GeneralProps['code']
53
- public readonly httpStatus?: Error0GeneralProps['httpStatus']
54
- public readonly expected?: Error0GeneralProps['expected']
55
- public readonly clientMessage?: Error0GeneralProps['clientMessage']
56
- public readonly anyMessage?: Error0GeneralProps['anyMessage']
57
- public override readonly cause?: Error0GeneralProps['cause']
58
- public readonly meta?: Meta0.Meta0OrValueTypeNullish
59
- public readonly zodError?: Error0GeneralProps['zodError']
60
- public readonly axiosError?: Error0GeneralProps['axiosError']
61
-
62
- static defaultMessage = 'Unknown error'
63
- static defaultCode?: Error0GeneralProps['code']
64
- static defaultHttpStatus?: Error0GeneralProps['httpStatus']
65
- static defaultExpected?: Error0GeneralProps['expected']
66
- static defaultClientMessage?: Error0GeneralProps['clientMessage']
67
- static defaultMeta?: Meta0.Meta0OrValueTypeNullish
68
-
69
- public readonly propsOriginal: Error0GeneralProps
70
-
71
- constructor(message: string)
72
- constructor(input: Error0Input)
73
- constructor(message: string, input: Error0Input)
74
- constructor(error: Error)
75
- constructor(error: Error, input: Error0Input)
76
- constructor(value: unknown)
77
- constructor(value: unknown, input: Error0Input)
78
- constructor(...args: unknown[]) {
79
- const input: Partial<Error0Input> = {}
80
- if (args[0] instanceof Error) {
81
- input.cause = args[0]
82
- } else if (typeof args[0] === 'object' && args[0] !== null) {
83
- Object.assign(input, args[0])
84
- } else if (typeof args[0] === 'string') {
85
- input.message = args[0]
86
- }
87
- if (typeof args[1] === 'object' && args[1] !== null) {
88
- Object.assign(input, args[1])
89
- }
90
- const safeInput = Error0._safeParseInput(input)
91
-
92
- const message = safeInput.message || Error0.defaultMessage
93
- super(message)
94
- Object.setPrototypeOf(this, (this.constructor as typeof Error0).prototype)
95
- this.name = 'Error0'
247
+ type EmptyPluginsMap = {
248
+ props: Record<never, { init: never; output: never; resolve: never }>
249
+ methods: Record<never, ErrorMethodRecord>
250
+ }
96
251
 
97
- this.propsOriginal = (this.constructor as typeof Error0)._getSelfGeneralProps({
98
- error0Input: safeInput,
99
- message,
100
- stack: safeInput.stack || this.stack,
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
224
- }
225
-
226
- // sepcial
227
-
228
- public static _getExtraError0PropsByZodError(zodError: ZodError): Partial<Error0GeneralProps> {
229
- return {
230
- message: `Zod Validation Error: ${zodError.message}`,
231
- }
252
+ type ErrorPluginResolved = {
253
+ props: Record<string, ErrorPluginPropOptions<unknown>>
254
+ methods: Record<string, ErrorPluginMethodFn<unknown>>
255
+ adapt: Array<ErrorPluginAdaptFn<Error0, Record<string, unknown>>>
256
+ stack?: ErrorPluginStack
257
+ cause?: ErrorPluginCause
258
+ message?: ErrorPluginMessage
259
+ propKeys: string[]
260
+ propEntries: Array<[string, ErrorPluginPropOptions<unknown>]>
261
+ methodEntries: Array<[string, ErrorPluginMethodFn<unknown>]>
262
+ }
263
+ const RESERVED_STACK_PROP_ERROR = 'Error0: "stack" is a reserved prop key. Use .stack(...) plugin API instead'
264
+ const RESERVED_MESSAGE_PROP_ERROR = 'Error0: "message" is a reserved prop key. Use .message(...) plugin API instead'
265
+
266
+ type PluginPropsMapOf<TPlugin extends ErrorPlugin> = {
267
+ [TKey in keyof NonNullable<TPlugin['props']>]: NonNullable<TPlugin['props']>[TKey] extends ErrorPluginPropOptions<
268
+ any,
269
+ infer TOutputValue,
270
+ any,
271
+ infer TResolveValue
272
+ >
273
+ ? {
274
+ init: InferPluginPropInput<NonNullable<TPlugin['props']>[TKey]>
275
+ output: TOutputValue
276
+ resolve: TResolveValue
277
+ }
278
+ : never
279
+ }
280
+ type PluginMethodsMapOf<TPlugin extends ErrorPlugin> = {
281
+ [TKey in keyof NonNullable<TPlugin['methods']>]: {
282
+ fn: NonNullable<TPlugin['methods']>[TKey] extends ErrorPluginAnyMethodFn
283
+ ? NonNullable<TPlugin['methods']>[TKey]
284
+ : never
232
285
  }
286
+ }
287
+ type ErrorPluginsMapOfPlugin<TPlugin extends ErrorPlugin> = {
288
+ props: PluginPropsMapOf<TPlugin>
289
+ methods: PluginMethodsMapOf<TPlugin>
290
+ }
291
+ type ExtendErrorPluginsMap<TMap extends ErrorPluginsMap, TPlugin extends ErrorPlugin> = {
292
+ props: TMap['props'] & ErrorPluginsMapOfPlugin<TPlugin>['props']
293
+ methods: TMap['methods'] & ErrorPluginsMapOfPlugin<TPlugin>['methods']
294
+ }
295
+ type ExtendErrorPluginsMapWithProp<
296
+ TMap extends ErrorPluginsMap,
297
+ TKey extends string,
298
+ TInputValue,
299
+ TOutputValue,
300
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
301
+ > = ExtendErrorPluginsMap<
302
+ TMap,
303
+ ErrorPlugin<Record<TKey, ErrorPluginPropOptions<TInputValue, TOutputValue, Error0, TResolveValue>>>
304
+ >
305
+ type ExtendErrorPluginsMapWithMethod<
306
+ TMap extends ErrorPluginsMap,
307
+ TKey extends string,
308
+ TMethod extends ErrorPluginAnyMethodFn,
309
+ > = ExtendErrorPluginsMap<TMap, ErrorPlugin<Record<never, never>, Record<TKey, TMethod>>>
233
310
 
234
- public static _getExtraError0PropsByAxiosError(axiosError: AxiosError): Partial<Error0GeneralProps> {
235
- return {
236
- message: 'Axios Error',
237
- meta: {
238
- axiosData: (() => {
239
- try {
240
- return JSON.stringify(axiosError.response?.data)
241
- } catch {
242
- return undefined
243
- }
244
- })(),
245
- axiosStatus: axiosError.response?.status,
246
- },
247
- }
248
- }
249
-
250
- public static _assignError0Props(
251
- error0Props: Error0GeneralProps,
252
- extraError0Props: Partial<Error0GeneralProps>,
253
- ): void {
254
- const metaValue = Meta0.mergeValues(error0Props.meta, extraError0Props.meta)
255
- Object.assign(error0Props, extraError0Props, { meta: metaValue })
311
+ type PluginsMapOf<TClass> = TClass extends { __pluginsMap?: infer TPluginsMap }
312
+ ? TPluginsMap extends ErrorPluginsMap
313
+ ? TPluginsMap
314
+ : EmptyPluginsMap
315
+ : EmptyPluginsMap
316
+ type PluginsMapOfInstance<TInstance> = TInstance extends { __pluginsMap?: infer TPluginsMap }
317
+ ? TPluginsMap extends ErrorPluginsMap
318
+ ? TPluginsMap
319
+ : EmptyPluginsMap
320
+ : EmptyPluginsMap
321
+
322
+ type PluginsMapFromParts<
323
+ TProps extends ErrorPluginProps,
324
+ TMethods extends ErrorPluginMethods,
325
+ > = ErrorPluginsMapOfPlugin<ErrorPlugin<TProps, TMethods>>
326
+ type ErrorInstanceOfMap<TMap extends ErrorPluginsMap> = Error0 &
327
+ ErrorResolved<TMap> &
328
+ ErrorOwnMethods<TMap> &
329
+ ErrorResolveMethods<TMap> & { readonly __pluginsMap?: TMap }
330
+ type BuilderError0<TProps extends ErrorPluginProps, TMethods extends ErrorPluginMethods> = Error0 &
331
+ ErrorResolved<PluginsMapFromParts<TProps, TMethods>> &
332
+ ErrorOwnMethods<PluginsMapFromParts<TProps, TMethods>> &
333
+ ErrorResolveMethods<PluginsMapFromParts<TProps, TMethods>> & {
334
+ readonly __pluginsMap?: PluginsMapFromParts<TProps, TMethods>
256
335
  }
257
336
 
258
- // expected
337
+ type PluginOfBuilder<TBuilder> =
338
+ TBuilder extends PluginError0<infer TProps, infer TMethods> ? ErrorPlugin<TProps, TMethods> : never
339
+
340
+ export class PluginError0<
341
+ TProps extends ErrorPluginProps = Record<never, never>,
342
+ TMethods extends ErrorPluginMethods = Record<never, never>,
343
+ > {
344
+ private readonly _plugin: ErrorPlugin<ErrorPluginProps, ErrorPluginMethods>
345
+
346
+ readonly Infer = undefined as unknown as {
347
+ props: TProps
348
+ methods: TMethods
349
+ }
259
350
 
260
- public static _normalizeSelfExpected(
261
- error0Props: Error0GeneralProps,
262
- expectedProvided: Error0Input['expected'],
263
- ): boolean | undefined {
264
- if (typeof expectedProvided === 'function') {
265
- return expectedProvided(error0Props)
351
+ constructor(plugin?: ErrorPlugin<ErrorPluginProps, ErrorPluginMethods>) {
352
+ this._plugin = {
353
+ props: { ...(plugin?.props ?? {}) },
354
+ methods: { ...(plugin?.methods ?? {}) },
355
+ adapt: [...(plugin?.adapt ?? [])],
356
+ stack: plugin?.stack,
357
+ cause: plugin?.cause,
358
+ message: plugin?.message,
266
359
  }
267
- return expectedProvided
268
360
  }
269
361
 
270
- public static _isExpected(causesProps: Error0GeneralProps[]): boolean {
271
- let hasExpectedTrue = false
272
- for (const causeProps of causesProps) {
273
- if (causeProps.expected === false) {
274
- return false
362
+ prop<
363
+ TKey extends string,
364
+ TInputValue = undefined,
365
+ TOutputValue = unknown,
366
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
367
+ >(
368
+ key: TKey,
369
+ value: ErrorPluginPropOptions<TInputValue, TOutputValue, BuilderError0<TProps, TMethods>, TResolveValue>,
370
+ ): PluginError0<AddPropToPluginProps<TProps, TKey, TInputValue, TOutputValue, TResolveValue>, TMethods> {
371
+ return this.use('prop', key, value)
372
+ }
373
+
374
+ method<TKey extends string, TMethod extends (error: BuilderError0<TProps, TMethods>, ...args: any[]) => any>(
375
+ key: TKey,
376
+ value: TMethod,
377
+ ): PluginError0<TProps, AddMethodToPluginMethods<TMethods, TKey, TMethod>> {
378
+ return this.use('method', key, value)
379
+ }
380
+
381
+ adapt(
382
+ value: ErrorPluginAdaptFn<BuilderError0<TProps, TMethods>, PluginOutputProps<TProps>>,
383
+ ): PluginError0<TProps, TMethods> {
384
+ return this.use('adapt', value)
385
+ }
386
+
387
+ stack(value: ErrorPluginStack<BuilderError0<TProps, TMethods>>): PluginError0<TProps, TMethods> {
388
+ return this.use('stack', value)
389
+ }
390
+
391
+ cause(value: ErrorPluginCause<BuilderError0<TProps, TMethods>>): PluginError0<TProps, TMethods> {
392
+ return this.use('cause', value)
393
+ }
394
+
395
+ message(value: ErrorPluginMessage<BuilderError0<TProps, TMethods>>): PluginError0<TProps, TMethods> {
396
+ return this.use('message', value)
397
+ }
398
+
399
+ use<
400
+ TKey extends string,
401
+ TInputValue = undefined,
402
+ TOutputValue = unknown,
403
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
404
+ >(
405
+ kind: 'prop',
406
+ key: TKey,
407
+ value: ErrorPluginPropOptions<TInputValue, TOutputValue, BuilderError0<TProps, TMethods>, TResolveValue>,
408
+ ): PluginError0<AddPropToPluginProps<TProps, TKey, TInputValue, TOutputValue, TResolveValue>, TMethods>
409
+ use<TKey extends string, TMethod extends (error: BuilderError0<TProps, TMethods>, ...args: any[]) => any>(
410
+ kind: 'method',
411
+ key: TKey,
412
+ value: TMethod,
413
+ ): PluginError0<TProps, AddMethodToPluginMethods<TMethods, TKey, TMethod>>
414
+ use(
415
+ kind: 'adapt',
416
+ value: ErrorPluginAdaptFn<BuilderError0<TProps, TMethods>, PluginOutputProps<TProps>>,
417
+ ): PluginError0<TProps, TMethods>
418
+ use(kind: 'stack', value: ErrorPluginStack<BuilderError0<TProps, TMethods>>): PluginError0<TProps, TMethods>
419
+ use(kind: 'cause', value: ErrorPluginCause<BuilderError0<TProps, TMethods>>): PluginError0<TProps, TMethods>
420
+ use(kind: 'message', value: ErrorPluginMessage<BuilderError0<TProps, TMethods>>): PluginError0<TProps, TMethods>
421
+ use(
422
+ kind: 'prop' | 'method' | 'adapt' | 'stack' | 'cause' | 'message',
423
+ keyOrValue: unknown,
424
+ value?: ErrorPluginPropOptions<unknown, unknown, any> | ErrorPluginMethodFn<unknown, unknown[], any>,
425
+ ): PluginError0<any, any> {
426
+ const nextProps: ErrorPluginProps = { ...(this._plugin.props ?? {}) }
427
+ const nextMethods: ErrorPluginMethods = { ...(this._plugin.methods ?? {}) }
428
+ const nextAdapt: Array<ErrorPluginAdaptFn<Error0, Record<string, unknown>>> = [...(this._plugin.adapt ?? [])]
429
+ let nextStack: ErrorPluginStack | undefined = this._plugin.stack
430
+ let nextCause: ErrorPluginCause | undefined = this._plugin.cause
431
+ let nextMessage: ErrorPluginMessage | undefined = this._plugin.message
432
+ if (kind === 'prop') {
433
+ const key = keyOrValue as string
434
+ if (key === 'stack') {
435
+ throw new Error(RESERVED_STACK_PROP_ERROR)
436
+ }
437
+ if (key === 'message') {
438
+ throw new Error(RESERVED_MESSAGE_PROP_ERROR)
439
+ }
440
+ if (value === undefined) {
441
+ throw new Error('PluginError0.use("prop", key, value) requires value')
275
442
  }
276
- if (causeProps.expected === true) {
277
- hasExpectedTrue = true
443
+ nextProps[key] = value as ErrorPluginPropOptions<any, any>
444
+ } else if (kind === 'method') {
445
+ const key = keyOrValue as string
446
+ if (value === undefined) {
447
+ throw new Error('PluginError0.use("method", key, value) requires value')
278
448
  }
449
+ nextMethods[key] = value as ErrorPluginMethodFn<any, any[]>
450
+ } else if (kind === 'adapt') {
451
+ nextAdapt.push(keyOrValue as ErrorPluginAdaptFn<Error0, Record<string, unknown>>)
452
+ } else if (kind === 'stack') {
453
+ nextStack = keyOrValue as ErrorPluginStack
454
+ } else if (kind === 'cause') {
455
+ nextCause = keyOrValue as ErrorPluginCause
456
+ } else {
457
+ nextMessage = keyOrValue as ErrorPluginMessage
279
458
  }
280
- return hasExpectedTrue
459
+ return new PluginError0({
460
+ props: nextProps,
461
+ methods: nextMethods,
462
+ adapt: nextAdapt,
463
+ stack: nextStack,
464
+ cause: nextCause,
465
+ message: nextMessage,
466
+ })
281
467
  }
468
+ }
282
469
 
283
- // getters
470
+ const OWN_SYMBOL: unique symbol = Symbol('Error0.own')
471
+ type ErrorOwnStore = Record<string, unknown>
284
472
 
285
- public static _getPropsFromUnknown(error: unknown, defaults?: Error0Input): Error0GeneralProps {
286
- if (typeof error !== 'object' || error === null) {
287
- return {
288
- message: undefined,
289
- tag: undefined,
290
- code: undefined,
291
- httpStatus: undefined,
292
- expected: undefined,
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))
473
+ export type ClassError0<TPluginsMap extends ErrorPluginsMap = EmptyPluginsMap> = {
474
+ MAX_CAUSES_DEPTH: number
475
+ new (
476
+ message: string,
477
+ input?: ErrorInput<TPluginsMap>,
478
+ ): Error0 &
479
+ ErrorResolved<TPluginsMap> &
480
+ ErrorOwnMethods<TPluginsMap> &
481
+ ErrorResolveMethods<TPluginsMap> & { readonly __pluginsMap?: TPluginsMap }
482
+ new (
483
+ input: { message: string } & ErrorInput<TPluginsMap>,
484
+ ): Error0 &
485
+ ErrorResolved<TPluginsMap> &
486
+ ErrorOwnMethods<TPluginsMap> &
487
+ ErrorResolveMethods<TPluginsMap> & { readonly __pluginsMap?: TPluginsMap }
488
+ readonly __pluginsMap?: TPluginsMap
489
+ from: (
490
+ error: unknown,
491
+ ) => Error0 & ErrorResolved<TPluginsMap> & ErrorOwnMethods<TPluginsMap> & ErrorResolveMethods<TPluginsMap>
492
+ round: (
493
+ error: unknown,
494
+ isPublic?: boolean,
495
+ ) => Error0 & ErrorResolved<TPluginsMap> & ErrorOwnMethods<TPluginsMap> & ErrorResolveMethods<TPluginsMap>
496
+ causes: {
497
+ (error: unknown, instancesOnly?: false): unknown[]
498
+ (
499
+ error: unknown,
500
+ instancesOnly: true,
501
+ ): Array<Error0 & ErrorResolved<TPluginsMap> & ErrorOwnMethods<TPluginsMap> & ErrorResolveMethods<TPluginsMap>>
502
+ }
503
+ resolve: (error: unknown) => ErrorResolvedProps<TPluginsMap>
504
+ serialize: (error: unknown, isPublic?: boolean) => Record<string, unknown>
505
+ own: {
506
+ (error: object): ErrorOwnProps<TPluginsMap>
507
+ <TKey extends keyof TPluginsMap['props'] & string>(error: object, key: TKey): ErrorOwnProps<TPluginsMap>[TKey]
508
+ }
509
+ flow: <TKey extends keyof TPluginsMap['props'] & string>(
510
+ error: object,
511
+ key: TKey,
512
+ ) => Array<ErrorOwnProps<TPluginsMap>[TKey]>
513
+ // prop: <
514
+ // TKey extends string,
515
+ // TInputValue = undefined,
516
+ // TOutputValue = unknown,
517
+ // TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
518
+ // >(
519
+ // key: TKey,
520
+ // value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<TPluginsMap>, TResolveValue>,
521
+ // ) => ClassError0<ExtendErrorPluginsMapWithProp<TPluginsMap, TKey, TInputValue, TOutputValue, TResolveValue>>
522
+ // method: <TKey extends string, TMethod extends (error: ErrorInstanceOfMap<TPluginsMap>, ...args: any[]) => any>(
523
+ // key: TKey,
524
+ // value: TMethod,
525
+ // ) => ClassError0<ExtendErrorPluginsMapWithMethod<TPluginsMap, TKey, TMethod>>
526
+ // adapt: (
527
+ // value: ErrorPluginAdaptFn<ErrorInstanceOfMap<TPluginsMap>, ErrorResolvedProps<TPluginsMap>>,
528
+ // ) => ClassError0<TPluginsMap>
529
+ // stack: (value: ErrorPluginStack<ErrorInstanceOfMap<TPluginsMap>>) => ClassError0<TPluginsMap>
530
+ // cause: (value: ErrorPluginCause<ErrorInstanceOfMap<TPluginsMap>>) => ClassError0<TPluginsMap>
531
+ use: {
532
+ <TBuilder extends PluginError0>(
533
+ plugin: TBuilder,
534
+ ): ClassError0<ExtendErrorPluginsMap<TPluginsMap, PluginOfBuilder<TBuilder>>>
535
+ <
536
+ TKey extends string,
537
+ TInputValue = undefined,
538
+ TOutputValue = unknown,
539
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
540
+ >(
541
+ kind: 'prop',
542
+ key: TKey,
543
+ value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<TPluginsMap>, TResolveValue>,
544
+ ): ClassError0<ExtendErrorPluginsMapWithProp<TPluginsMap, TKey, TInputValue, TOutputValue, TResolveValue>>
545
+ <TKey extends string, TMethod extends (error: ErrorInstanceOfMap<TPluginsMap>, ...args: any[]) => any>(
546
+ kind: 'method',
547
+ key: TKey,
548
+ value: TMethod,
549
+ ): ClassError0<ExtendErrorPluginsMapWithMethod<TPluginsMap, TKey, TMethod>>
550
+ (
551
+ kind: 'adapt',
552
+ value: ErrorPluginAdaptFn<ErrorInstanceOfMap<TPluginsMap>, ErrorResolvedProps<TPluginsMap>>,
553
+ ): ClassError0<TPluginsMap>
554
+ (kind: 'stack', value: ErrorPluginStack<ErrorInstanceOfMap<TPluginsMap>>): ClassError0<TPluginsMap>
555
+ (kind: 'cause', value: ErrorPluginCause<ErrorInstanceOfMap<TPluginsMap>>): ClassError0<TPluginsMap>
556
+ (kind: 'message', value: ErrorPluginMessage<ErrorInstanceOfMap<TPluginsMap>>): ClassError0<TPluginsMap>
557
+ }
558
+ plugin: () => PluginError0
559
+ } & ErrorStaticMethods<TPluginsMap>
560
+
561
+ export class Error0 extends Error {
562
+ static readonly __pluginsMap?: EmptyPluginsMap
563
+ readonly __pluginsMap?: EmptyPluginsMap
564
+ static MAX_CAUSES_DEPTH = 99
565
+ protected static _plugins: ErrorPlugin[] = []
566
+ protected static _resolvedPlugin?: ErrorPluginResolved
567
+
568
+ private static readonly _emptyPlugin: ErrorPluginResolved = {
569
+ props: {},
570
+ methods: {},
571
+ adapt: [],
572
+ stack: undefined,
573
+ cause: undefined,
574
+ message: undefined,
575
+ propKeys: [],
576
+ propEntries: [],
577
+ methodEntries: [],
578
+ }
579
+
580
+ private static _indexResolvedPlugin(
581
+ resolved: Omit<ErrorPluginResolved, 'propKeys' | 'propEntries' | 'methodEntries'>,
582
+ ): ErrorPluginResolved {
583
+ return {
584
+ ...resolved,
585
+ propKeys: Object.keys(resolved.props),
586
+ propEntries: Object.entries(resolved.props),
587
+ methodEntries: Object.entries(resolved.methods),
350
588
  }
351
- return result
352
589
  }
353
590
 
354
- public static _getCausesPropsFromUnknown(error: unknown, maxLevel: number): Error0GeneralProps[] {
355
- if (!error) {
356
- return []
591
+ private static _applyPlugin(
592
+ resolved: Omit<ErrorPluginResolved, 'propKeys' | 'propEntries' | 'methodEntries'>,
593
+ plugin: ErrorPlugin,
594
+ ): void {
595
+ if (plugin.props && 'stack' in plugin.props) {
596
+ throw new Error(RESERVED_STACK_PROP_ERROR)
597
+ }
598
+ if (plugin.props && 'message' in plugin.props) {
599
+ throw new Error(RESERVED_MESSAGE_PROP_ERROR)
600
+ }
601
+ Object.assign(resolved.props, plugin.props ?? this._emptyPlugin.props)
602
+ Object.assign(resolved.methods, plugin.methods ?? this._emptyPlugin.methods)
603
+ resolved.adapt.push(...(plugin.adapt ?? this._emptyPlugin.adapt))
604
+ if (typeof plugin.stack !== 'undefined') {
605
+ resolved.stack = plugin.stack
357
606
  }
358
- const causeProps = this._getPropsFromUnknown(error)
359
- const causesProps: Error0GeneralProps[] = [causeProps]
360
- if (!causeProps.cause) {
361
- return causesProps
607
+ if (typeof plugin.cause !== 'undefined') {
608
+ resolved.cause = plugin.cause
362
609
  }
363
- if (maxLevel > 0) {
364
- causesProps.push(...this._getCausesPropsFromUnknown(this._getPropsFromUnknown(causeProps.cause), maxLevel - 1))
610
+ if (typeof plugin.message !== 'undefined') {
611
+ resolved.message = plugin.message
365
612
  }
366
- return causesProps
367
613
  }
368
614
 
369
- public static _getCausesPropsFromError0Props(
370
- error0Props: Error0GeneralProps,
371
- maxLevel: number,
372
- ): Error0GeneralProps[] {
373
- return [error0Props, ...this._getCausesPropsFromUnknown(error0Props.cause, maxLevel - 1)]
615
+ private static _mergeResolvedPlugin(
616
+ this: typeof Error0,
617
+ base: ErrorPluginResolved,
618
+ plugin: ErrorPlugin,
619
+ ): ErrorPluginResolved {
620
+ const merged: Omit<ErrorPluginResolved, 'propKeys' | 'propEntries' | 'methodEntries'> = {
621
+ props: { ...base.props },
622
+ methods: { ...base.methods },
623
+ adapt: [...base.adapt],
624
+ stack: base.stack,
625
+ cause: base.cause,
626
+ message: base.message,
627
+ }
628
+ this._applyPlugin(merged, plugin)
629
+ return this._indexResolvedPlugin(merged)
374
630
  }
375
631
 
376
- public static _getClosestPropValue<TPropKey extends keyof Error0GeneralProps>(
377
- causesProps: Error0GeneralProps[],
378
- propKey: TPropKey,
379
- ): NonNullable<Error0GeneralProps[TPropKey]> | undefined {
380
- for (const causeProps of causesProps) {
381
- const propValue = causeProps[propKey]
382
- if (isFilled(propValue)) {
383
- return propValue as NonNullable<Error0GeneralProps[TPropKey]>
384
- }
632
+ private static _getResolvedPlugin(this: typeof Error0): ErrorPluginResolved {
633
+ if (Object.prototype.hasOwnProperty.call(this, '_resolvedPlugin') && this._resolvedPlugin) {
634
+ return this._resolvedPlugin
385
635
  }
386
- return undefined
636
+ const resolved: ErrorPluginResolved = {
637
+ props: {},
638
+ methods: {},
639
+ adapt: [],
640
+ propKeys: [],
641
+ propEntries: [],
642
+ methodEntries: [],
643
+ }
644
+ for (const plugin of this._plugins) {
645
+ this._applyPlugin(resolved, plugin)
646
+ }
647
+ const indexed = this._indexResolvedPlugin(resolved)
648
+ Object.defineProperty(this, '_resolvedPlugin', {
649
+ value: indexed,
650
+ writable: true,
651
+ enumerable: false,
652
+ configurable: true,
653
+ })
654
+ return indexed
387
655
  }
388
656
 
389
- // private static getClosestByGetter<TResult>(
390
- // causesProps: Error0GeneralProps[],
391
- // getter: (props: Error0GeneralProps) => TResult,
392
- // ): NonNullable<TResult> | undefined {
393
- // for (const causeProps of causesProps) {
394
- // const result = getter(causeProps)
395
- // if (isFilled(result)) {
396
- // return result
397
- // }
398
- // }
399
- // return undefined
400
- // }
657
+ constructor(message: string, input?: ErrorInput<EmptyPluginsMap>)
658
+ constructor(input: { message: string } & ErrorInput<EmptyPluginsMap>)
659
+ constructor(
660
+ ...args:
661
+ | [message: string, input?: ErrorInput<EmptyPluginsMap>]
662
+ | [{ message: string } & ErrorInput<EmptyPluginsMap>]
663
+ ) {
664
+ const [first, second] = args
665
+ const input = typeof first === 'string' ? { message: first, ...(second ?? {}) } : first
666
+
667
+ super(input.message, { cause: input.cause })
668
+ this.name = 'Error0'
401
669
 
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]>)
670
+ const ctor = this.constructor as typeof Error0
671
+ const plugin = ctor._getResolvedPlugin()
672
+ const ownStore = Object.create(null) as ErrorOwnStore
673
+ Object.defineProperty(this, OWN_SYMBOL, { value: ownStore, writable: true, enumerable: false, configurable: true })
674
+
675
+ for (const [key, prop] of plugin.propEntries) {
676
+ if (key === 'stack') {
677
+ continue
678
+ }
679
+ Object.defineProperty(this, key, {
680
+ get: () =>
681
+ prop.resolve({
682
+ own: ownStore[key],
683
+ flow: this.flow(key as never),
684
+ error: this,
685
+ }),
686
+ set: (value) => {
687
+ ownStore[key] = value
688
+ },
689
+ enumerable: true,
690
+ configurable: true,
691
+ })
692
+ if (key in input) {
693
+ const ownValue = (input as Record<string, unknown>)[key]
694
+ ownStore[key] = typeof prop.init === 'function' ? prop.init(ownValue) : ownValue
411
695
  }
412
696
  }
413
- return values
414
697
  }
415
698
 
416
- public static _getMergedMetaValue(causesProps: Error0GeneralProps[]): Meta0.ValueType {
417
- const metas = this._getFilledPropValues(causesProps, 'meta')
418
- if (metas.length === 0) {
419
- return {}
420
- } else if (metas.length === 1) {
421
- return metas[0]
422
- } else {
423
- return Meta0.mergeValues(metas[0], ...metas.slice(1))
699
+ private static _getOwnStore(object: object): ErrorOwnStore | undefined {
700
+ const record = object as Record<string | symbol, unknown>
701
+ const existing = record[OWN_SYMBOL]
702
+ if (existing && typeof existing === 'object') {
703
+ return existing as ErrorOwnStore
424
704
  }
705
+ return undefined
425
706
  }
426
707
 
427
- // stack
428
-
429
- public static _removeConstructorStackPart(stack: Error0GeneralProps['stack']): Error0GeneralProps['stack'] {
430
- if (!stack) {
431
- return stack
708
+ private static readonly isOwnProperty = (object: object, key: string): boolean => {
709
+ const ownStore = this._getOwnStore(object)
710
+ if (ownStore) {
711
+ return Object.prototype.hasOwnProperty.call(ownStore, key)
432
712
  }
433
- let lines = stack.split('\n')
434
- const removeAllLinesContains = (search: string) => {
435
- lines = lines.filter((line) => !line.includes(search))
713
+ return !!Object.getOwnPropertyDescriptor(object, key)
714
+ }
715
+ private static _ownByKey(error: object, key: string): unknown {
716
+ const ownStore = this._getOwnStore(error)
717
+ if (ownStore) {
718
+ return ownStore[key]
436
719
  }
437
- removeAllLinesContains('at new Error0')
438
- removeAllLinesContains('at _toError0')
439
- removeAllLinesContains('at Error0.from')
440
- removeAllLinesContains('at Error0._toError0')
441
- return lines.join('\n')
720
+ return (error as Record<string, unknown>)[key]
721
+ }
722
+ private static _flowByKey(error: object, key: string): unknown[] {
723
+ const causes = this.causes(error, true)
724
+ const values = new Array<unknown>(causes.length)
725
+ for (let i = 0; i < causes.length; i += 1) {
726
+ values[i] = this._ownByKey(causes[i], key)
727
+ }
728
+ return values
442
729
  }
443
730
 
444
- public static _mergeStack(
445
- prevStack: Error0GeneralProps['stack'],
446
- nextStack: Error0GeneralProps['stack'],
447
- ): Error0GeneralProps['stack'] {
448
- return [nextStack, prevStack].filter(Boolean).join('\n\n') || undefined
731
+ static own<TThis extends typeof Error0>(this: TThis, error: unknown): ErrorOwnProps<PluginsMapOf<TThis>>
732
+ static own<TThis extends typeof Error0, TKey extends keyof PluginsMapOf<TThis>['props'] & string>(
733
+ this: TThis,
734
+ error: unknown,
735
+ key: TKey,
736
+ ): ErrorOwnProps<PluginsMapOf<TThis>>[TKey]
737
+ static own(error: unknown, key?: string): unknown {
738
+ const error0 = this.from(error)
739
+ if (key === undefined) {
740
+ const ownValues: Record<string, unknown> = {}
741
+ const plugin = this._getResolvedPlugin()
742
+ for (const ownKey of plugin.propKeys) {
743
+ ownValues[ownKey] = this._ownByKey(error0, ownKey)
744
+ }
745
+ return ownValues
746
+ }
747
+ return this._ownByKey(error0, key)
748
+ }
749
+ own<TThis extends Error0>(this: TThis): ErrorOwnProps<PluginsMapOfInstance<TThis>>
750
+ own<TThis extends Error0, TKey extends keyof PluginsMapOfInstance<TThis>['props'] & string>(
751
+ this: TThis,
752
+ key: TKey,
753
+ ): ErrorOwnProps<PluginsMapOfInstance<TThis>>[TKey]
754
+ own(key?: string): unknown {
755
+ const ctor = this.constructor as typeof Error0
756
+ if (key === undefined) {
757
+ return ctor.own(this)
758
+ }
759
+ return ctor._ownByKey(this, key)
449
760
  }
450
761
 
451
- // transformations
762
+ static flow<TThis extends typeof Error0, TKey extends keyof PluginsMapOf<TThis>['props'] & string>(
763
+ this: TThis,
764
+ error: unknown,
765
+ key: TKey,
766
+ ): Array<ErrorOwnProps<PluginsMapOf<TThis>>[TKey]>
767
+ static flow(error: unknown, key: string): unknown[] {
768
+ const error0 = this.from(error)
769
+ return this._flowByKey(error0, key)
770
+ }
771
+ flow<TThis extends Error0, TKey extends keyof PluginsMapOfInstance<TThis>['props'] & string>(
772
+ this: TThis,
773
+ key: TKey,
774
+ ): Array<ErrorOwnProps<PluginsMapOfInstance<TThis>>[TKey]>
775
+ flow(key: string): unknown[] {
776
+ const ctor = this.constructor as typeof Error0
777
+ return ctor._flowByKey(this, key)
778
+ }
452
779
 
453
- static isError0(error: unknown): error is Error0 {
454
- return error instanceof Error0
780
+ static _resolveByKey(error: Error0, key: string, plugin: ErrorPluginResolved): unknown {
781
+ try {
782
+ const options = {
783
+ get own() {
784
+ return error.own(key as never)
785
+ },
786
+ get flow() {
787
+ return error.flow(key as never)
788
+ },
789
+ error,
790
+ }
791
+ const prop = plugin.props[key]
792
+ const resolver = prop.resolve
793
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
794
+ if (!resolver) {
795
+ return (error as any)[key]
796
+ }
797
+ return resolver(options as ErrorPluginPropOptionsResolveOptions<any, any>)
798
+ } catch {
799
+ // eslint-disable-next-line no-console
800
+ console.error(`Error0: failed to resolve property ${key}`, error)
801
+ return undefined
802
+ }
455
803
  }
456
804
 
457
- static isLikelyError0(error: unknown): error is Error0 {
458
- if (error instanceof Error0) {
459
- return true
805
+ static resolve<TThis extends typeof Error0>(this: TThis, error: unknown): ErrorResolvedProps<PluginsMapOf<TThis>>
806
+ static resolve(error: unknown): Record<string, unknown>
807
+ static resolve(error: unknown): Record<string, unknown> {
808
+ const error0 = this.from(error)
809
+ const resolved: Record<string, unknown> = {}
810
+ const plugin = this._getResolvedPlugin()
811
+ for (const key of plugin.propKeys) {
812
+ resolved[key] = this._resolveByKey(error0, key, plugin)
460
813
  }
814
+ return resolved
815
+ }
816
+ resolve<TThis extends Error0>(this: TThis): ErrorResolvedProps<PluginsMapOfInstance<TThis>>
817
+ resolve(): Record<string, unknown> {
818
+ const ctor = this.constructor as typeof Error0
819
+ return ctor.resolve(this)
820
+ }
461
821
 
462
- if (typeof error === 'object' && error !== null) {
463
- if ('__I_AM_ERROR_0' in error && error.__I_AM_ERROR_0 === true) {
464
- return true
822
+ static causes(error: unknown, instancesOnly?: false): unknown[]
823
+ static causes<T extends typeof Error0>(this: T, error: unknown, instancesOnly: true): Array<InstanceType<T>>
824
+ static causes(error: unknown, instancesOnly?: boolean): unknown[] {
825
+ const causes: unknown[] = []
826
+ let current: unknown = error
827
+ const seen = new Set<unknown>()
828
+ let depth = 0
829
+ while (depth < this.MAX_CAUSES_DEPTH) {
830
+ if (seen.has(current)) {
831
+ break
832
+ }
833
+ seen.add(current)
834
+ if (!instancesOnly || this.is(current)) {
835
+ causes.push(current)
836
+ }
837
+ if (!current || typeof current !== 'object') {
838
+ break
465
839
  }
840
+ current = (current as { cause?: unknown }).cause
841
+ depth += 1
466
842
  }
843
+ return causes
844
+ }
845
+ causes<TThis extends Error0>(this: TThis, instancesOnly?: false): [TThis, ...unknown[]]
846
+ causes<TThis extends Error0>(this: TThis, instancesOnly: true): [TThis, ...TThis[]]
847
+ causes(instancesOnly?: boolean): unknown[] {
848
+ const ctor = this.constructor as typeof Error0
849
+ if (instancesOnly) {
850
+ return ctor.causes(this, true)
851
+ }
852
+ return ctor.causes(this)
853
+ }
467
854
 
468
- return false
855
+ static is<T extends typeof Error0>(this: T, error: unknown): error is InstanceType<T> {
856
+ return error instanceof this
469
857
  }
470
858
 
471
- public static _toError0(error: unknown, inputOverride: Error0Input = {}): Error0 {
472
- if (error instanceof Error0) {
859
+ static isSerialized(error: unknown): error is Record<string, unknown> {
860
+ return !this.is(error) && typeof error === 'object' && error !== null && 'name' in error && error.name === 'Error0'
861
+ }
862
+
863
+ static from(error: unknown): Error0 {
864
+ if (this.is(error)) {
473
865
  return error
474
866
  }
867
+ if (this.isSerialized(error)) {
868
+ return this._fromSerialized(error)
869
+ }
870
+ return this._fromNonError0(error)
871
+ }
872
+
873
+ static round(error: unknown, isPublic = false): Error0 {
874
+ return this.from(this.serialize(error, isPublic))
875
+ }
475
876
 
476
- if (typeof error === 'string') {
477
- return new Error0(error, inputOverride)
877
+ private static _applyAdapt(error: Error0): Error0 {
878
+ const plugin = this._getResolvedPlugin()
879
+ for (const adapt of plugin.adapt) {
880
+ const adapted = adapt(error as any)
881
+ if (adapted && typeof adapted === 'object') {
882
+ Object.assign(error as unknown as Record<string, unknown>, adapted)
883
+ }
478
884
  }
885
+ return error
886
+ }
479
887
 
888
+ private static _fromSerialized(error: unknown): Error0 {
889
+ const message = this._extractMessage(error)
480
890
  if (typeof error !== 'object' || error === null) {
481
- return new Error0({
482
- message: this.defaultMessage,
483
- ...inputOverride,
891
+ return this._applyAdapt(new this(message, { cause: error }))
892
+ }
893
+ const errorRecord = error as Record<string, unknown>
894
+ const recreated = new this(message)
895
+ const plugin = this._getResolvedPlugin()
896
+ for (const [key, prop] of plugin.propEntries) {
897
+ if (prop.deserialize === false) {
898
+ continue
899
+ }
900
+ if (!(key in errorRecord)) {
901
+ continue
902
+ }
903
+ try {
904
+ const value = prop.deserialize({ value: errorRecord[key], record: errorRecord })
905
+ ;(recreated as unknown as Record<string, unknown>)[key] = value
906
+ } catch {
907
+ // eslint-disable-next-line no-console
908
+ console.error(`Error0: failed to deserialize property ${key}`, errorRecord)
909
+ }
910
+ }
911
+ if ('stack' in errorRecord) {
912
+ try {
913
+ if (typeof errorRecord.stack === 'string') {
914
+ recreated.stack = errorRecord.stack
915
+ }
916
+ } catch {
917
+ // eslint-disable-next-line no-console
918
+ console.error('Error0: failed to deserialize stack', errorRecord)
919
+ }
920
+ }
921
+ const causePlugin = plugin.cause
922
+ if (causePlugin && 'cause' in errorRecord) {
923
+ try {
924
+ ;(recreated as { cause?: unknown }).cause = causePlugin.deserialize({
925
+ cause: errorRecord.cause,
926
+ error: errorRecord,
927
+ isSerialized: (serializedCause) => this.isSerialized(serializedCause),
928
+ fromSerialized: (serializedCause) => this._fromSerialized(serializedCause),
929
+ })
930
+ } catch {
931
+ // eslint-disable-next-line no-console
932
+ console.error('Error0: failed to deserialize cause', errorRecord)
933
+ }
934
+ }
935
+ return recreated
936
+ }
937
+
938
+ private static _fromNonError0(error: unknown): Error0 {
939
+ const message = this._extractMessage(error)
940
+ return this._applyAdapt(new this(message, { cause: error }))
941
+ }
942
+
943
+ private static _extractMessage(error: unknown): string {
944
+ return (
945
+ (typeof error === 'string'
946
+ ? error
947
+ : typeof error === 'object' && error !== null && 'message' in error && typeof error.message === 'string'
948
+ ? error.message
949
+ : undefined) || 'Unknown error'
950
+ )
951
+ }
952
+
953
+ private static _useWithPlugin(
954
+ this: typeof Error0,
955
+ plugin: ErrorPlugin<ErrorPluginProps, ErrorPluginMethods>,
956
+ ): ClassError0 {
957
+ const Base = this as unknown as typeof Error0
958
+ const Error0Extended = class Error0 extends Base {}
959
+ ;(Error0Extended as typeof Error0)._plugins = [...Base._plugins, plugin]
960
+ const resolved = this._mergeResolvedPlugin(Base._getResolvedPlugin(), plugin)
961
+ ;(Error0Extended as typeof Error0)._resolvedPlugin = resolved
962
+ for (const [key, method] of resolved.methodEntries) {
963
+ Object.defineProperty((Error0Extended as typeof Error0).prototype, key, {
964
+ value: function (...args: unknown[]) {
965
+ return method(this as Error0, ...args)
966
+ },
967
+ writable: true,
968
+ enumerable: true,
969
+ configurable: true,
970
+ })
971
+ Object.defineProperty(Error0Extended, key, {
972
+ value: function (error: unknown, ...args: unknown[]) {
973
+ return method(this.from(error), ...args)
974
+ },
975
+ writable: true,
976
+ enumerable: true,
977
+ configurable: true,
484
978
  })
485
979
  }
486
980
 
487
- const inputFromData = get(error, 'data')
488
- if (inputFromData) {
489
- if (Error0.isLikelyError0(inputFromData)) {
490
- return this._toError0(inputFromData, inputOverride)
491
- }
981
+ return Error0Extended as unknown as ClassError0
982
+ }
983
+
984
+ private static _pluginFromBuilder(plugin: PluginError0): ErrorPlugin<ErrorPluginProps, ErrorPluginMethods> {
985
+ const pluginRecord = plugin as unknown as {
986
+ _plugin: ErrorPlugin<ErrorPluginProps, ErrorPluginMethods>
987
+ }
988
+ return {
989
+ props: { ...(pluginRecord._plugin.props ?? {}) },
990
+ methods: { ...(pluginRecord._plugin.methods ?? {}) },
991
+ adapt: [...(pluginRecord._plugin.adapt ?? [])],
992
+ stack: pluginRecord._plugin.stack,
993
+ cause: pluginRecord._plugin.cause,
994
+ message: pluginRecord._plugin.message,
492
995
  }
996
+ }
997
+
998
+ // static prop<
999
+ // TThis extends typeof Error0,
1000
+ // TKey extends string,
1001
+ // TInputValue = undefined,
1002
+ // TOutputValue = unknown,
1003
+ // TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
1004
+ // >(
1005
+ // this: TThis,
1006
+ // key: TKey,
1007
+ // value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<PluginsMapOf<TThis>>, TResolveValue>,
1008
+ // ): ClassError0<ExtendErrorPluginsMapWithProp<PluginsMapOf<TThis>, TKey, TInputValue, TOutputValue, TResolveValue>> {
1009
+ // return this.use('prop', key, value)
1010
+ // }
1011
+
1012
+ // static method<TThis extends typeof Error0, TKey extends string, TMethod extends (error: ErrorInstanceOfMap<PluginsMapOf<TThis>>, ...args: any[]) => any>(
1013
+ // this: TThis,
1014
+ // key: TKey,
1015
+ // value: TMethod,
1016
+ // ): ClassError0<ExtendErrorPluginsMapWithMethod<PluginsMapOf<TThis>, TKey, TMethod>> {
1017
+ // return this.use('method', key, value)
1018
+ // }
1019
+
1020
+ // static adapt<TThis extends typeof Error0>(
1021
+ // this: TThis,
1022
+ // value: ErrorPluginAdaptFn<ErrorInstanceOfMap<PluginsMapOf<TThis>>, ErrorResolvedProps<PluginsMapOf<TThis>>>,
1023
+ // ): ClassError0<PluginsMapOf<TThis>> {
1024
+ // return this.use('adapt', value)
1025
+ // }
1026
+
1027
+ // static stack<TThis extends typeof Error0>(
1028
+ // this: TThis,
1029
+ // value: ErrorPluginStack<ErrorInstanceOfMap<PluginsMapOf<TThis>>>,
1030
+ // ): ClassError0<PluginsMapOf<TThis>> {
1031
+ // return this.use('stack', value)
1032
+ // }
493
1033
 
494
- const inputFromDataError0 = get(error, 'data.error0')
495
- if (inputFromDataError0) {
496
- if (Error0.isLikelyError0(inputFromDataError0)) {
497
- return this._toError0(inputFromDataError0, inputOverride)
1034
+ // static cause<TThis extends typeof Error0>(
1035
+ // this: TThis,
1036
+ // value: ErrorPluginCause<ErrorInstanceOfMap<PluginsMapOf<TThis>>>,
1037
+ // ): ClassError0<PluginsMapOf<TThis>> {
1038
+ // return this.use('cause', value)
1039
+ // }
1040
+
1041
+ static use<TThis extends typeof Error0, TBuilder extends PluginError0>(
1042
+ this: TThis,
1043
+ plugin: TBuilder,
1044
+ ): ClassError0<ExtendErrorPluginsMap<PluginsMapOf<TThis>, PluginOfBuilder<TBuilder>>>
1045
+ static use<
1046
+ TThis extends typeof Error0,
1047
+ TKey extends string,
1048
+ TInputValue = undefined,
1049
+ TOutputValue = unknown,
1050
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
1051
+ >(
1052
+ this: TThis,
1053
+ kind: 'prop',
1054
+ key: TKey,
1055
+ value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<PluginsMapOf<TThis>>, TResolveValue>,
1056
+ ): ClassError0<ExtendErrorPluginsMapWithProp<PluginsMapOf<TThis>, TKey, TInputValue, TOutputValue, TResolveValue>>
1057
+ static use<
1058
+ TThis extends typeof Error0,
1059
+ TKey extends string,
1060
+ TMethod extends (error: ErrorInstanceOfMap<PluginsMapOf<TThis>>, ...args: any[]) => any,
1061
+ >(
1062
+ this: TThis,
1063
+ kind: 'method',
1064
+ key: TKey,
1065
+ value: TMethod,
1066
+ ): ClassError0<ExtendErrorPluginsMapWithMethod<PluginsMapOf<TThis>, TKey, TMethod>>
1067
+ static use<TThis extends typeof Error0>(
1068
+ this: TThis,
1069
+ kind: 'adapt',
1070
+ value: ErrorPluginAdaptFn<ErrorInstanceOfMap<PluginsMapOf<TThis>>, ErrorResolvedProps<PluginsMapOf<TThis>>>,
1071
+ ): ClassError0<PluginsMapOf<TThis>>
1072
+ static use<TThis extends typeof Error0>(
1073
+ this: TThis,
1074
+ kind: 'stack',
1075
+ value: ErrorPluginStack<ErrorInstanceOfMap<PluginsMapOf<TThis>>>,
1076
+ ): ClassError0<PluginsMapOf<TThis>>
1077
+ static use<TThis extends typeof Error0>(
1078
+ this: TThis,
1079
+ kind: 'cause',
1080
+ value: ErrorPluginCause<ErrorInstanceOfMap<PluginsMapOf<TThis>>>,
1081
+ ): ClassError0<PluginsMapOf<TThis>>
1082
+ static use<TThis extends typeof Error0>(
1083
+ this: TThis,
1084
+ kind: 'message',
1085
+ value: ErrorPluginMessage<ErrorInstanceOfMap<PluginsMapOf<TThis>>>,
1086
+ ): ClassError0<PluginsMapOf<TThis>>
1087
+ static use(
1088
+ this: typeof Error0,
1089
+ first: PluginError0 | 'prop' | 'method' | 'adapt' | 'stack' | 'cause' | 'message',
1090
+ key?: unknown,
1091
+ value?: ErrorPluginPropOptions<unknown> | ErrorPluginMethodFn<unknown>,
1092
+ ): ClassError0 {
1093
+ if (first instanceof PluginError0) {
1094
+ return this._useWithPlugin(this._pluginFromBuilder(first))
1095
+ }
1096
+ if (first === 'stack') {
1097
+ if (typeof key === 'undefined') {
1098
+ throw new Error('Error0.use("stack", value) requires stack plugin value')
1099
+ }
1100
+ if (typeof key !== 'object' || key === null || typeof (key as { serialize?: unknown }).serialize !== 'function') {
1101
+ throw new Error('Error0.use("stack", value) expects { serialize: function }')
1102
+ }
1103
+ return this._useWithPlugin({
1104
+ stack: key as ErrorPluginStack,
1105
+ })
1106
+ }
1107
+ if (first === 'cause') {
1108
+ if (typeof key === 'undefined') {
1109
+ throw new Error('Error0.use("cause", value) requires cause plugin value')
1110
+ }
1111
+ if (
1112
+ typeof key !== 'object' ||
1113
+ key === null ||
1114
+ typeof (key as { serialize?: unknown }).serialize !== 'function' ||
1115
+ typeof (key as { deserialize?: unknown }).deserialize !== 'function'
1116
+ ) {
1117
+ throw new Error('Error0.use("cause", value) expects { serialize: function, deserialize: function }')
1118
+ }
1119
+ return this._useWithPlugin({
1120
+ cause: key as ErrorPluginCause,
1121
+ })
1122
+ }
1123
+ if (first === 'message') {
1124
+ if (typeof key === 'undefined') {
1125
+ throw new Error('Error0.use("message", value) requires message plugin value')
1126
+ }
1127
+ if (typeof key !== 'object' || key === null || typeof (key as { serialize?: unknown }).serialize !== 'function') {
1128
+ throw new Error('Error0.use("message", value) expects { serialize: function }')
1129
+ }
1130
+ return this._useWithPlugin({
1131
+ message: key as ErrorPluginMessage,
1132
+ })
1133
+ }
1134
+ if (first === 'adapt') {
1135
+ if (typeof key !== 'function') {
1136
+ throw new Error('Error0.use("adapt", value) requires adapt function')
498
1137
  }
1138
+ return this._useWithPlugin({
1139
+ adapt: [key as ErrorPluginAdaptFn<Error0, Record<string, unknown>>],
1140
+ })
1141
+ }
1142
+ if (typeof key !== 'string' || value === undefined) {
1143
+ throw new Error('Error0.use(kind, key, value) requires key and value')
499
1144
  }
500
1145
 
501
- return new Error0(this._getPropsFromUnknown(error, inputOverride))
1146
+ if (first === 'prop') {
1147
+ if (key === 'stack') {
1148
+ throw new Error(RESERVED_STACK_PROP_ERROR)
1149
+ }
1150
+ if (key === 'message') {
1151
+ throw new Error(RESERVED_MESSAGE_PROP_ERROR)
1152
+ }
1153
+ return this._useWithPlugin({
1154
+ props: { [key]: value as ErrorPluginPropOptions<unknown> },
1155
+ })
1156
+ }
1157
+ return this._useWithPlugin({
1158
+ methods: { [key]: value as ErrorPluginMethodFn<unknown> },
1159
+ })
502
1160
  }
503
1161
 
504
- static from(error: unknown, inputOverride?: Error0Input): Error0 {
505
- return this._toError0(error, inputOverride)
1162
+ static plugin(): PluginError0 {
1163
+ return new PluginError0()
506
1164
  }
507
1165
 
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)
1166
+ static serialize(error: unknown, isPublic = true): Record<string, unknown> {
1167
+ const error0 = this.from(error)
1168
+ const plugin = this._getResolvedPlugin()
1169
+ const resolveByKey = (targetError: Error0, key: string, targetPlugin: ErrorPluginResolved): unknown =>
1170
+ this._resolveByKey(targetError, key, targetPlugin)
1171
+ const messagePlugin = plugin.message
1172
+ let serializedMessage: unknown = error0.message
1173
+ try {
1174
+ if (messagePlugin) {
1175
+ serializedMessage = messagePlugin.serialize({ value: error0.message, error: error0, isPublic })
1176
+ }
1177
+ } catch {
1178
+ // eslint-disable-next-line no-console
1179
+ console.error('Error0: failed to serialize message', error0)
1180
+ serializedMessage = error0.message
1181
+ }
1182
+ const json: Record<string, unknown> = {
1183
+ name: error0.name,
1184
+ }
1185
+ if (serializedMessage !== undefined) {
1186
+ json.message = serializedMessage
524
1187
  }
525
- }
526
1188
 
527
- static extendCollection<T extends Record<string, typeof Error0>>(
528
- classes: T,
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
1189
+ for (const [key, prop] of plugin.propEntries) {
1190
+ if (prop.serialize === false) {
1191
+ continue
1192
+ }
1193
+ try {
1194
+ const options = {
1195
+ get own() {
1196
+ return error0.own(key as never)
1197
+ },
1198
+ get flow() {
1199
+ return error0.flow(key as never)
1200
+ },
1201
+ get resolved() {
1202
+ return resolveByKey(error0, key, plugin)
1203
+ },
1204
+ error: error0,
1205
+ isPublic,
1206
+ }
1207
+ const jsonValue = prop.serialize(options as ErrorPluginPropSerializeOptions<any, any, any>)
1208
+ if (jsonValue !== undefined) {
1209
+ json[key] = jsonValue
1210
+ }
1211
+ } catch {
1212
+ // eslint-disable-next-line no-console
1213
+ console.error(`Error0: failed to serialize property ${key}`, error0)
1214
+ }
1215
+ }
1216
+ const stackPlugin = plugin.stack
1217
+ try {
1218
+ let serializedStack: unknown
1219
+ if (stackPlugin) {
1220
+ serializedStack = stackPlugin.serialize({ value: error0.stack, error: error0, isPublic })
1221
+ } else {
1222
+ serializedStack = isPublic ? undefined : error0.stack
1223
+ }
1224
+ if (serializedStack !== undefined) {
1225
+ json.stack = serializedStack
1226
+ }
1227
+ } catch {
1228
+ // eslint-disable-next-line no-console
1229
+ console.error('Error0: failed to serialize stack', error0)
1230
+ }
1231
+ const causePlugin = plugin.cause
1232
+ if (causePlugin?.serialize) {
1233
+ try {
1234
+ const serializedCause = causePlugin.serialize({
1235
+ cause: (error0 as { cause?: unknown }).cause,
1236
+ error: error0,
1237
+ isPublic,
1238
+ is: (cause) => this.is(cause),
1239
+ serialize: (cause) => this.serialize(cause, isPublic),
1240
+ })
1241
+ if (serializedCause !== undefined) {
1242
+ json.cause = serializedCause
1243
+ }
1244
+ } catch {
1245
+ // eslint-disable-next-line no-console
1246
+ console.error('Error0: failed to serialize cause', error0)
1247
+ }
1248
+ }
1249
+ return json
539
1250
  }
540
1251
 
541
- toJSON() {
542
- return {
543
- message: this.message,
544
- tag: this.tag,
545
- code: this.code,
546
- httpStatus: this.httpStatus,
547
- expected: this.expected,
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,
554
- }
555
- }
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
- )
1252
+ serialize(isPublic = true): Record<string, unknown> {
1253
+ const ctor = this.constructor as typeof Error0
1254
+ return ctor.serialize(this, isPublic)
572
1255
  }
573
- }
574
1256
 
575
- export namespace Error0 {
576
- export type JSON = ReturnType<Error0['toJSON']>
577
- export type Collection = Record<string, typeof Error0>
1257
+ round<TThis extends Error0>(this: TThis, isPublic = true): TThis {
1258
+ const ctor = this.constructor as typeof Error0
1259
+ return ctor.round(this, isPublic) as TThis
1260
+ }
578
1261
  }
579
-
580
- export const e0s = {
581
- Default: Error0,
582
- Expected: Error0.extend({
583
- defaultExpected: true,
584
- }) as typeof Error0,
585
- } satisfies Error0.Collection