@devp0nt/error0 1.0.0-next.42 → 1.0.0-next.44

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/src/index.ts CHANGED
@@ -6,9 +6,11 @@ type InferFirstArg<TFn> = TFn extends (...args: infer TArgs) => unknown
6
6
  ? TFirst
7
7
  : undefined
8
8
  : undefined
9
- type InferPluginPropInput<TProp extends ErrorPluginPropOptions<any, any, any>> = NormalizeUnknownToUndefined<
10
- InferFirstArg<TProp['init']>
11
- >
9
+ type InferPluginPropInput<TProp extends ErrorPluginPropOptions<any, any, any, any>> = TProp extends {
10
+ init: infer TInit
11
+ }
12
+ ? NormalizeUnknownToUndefined<InferFirstArg<TInit>>
13
+ : undefined
12
14
  type ErrorPluginPropInit<TInputValue, TOutputValue> = ((input: TInputValue) => TOutputValue) | (() => TOutputValue)
13
15
  type ErrorPluginPropSerialize<TOutputValue, TError extends Error0> =
14
16
  | ((options: { value: TOutputValue; error: TError; isPublic: boolean }) => unknown)
@@ -16,17 +18,38 @@ type ErrorPluginPropSerialize<TOutputValue, TError extends Error0> =
16
18
  type ErrorPluginPropDeserialize<TOutputValue> =
17
19
  | ((options: { value: unknown; serialized: Record<string, unknown> }) => TOutputValue | undefined)
18
20
  | false
19
-
20
- export type ErrorPluginPropOptions<TInputValue, TOutputValue, TError extends Error0 = Error0> = {
21
- init: ErrorPluginPropInit<TInputValue, TOutputValue>
21
+ type ErrorPluginPropOptionsBase<TOutputValue, TError extends Error0, TResolveValue extends TOutputValue | undefined> = {
22
22
  resolve: (options: {
23
- value: TOutputValue | undefined
23
+ own: TOutputValue | undefined
24
24
  flow: Array<TOutputValue | undefined>
25
25
  error: TError
26
- }) => TOutputValue | undefined
27
- serialize: ErrorPluginPropSerialize<TOutputValue, TError>
26
+ }) => TResolveValue
27
+ serialize: ErrorPluginPropSerialize<TResolveValue, TError>
28
28
  deserialize: ErrorPluginPropDeserialize<TOutputValue>
29
29
  }
30
+ type ErrorPluginPropOptionsWithInit<
31
+ TInputValue,
32
+ TOutputValue,
33
+ TError extends Error0,
34
+ TResolveValue extends TOutputValue | undefined,
35
+ > = ErrorPluginPropOptionsBase<TOutputValue, TError, TResolveValue> & {
36
+ init: ErrorPluginPropInit<TInputValue, TOutputValue>
37
+ }
38
+ type ErrorPluginPropOptionsWithoutInit<
39
+ TOutputValue,
40
+ TError extends Error0,
41
+ TResolveValue extends TOutputValue | undefined,
42
+ > = ErrorPluginPropOptionsBase<TOutputValue, TError, TResolveValue> & {
43
+ init?: undefined
44
+ }
45
+ export type ErrorPluginPropOptions<
46
+ TInputValue = undefined,
47
+ TOutputValue = unknown,
48
+ TError extends Error0 = Error0,
49
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
50
+ > =
51
+ | ErrorPluginPropOptionsWithInit<TInputValue, TOutputValue, TError, TResolveValue>
52
+ | ErrorPluginPropOptionsWithoutInit<TOutputValue, TError, TResolveValue>
30
53
  export type ErrorPluginMethodFn<TOutputValue, TArgs extends unknown[] = unknown[], TError extends Error0 = Error0> = (
31
54
  error: TError,
32
55
  ...args: TArgs
@@ -36,6 +59,15 @@ export type ErrorPluginAdaptFn<
36
59
  TError extends Error0 = Error0,
37
60
  TOutputProps extends Record<string, unknown> = Record<never, never>,
38
61
  > = ((error: TError) => void) | ((error: TError) => ErrorPluginAdaptResult<TOutputProps>)
62
+ export type ErrorPluginStackSerialize<TError extends Error0> =
63
+ | ((options: { value: string | undefined; error: TError; isPublic: boolean }) => unknown)
64
+ | boolean
65
+ | 'merge'
66
+ export type ErrorPluginStack<TError extends Error0 = Error0> = ErrorPluginStackSerialize<TError>
67
+ export type ErrorPluginCauseSerialize<TError extends Error0> =
68
+ | ((options: { value: unknown; error: TError; isPublic: boolean }) => unknown)
69
+ | boolean
70
+ export type ErrorPluginCause<TError extends Error0 = Error0> = ErrorPluginCauseSerialize<TError>
39
71
  type ErrorMethodRecord = {
40
72
  args: unknown[]
41
73
  output: unknown
@@ -51,9 +83,16 @@ export type ErrorPlugin<
51
83
  props?: TProps
52
84
  methods?: TMethods
53
85
  adapt?: Array<ErrorPluginAdaptFn<Error0, PluginOutputProps<TProps>>>
86
+ stack?: ErrorPluginStack
87
+ cause?: ErrorPluginCause
54
88
  }
55
- type AddPropToPluginProps<TProps extends ErrorPluginProps, TKey extends string, TInputValue, TOutputValue> = TProps &
56
- Record<TKey, ErrorPluginPropOptions<TInputValue, TOutputValue>>
89
+ type AddPropToPluginProps<
90
+ TProps extends ErrorPluginProps,
91
+ TKey extends string,
92
+ TInputValue,
93
+ TOutputValue,
94
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
95
+ > = TProps & Record<TKey, ErrorPluginPropOptions<TInputValue, TOutputValue, Error0, TResolveValue>>
57
96
  type AddMethodToPluginMethods<
58
97
  TMethods extends ErrorPluginMethods,
59
98
  TKey extends string,
@@ -61,10 +100,12 @@ type AddMethodToPluginMethods<
61
100
  TOutputValue,
62
101
  > = TMethods & Record<TKey, ErrorPluginMethodFn<TOutputValue, TArgs>>
63
102
  type PluginOutputProps<TProps extends ErrorPluginProps> = {
64
- [TKey in keyof TProps]: TProps[TKey] extends ErrorPluginPropOptions<any, infer TOutputValue> ? TOutputValue : never
103
+ [TKey in keyof TProps]: TProps[TKey] extends ErrorPluginPropOptions<any, any, any, infer TResolveValue>
104
+ ? TResolveValue
105
+ : never
65
106
  }
66
107
  export type ErrorPluginsMap = {
67
- props: Record<string, { init: unknown; resolve: unknown }>
108
+ props: Record<string, { init: unknown; output: unknown; resolve: unknown }>
68
109
  methods: Record<string, ErrorMethodRecord>
69
110
  }
70
111
  export type IsEmptyObject<T> = keyof T extends never ? true : false
@@ -81,10 +122,23 @@ export type ErrorInput<TPluginsMap extends ErrorPluginsMap> =
81
122
  ? ErrorInputBase
82
123
  : ErrorInputBase & ErrorInputPluginProps<TPluginsMap>
83
124
 
84
- type ErrorOutputProps<TPluginsMap extends ErrorPluginsMap> = {
85
- [TKey in keyof TPluginsMap['props']]: TPluginsMap['props'][TKey]['resolve'] | undefined
125
+ type ErrorResolvedProps<TPluginsMap extends ErrorPluginsMap> = {
126
+ [TKey in keyof TPluginsMap['props']]: TPluginsMap['props'][TKey]['resolve']
127
+ }
128
+ type ErrorOwnProps<TPluginsMap extends ErrorPluginsMap> = {
129
+ [TKey in keyof TPluginsMap['props']]: TPluginsMap['props'][TKey]['output'] | undefined
130
+ }
131
+ type ErrorOwnMethods<TPluginsMap extends ErrorPluginsMap> = {
132
+ own: {
133
+ (): ErrorOwnProps<TPluginsMap>
134
+ <TKey extends keyof TPluginsMap['props'] & string>(key: TKey): ErrorOwnProps<TPluginsMap>[TKey]
135
+ }
136
+ flow: <TKey extends keyof TPluginsMap['props'] & string>(key: TKey) => Array<ErrorOwnProps<TPluginsMap>[TKey]>
86
137
  }
87
- type ErrorOutputMethods<TPluginsMap extends ErrorPluginsMap> = {
138
+ type ErrorResolveMethods<TPluginsMap extends ErrorPluginsMap> = {
139
+ resolve: () => ErrorResolvedProps<TPluginsMap>
140
+ }
141
+ type ErrorMethods<TPluginsMap extends ErrorPluginsMap> = {
88
142
  [TKey in keyof TPluginsMap['methods']]: TPluginsMap['methods'][TKey] extends {
89
143
  args: infer TArgs extends unknown[]
90
144
  output: infer TOutput
@@ -92,8 +146,8 @@ type ErrorOutputMethods<TPluginsMap extends ErrorPluginsMap> = {
92
146
  ? (...args: TArgs) => TOutput
93
147
  : never
94
148
  }
95
- export type ErrorOutput<TPluginsMap extends ErrorPluginsMap> = ErrorOutputProps<TPluginsMap> &
96
- ErrorOutputMethods<TPluginsMap>
149
+ export type ErrorResolved<TPluginsMap extends ErrorPluginsMap> = ErrorResolvedProps<TPluginsMap> &
150
+ ErrorMethods<TPluginsMap>
97
151
 
98
152
  type ErrorStaticMethods<TPluginsMap extends ErrorPluginsMap> = {
99
153
  [TKey in keyof TPluginsMap['methods']]: TPluginsMap['methods'][TKey] extends {
@@ -105,22 +159,31 @@ type ErrorStaticMethods<TPluginsMap extends ErrorPluginsMap> = {
105
159
  }
106
160
 
107
161
  type EmptyPluginsMap = {
108
- props: Record<never, { init: never; resolve: never }>
162
+ props: Record<never, { init: never; output: never; resolve: never }>
109
163
  methods: Record<never, ErrorMethodRecord>
110
164
  }
111
165
 
112
166
  type ErrorPluginResolved = {
113
- props: Record<string, ErrorPluginPropOptions<unknown, unknown>>
167
+ props: Record<string, ErrorPluginPropOptions<unknown>>
114
168
  methods: Record<string, ErrorPluginMethodFn<unknown>>
115
169
  adapt: Array<ErrorPluginAdaptFn<Error0, Record<string, unknown>>>
170
+ stack?: ErrorPluginStack
171
+ cause?: ErrorPluginCause
116
172
  }
173
+ const RESERVED_STACK_PROP_ERROR = 'Error0: "stack" is a reserved prop key. Use .stack(...) plugin API instead'
117
174
 
118
175
  type PluginPropsMapOf<TPlugin extends ErrorPlugin> = {
119
176
  [TKey in keyof NonNullable<TPlugin['props']>]: NonNullable<TPlugin['props']>[TKey] extends ErrorPluginPropOptions<
120
177
  any,
121
- infer TOutputValue
178
+ infer TOutputValue,
179
+ any,
180
+ infer TResolveValue
122
181
  >
123
- ? { init: InferPluginPropInput<NonNullable<TPlugin['props']>[TKey]>; resolve: TOutputValue }
182
+ ? {
183
+ init: InferPluginPropInput<NonNullable<TPlugin['props']>[TKey]>
184
+ output: TOutputValue
185
+ resolve: TResolveValue
186
+ }
124
187
  : never
125
188
  }
126
189
  type PluginMethodsMapOf<TPlugin extends ErrorPlugin> = {
@@ -144,7 +207,11 @@ type ExtendErrorPluginsMapWithProp<
144
207
  TKey extends string,
145
208
  TInputValue,
146
209
  TOutputValue,
147
- > = ExtendErrorPluginsMap<TMap, ErrorPlugin<Record<TKey, ErrorPluginPropOptions<TInputValue, TOutputValue>>>>
210
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
211
+ > = ExtendErrorPluginsMap<
212
+ TMap,
213
+ ErrorPlugin<Record<TKey, ErrorPluginPropOptions<TInputValue, TOutputValue, Error0, TResolveValue>>>
214
+ >
148
215
  type ExtendErrorPluginsMapWithMethod<
149
216
  TMap extends ErrorPluginsMap,
150
217
  TKey extends string,
@@ -160,14 +227,19 @@ type PluginsMapOf<TClass> = TClass extends { __pluginsMap?: infer TPluginsMap }
160
227
  ? TPluginsMap
161
228
  : EmptyPluginsMap
162
229
  : EmptyPluginsMap
230
+ type PluginsMapOfInstance<TInstance> = TInstance extends { constructor: { __pluginsMap?: infer TPluginsMap } }
231
+ ? TPluginsMap extends ErrorPluginsMap
232
+ ? TPluginsMap
233
+ : EmptyPluginsMap
234
+ : EmptyPluginsMap
163
235
 
164
236
  type PluginsMapFromParts<
165
237
  TProps extends ErrorPluginProps,
166
238
  TMethods extends ErrorPluginMethods,
167
239
  > = ErrorPluginsMapOfPlugin<ErrorPlugin<TProps, TMethods>>
168
- type ErrorInstanceOfMap<TMap extends ErrorPluginsMap> = Error0 & ErrorOutput<TMap>
240
+ type ErrorInstanceOfMap<TMap extends ErrorPluginsMap> = Error0 & ErrorResolved<TMap>
169
241
  type BuilderError0<TProps extends ErrorPluginProps, TMethods extends ErrorPluginMethods> = Error0 &
170
- ErrorOutput<PluginsMapFromParts<TProps, TMethods>>
242
+ ErrorResolved<PluginsMapFromParts<TProps, TMethods>>
171
243
 
172
244
  type PluginOfBuilder<TBuilder> =
173
245
  TBuilder extends PluginError0<infer TProps, infer TMethods> ? ErrorPlugin<TProps, TMethods> : never
@@ -188,13 +260,20 @@ export class PluginError0<
188
260
  props: { ...(plugin?.props ?? {}) },
189
261
  methods: { ...(plugin?.methods ?? {}) },
190
262
  adapt: [...(plugin?.adapt ?? [])],
263
+ stack: plugin?.stack,
264
+ cause: plugin?.cause,
191
265
  }
192
266
  }
193
267
 
194
- prop<TKey extends string, TInputValue, TOutputValue>(
268
+ prop<
269
+ TKey extends string,
270
+ TInputValue = undefined,
271
+ TOutputValue = unknown,
272
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
273
+ >(
195
274
  key: TKey,
196
- value: ErrorPluginPropOptions<TInputValue, TOutputValue, BuilderError0<TProps, TMethods>>,
197
- ): PluginError0<AddPropToPluginProps<TProps, TKey, TInputValue, TOutputValue>, TMethods> {
275
+ value: ErrorPluginPropOptions<TInputValue, TOutputValue, BuilderError0<TProps, TMethods>, TResolveValue>,
276
+ ): PluginError0<AddPropToPluginProps<TProps, TKey, TInputValue, TOutputValue, TResolveValue>, TMethods> {
198
277
  return this.use('prop', key, value)
199
278
  }
200
279
 
@@ -211,11 +290,24 @@ export class PluginError0<
211
290
  return this.use('adapt', value)
212
291
  }
213
292
 
214
- use<TKey extends string, TInputValue, TOutputValue>(
293
+ stack(value: ErrorPluginStack<BuilderError0<TProps, TMethods>>): PluginError0<TProps, TMethods> {
294
+ return this.use('stack', value)
295
+ }
296
+
297
+ cause(value: ErrorPluginCause<BuilderError0<TProps, TMethods>>): PluginError0<TProps, TMethods> {
298
+ return this.use('cause', value)
299
+ }
300
+
301
+ use<
302
+ TKey extends string,
303
+ TInputValue = undefined,
304
+ TOutputValue = unknown,
305
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
306
+ >(
215
307
  kind: 'prop',
216
308
  key: TKey,
217
- value: ErrorPluginPropOptions<TInputValue, TOutputValue, BuilderError0<TProps, TMethods>>,
218
- ): PluginError0<AddPropToPluginProps<TProps, TKey, TInputValue, TOutputValue>, TMethods>
309
+ value: ErrorPluginPropOptions<TInputValue, TOutputValue, BuilderError0<TProps, TMethods>, TResolveValue>,
310
+ ): PluginError0<AddPropToPluginProps<TProps, TKey, TInputValue, TOutputValue, TResolveValue>, TMethods>
219
311
  use<TKey extends string, TArgs extends unknown[], TOutputValue>(
220
312
  kind: 'method',
221
313
  key: TKey,
@@ -225,16 +317,23 @@ export class PluginError0<
225
317
  kind: 'adapt',
226
318
  value: ErrorPluginAdaptFn<BuilderError0<TProps, TMethods>, PluginOutputProps<TProps>>,
227
319
  ): PluginError0<TProps, TMethods>
320
+ use(kind: 'stack', value: ErrorPluginStack<BuilderError0<TProps, TMethods>>): PluginError0<TProps, TMethods>
321
+ use(kind: 'cause', value: ErrorPluginCause<BuilderError0<TProps, TMethods>>): PluginError0<TProps, TMethods>
228
322
  use(
229
- kind: 'prop' | 'method' | 'adapt',
230
- keyOrValue: string | ErrorPluginAdaptFn<any, any>,
323
+ kind: 'prop' | 'method' | 'adapt' | 'stack' | 'cause',
324
+ keyOrValue: unknown,
231
325
  value?: ErrorPluginPropOptions<unknown, unknown, any> | ErrorPluginMethodFn<unknown, unknown[], any>,
232
326
  ): PluginError0<any, any> {
233
327
  const nextProps: ErrorPluginProps = { ...(this._plugin.props ?? {}) }
234
328
  const nextMethods: ErrorPluginMethods = { ...(this._plugin.methods ?? {}) }
235
329
  const nextAdapt: Array<ErrorPluginAdaptFn<Error0, Record<string, unknown>>> = [...(this._plugin.adapt ?? [])]
330
+ let nextStack: ErrorPluginStack | undefined = this._plugin.stack
331
+ let nextCause: ErrorPluginCause | undefined = this._plugin.cause
236
332
  if (kind === 'prop') {
237
333
  const key = keyOrValue as string
334
+ if (key === 'stack') {
335
+ throw new Error(RESERVED_STACK_PROP_ERROR)
336
+ }
238
337
  if (value === undefined) {
239
338
  throw new Error('PluginError0.use("prop", key, value) requires value')
240
339
  }
@@ -245,43 +344,77 @@ export class PluginError0<
245
344
  throw new Error('PluginError0.use("method", key, value) requires value')
246
345
  }
247
346
  nextMethods[key] = value as ErrorPluginMethodFn<any, any[]>
248
- } else {
347
+ } else if (kind === 'adapt') {
249
348
  nextAdapt.push(keyOrValue as ErrorPluginAdaptFn<Error0, Record<string, unknown>>)
349
+ } else if (kind === 'stack') {
350
+ nextStack = keyOrValue as ErrorPluginStack
351
+ } else {
352
+ nextCause = keyOrValue as ErrorPluginCause
250
353
  }
251
354
  return new PluginError0({
252
355
  props: nextProps,
253
356
  methods: nextMethods,
254
357
  adapt: nextAdapt,
358
+ stack: nextStack,
359
+ cause: nextCause,
255
360
  })
256
361
  }
257
362
  }
258
363
 
259
364
  export type ClassError0<TPluginsMap extends ErrorPluginsMap = EmptyPluginsMap> = {
260
- new (message: string, input?: ErrorInput<TPluginsMap>): Error0 & ErrorOutput<TPluginsMap>
261
- new (input: { message: string } & ErrorInput<TPluginsMap>): Error0 & ErrorOutput<TPluginsMap>
365
+ new (
366
+ message: string,
367
+ input?: ErrorInput<TPluginsMap>,
368
+ ): Error0 & ErrorResolved<TPluginsMap> & ErrorOwnMethods<TPluginsMap> & ErrorResolveMethods<TPluginsMap>
369
+ new (
370
+ input: { message: string } & ErrorInput<TPluginsMap>,
371
+ ): Error0 & ErrorResolved<TPluginsMap> & ErrorOwnMethods<TPluginsMap> & ErrorResolveMethods<TPluginsMap>
262
372
  readonly __pluginsMap?: TPluginsMap
263
- from: (error: unknown) => Error0 & ErrorOutput<TPluginsMap>
373
+ from: (
374
+ error: unknown,
375
+ ) => Error0 & ErrorResolved<TPluginsMap> & ErrorOwnMethods<TPluginsMap> & ErrorResolveMethods<TPluginsMap>
376
+ resolve: (error: unknown) => ErrorResolvedProps<TPluginsMap>
264
377
  serialize: (error: unknown, isPublic?: boolean) => Record<string, unknown>
265
- prop: <TKey extends string, TInputValue, TOutputValue>(
378
+ own: {
379
+ (error: object): ErrorOwnProps<TPluginsMap>
380
+ <TKey extends keyof TPluginsMap['props'] & string>(error: object, key: TKey): ErrorOwnProps<TPluginsMap>[TKey]
381
+ }
382
+ flow: <TKey extends keyof TPluginsMap['props'] & string>(
383
+ error: object,
266
384
  key: TKey,
267
- value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<TPluginsMap>>,
268
- ) => ClassError0<ExtendErrorPluginsMapWithProp<TPluginsMap, TKey, TInputValue, TOutputValue>>
385
+ ) => Array<ErrorOwnProps<TPluginsMap>[TKey]>
386
+ prop: <
387
+ TKey extends string,
388
+ TInputValue = undefined,
389
+ TOutputValue = unknown,
390
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
391
+ >(
392
+ key: TKey,
393
+ value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<TPluginsMap>, TResolveValue>,
394
+ ) => ClassError0<ExtendErrorPluginsMapWithProp<TPluginsMap, TKey, TInputValue, TOutputValue, TResolveValue>>
269
395
  method: <TKey extends string, TArgs extends unknown[], TOutputValue>(
270
396
  key: TKey,
271
397
  value: ErrorPluginMethodFn<TOutputValue, TArgs, ErrorInstanceOfMap<TPluginsMap>>,
272
398
  ) => ClassError0<ExtendErrorPluginsMapWithMethod<TPluginsMap, TKey, TArgs, TOutputValue>>
273
399
  adapt: (
274
- value: ErrorPluginAdaptFn<ErrorInstanceOfMap<TPluginsMap>, ErrorOutputProps<TPluginsMap>>,
400
+ value: ErrorPluginAdaptFn<ErrorInstanceOfMap<TPluginsMap>, ErrorResolvedProps<TPluginsMap>>,
275
401
  ) => ClassError0<TPluginsMap>
402
+ stack: (value: ErrorPluginStack<ErrorInstanceOfMap<TPluginsMap>>) => ClassError0<TPluginsMap>
403
+ cause: (value: ErrorPluginCause<ErrorInstanceOfMap<TPluginsMap>>) => ClassError0<TPluginsMap>
276
404
  use: {
277
405
  <TBuilder extends PluginError0>(
278
406
  plugin: TBuilder,
279
407
  ): ClassError0<ExtendErrorPluginsMap<TPluginsMap, PluginOfBuilder<TBuilder>>>
280
- <TKey extends string, TInputValue, TOutputValue>(
408
+ <
409
+ TKey extends string,
410
+ TInputValue = undefined,
411
+ TOutputValue = unknown,
412
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
413
+ >(
281
414
  kind: 'prop',
282
415
  key: TKey,
283
- value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<TPluginsMap>>,
284
- ): ClassError0<ExtendErrorPluginsMapWithProp<TPluginsMap, TKey, TInputValue, TOutputValue>>
416
+ value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<TPluginsMap>, TResolveValue>,
417
+ ): ClassError0<ExtendErrorPluginsMapWithProp<TPluginsMap, TKey, TInputValue, TOutputValue, TResolveValue>>
285
418
  <TKey extends string, TArgs extends unknown[], TOutputValue>(
286
419
  kind: 'method',
287
420
  key: TKey,
@@ -289,8 +422,10 @@ export type ClassError0<TPluginsMap extends ErrorPluginsMap = EmptyPluginsMap> =
289
422
  ): ClassError0<ExtendErrorPluginsMapWithMethod<TPluginsMap, TKey, TArgs, TOutputValue>>
290
423
  (
291
424
  kind: 'adapt',
292
- value: ErrorPluginAdaptFn<ErrorInstanceOfMap<TPluginsMap>, ErrorOutputProps<TPluginsMap>>,
425
+ value: ErrorPluginAdaptFn<ErrorInstanceOfMap<TPluginsMap>, ErrorResolvedProps<TPluginsMap>>,
293
426
  ): ClassError0<TPluginsMap>
427
+ (kind: 'stack', value: ErrorPluginStack<ErrorInstanceOfMap<TPluginsMap>>): ClassError0<TPluginsMap>
428
+ (kind: 'cause', value: ErrorPluginCause<ErrorInstanceOfMap<TPluginsMap>>): ClassError0<TPluginsMap>
294
429
  }
295
430
  plugin: () => PluginError0
296
431
  } & ErrorStaticMethods<TPluginsMap>
@@ -303,6 +438,8 @@ export class Error0 extends Error {
303
438
  props: {},
304
439
  methods: {},
305
440
  adapt: [],
441
+ stack: undefined,
442
+ cause: undefined,
306
443
  }
307
444
 
308
445
  private static _getResolvedPlugin(this: typeof Error0): ErrorPluginResolved {
@@ -312,9 +449,18 @@ export class Error0 extends Error {
312
449
  adapt: [],
313
450
  }
314
451
  for (const plugin of this._plugins) {
452
+ if (plugin.props && 'stack' in plugin.props) {
453
+ throw new Error(RESERVED_STACK_PROP_ERROR)
454
+ }
315
455
  Object.assign(resolved.props, plugin.props ?? this._emptyPlugin.props)
316
456
  Object.assign(resolved.methods, plugin.methods ?? this._emptyPlugin.methods)
317
457
  resolved.adapt.push(...(plugin.adapt ?? this._emptyPlugin.adapt))
458
+ if (typeof plugin.stack !== 'undefined') {
459
+ resolved.stack = plugin.stack
460
+ }
461
+ if (typeof plugin.cause !== 'undefined') {
462
+ resolved.cause = plugin.cause
463
+ }
318
464
  }
319
465
  return resolved
320
466
  }
@@ -336,12 +482,19 @@ export class Error0 extends Error {
336
482
  const plugin = ctor._getResolvedPlugin()
337
483
 
338
484
  for (const [key, prop] of Object.entries(plugin.props)) {
485
+ if (key === 'stack') {
486
+ continue
487
+ }
339
488
  if (key in input) {
340
489
  const ownValue = (input as Record<string, unknown>)[key]
341
- ;(this as Record<string, unknown>)[key] = prop.init(ownValue)
490
+ if (typeof prop.init === 'function') {
491
+ ;(this as Record<string, unknown>)[key] = prop.init(ownValue)
492
+ } else {
493
+ ;(this as Record<string, unknown>)[key] = ownValue
494
+ }
342
495
  } else {
343
496
  Object.defineProperty(this, key, {
344
- get: () => prop.resolve({ value: undefined, flow: this.flow(key), error: this }),
497
+ get: () => prop.resolve({ own: undefined, flow: this.flow(key), error: this }),
345
498
  set: (value) => {
346
499
  Object.defineProperty(this, key, {
347
500
  value,
@@ -369,26 +522,105 @@ export class Error0 extends Error {
369
522
  }
370
523
  return true
371
524
  }
372
-
373
- static own(error: object, key: string): unknown {
525
+ private static _ownByKey(error: object, key: string): unknown {
374
526
  if (this.isSelfProperty(error, key)) {
375
527
  return (error as Record<string, unknown>)[key]
376
528
  }
377
529
  return undefined
378
530
  }
379
- own(key: string): unknown {
531
+ private static _flowByKey(error: object, key: string): unknown[] {
532
+ return this.causes(error, true).map((cause) => {
533
+ return this._ownByKey(cause, key)
534
+ })
535
+ }
536
+
537
+ static own<TThis extends typeof Error0>(this: TThis, error: unknown): ErrorOwnProps<PluginsMapOf<TThis>>
538
+ static own<TThis extends typeof Error0, TKey extends keyof PluginsMapOf<TThis>['props'] & string>(
539
+ this: TThis,
540
+ error: unknown,
541
+ key: TKey,
542
+ ): ErrorOwnProps<PluginsMapOf<TThis>>[TKey]
543
+ static own(error: unknown, key?: string): unknown {
544
+ const error0 = this.from(error)
545
+ if (key === undefined) {
546
+ const ownValues: Record<string, unknown> = {}
547
+ const plugin = this._getResolvedPlugin()
548
+ for (const ownKey of Object.keys(plugin.props)) {
549
+ ownValues[ownKey] = this._ownByKey(error0, ownKey)
550
+ }
551
+ return ownValues
552
+ }
553
+ return this._ownByKey(error0, key)
554
+ }
555
+ own<TThis extends Error0>(this: TThis): ErrorOwnProps<PluginsMapOfInstance<TThis>>
556
+ own<TThis extends Error0, TKey extends keyof PluginsMapOfInstance<TThis>['props'] & string>(
557
+ this: TThis,
558
+ key: TKey,
559
+ ): ErrorOwnProps<PluginsMapOfInstance<TThis>>[TKey]
560
+ own(key?: string): unknown {
380
561
  const ctor = this.constructor as typeof Error0
381
- return ctor.own(this, key)
562
+ if (key === undefined) {
563
+ return ctor.own(this)
564
+ }
565
+ return ctor._ownByKey(this, key)
382
566
  }
383
567
 
384
- static flow(error: object, key: string): unknown[] {
385
- return this.causes(error, true).map((cause) => {
386
- return this.own(cause, key)
387
- })
568
+ static flow<TThis extends typeof Error0, TKey extends keyof PluginsMapOf<TThis>['props'] & string>(
569
+ this: TThis,
570
+ error: unknown,
571
+ key: TKey,
572
+ ): Array<ErrorOwnProps<PluginsMapOf<TThis>>[TKey]>
573
+ static flow(error: unknown, key: string): unknown[]
574
+ static flow(error: unknown, key: string): unknown[] {
575
+ const error0 = this.from(error)
576
+ return this._flowByKey(error0, key)
388
577
  }
578
+ flow<TThis extends Error0, TKey extends keyof PluginsMapOfInstance<TThis>['props'] & string>(
579
+ this: TThis,
580
+ key: TKey,
581
+ ): Array<ErrorOwnProps<PluginsMapOfInstance<TThis>>[TKey]>
582
+ flow(key: string): unknown[]
389
583
  flow(key: string): unknown[] {
390
584
  const ctor = this.constructor as typeof Error0
391
- return ctor.flow(this, key)
585
+ return ctor._flowByKey(this, key)
586
+ }
587
+
588
+ static resolve<TThis extends typeof Error0>(this: TThis, error: unknown): ErrorResolvedProps<PluginsMapOf<TThis>>
589
+ static resolve(error: unknown): Record<string, unknown>
590
+ static resolve(error: unknown): Record<string, unknown> {
591
+ const error0 = this.from(error)
592
+ const resolved: Record<string, unknown> = {}
593
+ const plugin = this._getResolvedPlugin()
594
+ for (const [key, prop] of Object.entries(plugin.props)) {
595
+ try {
596
+ // resolved[key] = (error0 as unknown as Record<string, unknown>)[key]
597
+ const options = Object.defineProperties(
598
+ {
599
+ error: error0,
600
+ },
601
+ {
602
+ own: {
603
+ get: () => error0.own(key as never),
604
+ },
605
+ flow: {
606
+ get: () => error0.flow(key),
607
+ },
608
+ },
609
+ )
610
+ resolved[key] = prop.resolve(options as never)
611
+ // resolved[key] = prop.resolve({ own: error0.own(key as never), flow: error0.flow(key), error: error0 })
612
+ } catch {
613
+ // eslint-disable-next-line no-console
614
+ console.error(`Error0: failed to resolve property ${key}`, error0)
615
+ }
616
+ }
617
+ return resolved
618
+ }
619
+ resolve<TThis extends Error0>(this: TThis): ErrorResolvedProps<PluginsMapOfInstance<TThis>>
620
+ resolve(): Record<string, unknown>
621
+ resolve(): Record<string, unknown> {
622
+ const ctor = this.constructor as typeof Error0
623
+ return ctor.resolve(this)
392
624
  }
393
625
 
394
626
  static causes(error: unknown, instancesOnly?: false): unknown[]
@@ -413,8 +645,8 @@ export class Error0 extends Error {
413
645
  }
414
646
  return causes
415
647
  }
416
- causes<T extends typeof Error0>(this: T, instancesOnly?: false): [InstanceType<T>, ...unknown[]]
417
- causes<T extends typeof Error0>(this: T, instancesOnly: true): [InstanceType<T>, ...Array<InstanceType<T>>]
648
+ causes<TThis extends Error0>(this: TThis, instancesOnly?: false): [TThis, ...unknown[]]
649
+ causes<TThis extends Error0>(this: TThis, instancesOnly: true): [TThis, ...TThis[]]
418
650
  causes(instancesOnly?: boolean): unknown[] {
419
651
  const ctor = this.constructor as typeof Error0
420
652
  if (instancesOnly) {
@@ -472,14 +704,35 @@ export class Error0 extends Error {
472
704
  const value = prop.deserialize({ value: errorRecord[key], serialized: errorRecord })
473
705
  ;(recreated as unknown as Record<string, unknown>)[key] = value
474
706
  } catch {
475
- // ignore
707
+ // eslint-disable-next-line no-console
708
+ console.error(`Error0: failed to deserialize property ${key}`, errorRecord)
476
709
  }
477
710
  }
478
711
  // we do not serialize causes
479
712
  // ;(recreated as unknown as { cause?: unknown }).cause = errorRecord.cause
480
- const isStackInProps = propsEntries.some(([key]) => key === 'stack')
481
- if (typeof errorRecord.stack === 'string' && !isStackInProps) {
482
- recreated.stack = errorRecord.stack
713
+ const stackPlugin = plugin.stack
714
+ if (stackPlugin !== false && 'stack' in errorRecord) {
715
+ try {
716
+ if (typeof errorRecord.stack === 'string') {
717
+ recreated.stack = errorRecord.stack
718
+ }
719
+ } catch {
720
+ // eslint-disable-next-line no-console
721
+ console.error('Error0: failed to deserialize stack', errorRecord)
722
+ }
723
+ }
724
+ const causePlugin = plugin.cause ?? false
725
+ if (causePlugin && 'cause' in errorRecord) {
726
+ try {
727
+ if (this.isSerialized(errorRecord.cause)) {
728
+ ;(recreated as { cause?: unknown }).cause = this._fromSerialized(errorRecord.cause)
729
+ } else {
730
+ ;(recreated as { cause?: unknown }).cause = errorRecord.cause
731
+ }
732
+ } catch {
733
+ // eslint-disable-next-line no-console
734
+ console.error('Error0: failed to deserialize cause', errorRecord)
735
+ }
483
736
  }
484
737
  return recreated
485
738
  }
@@ -538,14 +791,22 @@ export class Error0 extends Error {
538
791
  props: { ...(pluginRecord._plugin.props ?? {}) },
539
792
  methods: { ...(pluginRecord._plugin.methods ?? {}) },
540
793
  adapt: [...(pluginRecord._plugin.adapt ?? [])],
794
+ stack: pluginRecord._plugin.stack,
795
+ cause: pluginRecord._plugin.cause,
541
796
  }
542
797
  }
543
798
 
544
- static prop<TThis extends typeof Error0, TKey extends string, TInputValue, TOutputValue>(
799
+ static prop<
800
+ TThis extends typeof Error0,
801
+ TKey extends string,
802
+ TInputValue = undefined,
803
+ TOutputValue = unknown,
804
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
805
+ >(
545
806
  this: TThis,
546
807
  key: TKey,
547
- value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<PluginsMapOf<TThis>>>,
548
- ): ClassError0<ExtendErrorPluginsMapWithProp<PluginsMapOf<TThis>, TKey, TInputValue, TOutputValue>> {
808
+ value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<PluginsMapOf<TThis>>, TResolveValue>,
809
+ ): ClassError0<ExtendErrorPluginsMapWithProp<PluginsMapOf<TThis>, TKey, TInputValue, TOutputValue, TResolveValue>> {
549
810
  return this.use('prop', key, value)
550
811
  }
551
812
 
@@ -559,21 +820,41 @@ export class Error0 extends Error {
559
820
 
560
821
  static adapt<TThis extends typeof Error0>(
561
822
  this: TThis,
562
- value: ErrorPluginAdaptFn<ErrorInstanceOfMap<PluginsMapOf<TThis>>, ErrorOutputProps<PluginsMapOf<TThis>>>,
823
+ value: ErrorPluginAdaptFn<ErrorInstanceOfMap<PluginsMapOf<TThis>>, ErrorResolvedProps<PluginsMapOf<TThis>>>,
563
824
  ): ClassError0<PluginsMapOf<TThis>> {
564
825
  return this.use('adapt', value)
565
826
  }
566
827
 
828
+ static stack<TThis extends typeof Error0>(
829
+ this: TThis,
830
+ value: ErrorPluginStack<ErrorInstanceOfMap<PluginsMapOf<TThis>>>,
831
+ ): ClassError0<PluginsMapOf<TThis>> {
832
+ return this.use('stack', value)
833
+ }
834
+
835
+ static cause<TThis extends typeof Error0>(
836
+ this: TThis,
837
+ value: ErrorPluginCause<ErrorInstanceOfMap<PluginsMapOf<TThis>>>,
838
+ ): ClassError0<PluginsMapOf<TThis>> {
839
+ return this.use('cause', value)
840
+ }
841
+
567
842
  static use<TThis extends typeof Error0, TBuilder extends PluginError0>(
568
843
  this: TThis,
569
844
  plugin: TBuilder,
570
845
  ): ClassError0<ExtendErrorPluginsMap<PluginsMapOf<TThis>, PluginOfBuilder<TBuilder>>>
571
- static use<TThis extends typeof Error0, TKey extends string, TInputValue, TOutputValue>(
846
+ static use<
847
+ TThis extends typeof Error0,
848
+ TKey extends string,
849
+ TInputValue = undefined,
850
+ TOutputValue = unknown,
851
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
852
+ >(
572
853
  this: TThis,
573
854
  kind: 'prop',
574
855
  key: TKey,
575
- value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<PluginsMapOf<TThis>>>,
576
- ): ClassError0<ExtendErrorPluginsMapWithProp<PluginsMapOf<TThis>, TKey, TInputValue, TOutputValue>>
856
+ value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<PluginsMapOf<TThis>>, TResolveValue>,
857
+ ): ClassError0<ExtendErrorPluginsMapWithProp<PluginsMapOf<TThis>, TKey, TInputValue, TOutputValue, TResolveValue>>
577
858
  static use<TThis extends typeof Error0, TKey extends string, TArgs extends unknown[], TOutputValue>(
578
859
  this: TThis,
579
860
  kind: 'method',
@@ -583,23 +864,55 @@ export class Error0 extends Error {
583
864
  static use<TThis extends typeof Error0>(
584
865
  this: TThis,
585
866
  kind: 'adapt',
586
- value: ErrorPluginAdaptFn<ErrorInstanceOfMap<PluginsMapOf<TThis>>, ErrorOutputProps<PluginsMapOf<TThis>>>,
867
+ value: ErrorPluginAdaptFn<ErrorInstanceOfMap<PluginsMapOf<TThis>>, ErrorResolvedProps<PluginsMapOf<TThis>>>,
868
+ ): ClassError0<PluginsMapOf<TThis>>
869
+ static use<TThis extends typeof Error0>(
870
+ this: TThis,
871
+ kind: 'stack',
872
+ value: ErrorPluginStack<ErrorInstanceOfMap<PluginsMapOf<TThis>>>,
873
+ ): ClassError0<PluginsMapOf<TThis>>
874
+ static use<TThis extends typeof Error0>(
875
+ this: TThis,
876
+ kind: 'cause',
877
+ value: ErrorPluginCause<ErrorInstanceOfMap<PluginsMapOf<TThis>>>,
587
878
  ): ClassError0<PluginsMapOf<TThis>>
588
879
  static use(
589
880
  this: typeof Error0,
590
- first: PluginError0 | 'prop' | 'method' | 'adapt',
591
- key?: string | ErrorPluginAdaptFn<any, any>,
592
- value?: ErrorPluginPropOptions<unknown, unknown> | ErrorPluginMethodFn<unknown>,
881
+ first: PluginError0 | 'prop' | 'method' | 'adapt' | 'stack' | 'cause',
882
+ key?: unknown,
883
+ value?: ErrorPluginPropOptions<unknown> | ErrorPluginMethodFn<unknown>,
593
884
  ): ClassError0 {
594
885
  if (first instanceof PluginError0) {
595
886
  return this._useWithPlugin(this._pluginFromBuilder(first))
596
887
  }
888
+ if (first === 'stack') {
889
+ if (typeof key === 'undefined') {
890
+ throw new Error('Error0.use("stack", value) requires stack plugin value')
891
+ }
892
+ if (key !== 'merge' && typeof key !== 'boolean' && typeof key !== 'function') {
893
+ throw new Error('Error0.use("stack", value) expects function | boolean | "merge"')
894
+ }
895
+ return this._useWithPlugin({
896
+ stack: key as ErrorPluginStack,
897
+ })
898
+ }
899
+ if (first === 'cause') {
900
+ if (typeof key === 'undefined') {
901
+ throw new Error('Error0.use("cause", value) requires cause plugin value')
902
+ }
903
+ if (typeof key !== 'boolean' && typeof key !== 'function') {
904
+ throw new Error('Error0.use("cause", value) expects function | boolean')
905
+ }
906
+ return this._useWithPlugin({
907
+ cause: key as ErrorPluginCause,
908
+ })
909
+ }
597
910
  if (first === 'adapt') {
598
911
  if (typeof key !== 'function') {
599
912
  throw new Error('Error0.use("adapt", value) requires adapt function')
600
913
  }
601
914
  return this._useWithPlugin({
602
- adapt: [key],
915
+ adapt: [key as ErrorPluginAdaptFn<Error0, Record<string, unknown>>],
603
916
  })
604
917
  }
605
918
  if (typeof key !== 'string' || value === undefined) {
@@ -607,8 +920,11 @@ export class Error0 extends Error {
607
920
  }
608
921
 
609
922
  if (first === 'prop') {
923
+ if (key === 'stack') {
924
+ throw new Error(RESERVED_STACK_PROP_ERROR)
925
+ }
610
926
  return this._useWithPlugin({
611
- props: { [key]: value as ErrorPluginPropOptions<unknown, unknown> },
927
+ props: { [key]: value as ErrorPluginPropOptions<unknown> },
612
928
  })
613
929
  }
614
930
  return this._useWithPlugin({
@@ -622,6 +938,8 @@ export class Error0 extends Error {
622
938
 
623
939
  static serialize(error: unknown, isPublic = true): Record<string, unknown> {
624
940
  const error0 = this.from(error)
941
+ const resolvedProps = this.resolve(error0)
942
+ const resolvedRecord = resolvedProps as Record<string, unknown>
625
943
  const json: Record<string, unknown> = {
626
944
  name: error0.name,
627
945
  message: error0.message,
@@ -636,18 +954,63 @@ export class Error0 extends Error {
636
954
  continue
637
955
  }
638
956
  try {
639
- const value = prop.resolve({ value: error0.own(key), flow: error0.flow(key), error: error0 })
957
+ const value = resolvedRecord[key]
640
958
  const jsonValue = prop.serialize({ value, error: error0, isPublic })
641
959
  if (jsonValue !== undefined) {
642
960
  json[key] = jsonValue
643
961
  }
644
962
  } catch {
645
- // ignore
963
+ // eslint-disable-next-line no-console
964
+ console.error(`Error0: failed to serialize property ${key}`, resolvedRecord)
646
965
  }
647
966
  }
648
- const isStackInProps = propsEntries.some(([key]) => key === 'stack')
649
- if (!isStackInProps && typeof error0.stack === 'string') {
650
- json.stack = error0.stack
967
+ const stackSerialize = plugin.stack
968
+ if (stackSerialize !== false) {
969
+ try {
970
+ let serializedStack: unknown
971
+ if (stackSerialize === 'merge') {
972
+ serializedStack = error0
973
+ .causes()
974
+ .map((cause) => {
975
+ return cause instanceof Error ? cause.stack : undefined
976
+ })
977
+ .filter((value): value is string => typeof value === 'string')
978
+ .join('\n')
979
+ } else if (typeof stackSerialize === 'function') {
980
+ serializedStack = stackSerialize({ value: error0.stack, error: error0, isPublic })
981
+ } else {
982
+ serializedStack = error0.stack
983
+ }
984
+ if (serializedStack !== undefined) {
985
+ json.stack = serializedStack
986
+ }
987
+ } catch {
988
+ // eslint-disable-next-line no-console
989
+ console.error('Error0: failed to serialize stack', error0)
990
+ }
991
+ }
992
+ const causeSerialize = plugin.cause ?? false
993
+ if (causeSerialize) {
994
+ try {
995
+ if (causeSerialize === true) {
996
+ const causeValue = (error0 as { cause?: unknown }).cause
997
+ if (this.is(causeValue)) {
998
+ json.cause = this.serialize(causeValue, isPublic)
999
+ }
1000
+ } else {
1001
+ const serializedCause = causeSerialize({
1002
+ value: (error0 as { cause?: unknown }).cause,
1003
+ error: error0,
1004
+ isPublic,
1005
+ })
1006
+ if (serializedCause !== undefined) {
1007
+ json.cause = serializedCause
1008
+ }
1009
+ }
1010
+ } catch {
1011
+ // eslint-disable-next-line no-console
1012
+ console.error('Error0: failed to serialize cause', error0)
1013
+ }
651
1014
  }
652
1015
  return Object.fromEntries(Object.entries(json).filter(([, value]) => value !== undefined)) as Record<
653
1016
  string,
@@ -655,7 +1018,7 @@ export class Error0 extends Error {
655
1018
  >
656
1019
  }
657
1020
 
658
- serialize(isPublic = true): object {
1021
+ serialize(isPublic = true): Record<string, unknown> {
659
1022
  const ctor = this.constructor as typeof Error0
660
1023
  return ctor.serialize(this, isPublic)
661
1024
  }