@devp0nt/error0 1.0.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts ADDED
@@ -0,0 +1,584 @@
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: store tags as array from all causes
7
+ // TODO: not use self stack if toError0
8
+ // TODO: fix default message in extended error0, should be used in constuctor of Error0
9
+ // TODO: remove defaults prop from getPropsFromUnknown
10
+ // TODO: code has enum type, fn to check if code exists
11
+
12
+ export interface Error0Input {
13
+ message?: string
14
+ tag?: string
15
+ code?: string
16
+ httpStatus?: HttpStatusCode | HttpStatusCodeString
17
+ expected?: boolean | ExpectedFn
18
+ clientMessage?: string
19
+ cause?: Error0Cause
20
+ stack?: string
21
+ meta?: Meta0.Meta0OrValueTypeNullish
22
+ zodError?: ZodError
23
+ axiosError?: AxiosError
24
+ }
25
+
26
+ interface Error0GeneralProps {
27
+ message: Error0Input['message']
28
+ tag: Error0Input['tag']
29
+ code: Error0Input['code']
30
+ httpStatus: number | undefined
31
+ expected: boolean | undefined
32
+ clientMessage: Error0Input['clientMessage']
33
+ anyMessage: string | undefined
34
+ cause: Error0Input['cause']
35
+ stack: Error['stack']
36
+ meta: Meta0.ValueType
37
+ zodError?: ZodError
38
+ axiosError?: AxiosError
39
+ }
40
+
41
+ type HttpStatusCodeString = keyof typeof HttpStatusCode
42
+ type Error0Cause = Error | Error0 | unknown
43
+ type ExpectedFn = (error: Error0GeneralProps) => boolean | undefined
44
+
45
+ const isFilled = <T>(value: T): value is NonNullable<T> => value !== null && value !== undefined && value !== ''
46
+
47
+ export class Error0 extends Error {
48
+ public readonly __I_AM_ERROR_0: true = true
49
+
50
+ public readonly tag?: Error0GeneralProps['tag']
51
+ public readonly code?: Error0GeneralProps['code']
52
+ public readonly httpStatus?: Error0GeneralProps['httpStatus']
53
+ public readonly expected?: Error0GeneralProps['expected']
54
+ public readonly clientMessage?: Error0GeneralProps['clientMessage']
55
+ public readonly anyMessage?: Error0GeneralProps['anyMessage']
56
+ public override readonly cause?: Error0GeneralProps['cause']
57
+ public readonly meta?: Meta0.Meta0OrValueTypeNullish
58
+ public readonly zodError?: Error0GeneralProps['zodError']
59
+ public readonly axiosError?: Error0GeneralProps['axiosError']
60
+
61
+ static defaultMessage = 'Unknown error'
62
+ static defaultCode?: Error0GeneralProps['code']
63
+ static defaultHttpStatus?: Error0GeneralProps['httpStatus']
64
+ static defaultExpected?: Error0GeneralProps['expected']
65
+ static defaultClientMessage?: Error0GeneralProps['clientMessage']
66
+ static defaultMeta?: Meta0.Meta0OrValueTypeNullish
67
+
68
+ public readonly propsOriginal: Error0GeneralProps
69
+
70
+ constructor(message: string)
71
+ constructor(input: Error0Input)
72
+ constructor(message: string, input: Error0Input)
73
+ constructor(error: Error)
74
+ constructor(error: Error, input: Error0Input)
75
+ constructor(value: unknown)
76
+ constructor(value: unknown, input: Error0Input)
77
+ constructor(...args: unknown[]) {
78
+ const input: Partial<Error0Input> = {}
79
+ if (args[0] instanceof Error) {
80
+ input.cause = args[0]
81
+ } else if (typeof args[0] === 'object' && args[0] !== null) {
82
+ Object.assign(input, args[0])
83
+ } else if (typeof args[0] === 'string') {
84
+ input.message = args[0]
85
+ }
86
+ if (typeof args[1] === 'object' && args[1] !== null) {
87
+ Object.assign(input, args[1])
88
+ }
89
+ const safeInput = Error0._safeParseInput(input)
90
+
91
+ const message = safeInput.message || Error0.defaultMessage
92
+ super(message)
93
+ Object.setPrototypeOf(this, (this.constructor as typeof Error0).prototype)
94
+ this.name = 'Error0'
95
+
96
+ this.propsOriginal = (this.constructor as typeof Error0)._getSelfGeneralProps({
97
+ error0Input: safeInput,
98
+ message,
99
+ stack: safeInput.stack || this.stack,
100
+ })
101
+ const causesProps = (this.constructor as typeof Error0)._getCausesPropsFromError0Props(
102
+ this.propsOriginal,
103
+ (this.constructor as typeof Error0).defaultMaxLevel,
104
+ )
105
+ const propsFloated = (this.constructor as typeof Error0)._getSelfPropsFloated(causesProps)
106
+ this.tag = propsFloated.tag
107
+ this.code = propsFloated.code
108
+ this.httpStatus = propsFloated.httpStatus
109
+ this.expected = propsFloated.expected
110
+ this.clientMessage = propsFloated.clientMessage
111
+ this.cause = propsFloated.cause
112
+ this.stack = propsFloated.stack
113
+ this.meta = propsFloated.meta
114
+ this.zodError = propsFloated.zodError
115
+ this.axiosError = propsFloated.axiosError
116
+ }
117
+
118
+ // settings
119
+
120
+ static defaultMaxLevel = 10
121
+
122
+ // props
123
+
124
+ public static _safeParseInput(error0Input: Record<string, unknown>): Error0Input {
125
+ const result: Error0Input = {}
126
+ result.message = typeof error0Input.message === 'string' ? error0Input.message : undefined
127
+ result.tag = typeof error0Input.tag === 'string' ? error0Input.tag : undefined
128
+ result.code = typeof error0Input.code === 'string' ? error0Input.code : undefined
129
+ result.httpStatus =
130
+ typeof error0Input.httpStatus === 'number' || typeof error0Input.httpStatus === 'string'
131
+ ? (error0Input.httpStatus as never)
132
+ : undefined
133
+ result.expected =
134
+ typeof error0Input.expected === 'function' || typeof error0Input.expected === 'boolean'
135
+ ? (error0Input.expected as never)
136
+ : undefined
137
+ result.clientMessage = typeof error0Input.clientMessage === 'string' ? error0Input.clientMessage : undefined
138
+ result.cause = error0Input.cause
139
+ result.stack = typeof error0Input.stack === 'string' ? error0Input.stack : undefined
140
+ // result.meta0 =
141
+ // error0Input.meta0 instanceof Meta0 ? error0Input.meta0 : undefined
142
+ // result.meta =
143
+ // typeof error0Input.meta === "object" && error0Input.meta !== null
144
+ // ? error0Input.meta
145
+ // : undefined
146
+ result.meta =
147
+ error0Input.meta instanceof Meta0
148
+ ? error0Input.meta
149
+ : typeof error0Input.meta === 'object' && error0Input.meta !== null
150
+ ? (error0Input.meta as Meta0.ValueType)
151
+ : undefined
152
+ result.zodError = error0Input.zodError instanceof ZodError ? error0Input.zodError : undefined
153
+ result.axiosError = isAxiosError(error0Input.axiosError) ? error0Input.axiosError : undefined
154
+ return result
155
+ }
156
+
157
+ public static _getSelfGeneralProps({
158
+ error0Input,
159
+ message,
160
+ stack,
161
+ }: {
162
+ error0Input: Error0Input
163
+ message: string
164
+ stack: Error0GeneralProps['stack']
165
+ }): Error0GeneralProps {
166
+ // const meta = Meta0.merge(error0Input.meta0, error0Input.meta).value
167
+ const meta0 = Meta0.extend(error0Input.meta, this.defaultMeta)
168
+ const meta = meta0.getValue()
169
+ const finalTag = meta0.getFinalTag(error0Input.tag)
170
+ const clientMessage = error0Input.clientMessage || this.defaultClientMessage
171
+ const result: Error0GeneralProps = {
172
+ message: error0Input.message || this.defaultMessage,
173
+ tag: finalTag,
174
+ code: error0Input.code || meta.code || this.defaultCode,
175
+ httpStatus:
176
+ typeof error0Input.httpStatus === 'number'
177
+ ? error0Input.httpStatus
178
+ : error0Input.httpStatus &&
179
+ typeof error0Input.httpStatus === 'string' &&
180
+ error0Input.httpStatus in HttpStatusCode
181
+ ? HttpStatusCode[error0Input.httpStatus]
182
+ : meta.httpStatus || this.defaultHttpStatus,
183
+ expected: undefined,
184
+ clientMessage,
185
+ anyMessage: clientMessage || message,
186
+ cause: error0Input.cause,
187
+ stack: undefined,
188
+ meta,
189
+ zodError: error0Input.zodError,
190
+ axiosError: error0Input.axiosError,
191
+ }
192
+ result.expected = this._normalizeSelfExpected(
193
+ result,
194
+ typeof error0Input.expected === 'boolean' || typeof error0Input.expected === 'function'
195
+ ? error0Input.expected
196
+ : meta.expected || this.defaultExpected,
197
+ )
198
+ result.stack = this._removeConstructorStackPart(stack)
199
+ return result
200
+ }
201
+
202
+ public static _getSelfPropsFloated(causesProps: Error0GeneralProps[]): Error0GeneralProps {
203
+ const cause = this._getClosestPropValue(causesProps, 'cause')
204
+ const stack = this._mergeStack(causesProps[1]?.stack, causesProps[0]?.stack)
205
+ const closestTag = this._getClosestPropValue(causesProps, 'tag')
206
+ const meta = this._getMergedMetaValue(causesProps)
207
+ const tag = Meta0.getFinalTag(meta, closestTag)
208
+ const propsFloated: Error0GeneralProps = {
209
+ message: this._getClosestPropValue(causesProps, 'message'),
210
+ tag,
211
+ code: this._getClosestPropValue(causesProps, 'code'),
212
+ httpStatus: this._getClosestPropValue(causesProps, 'httpStatus'),
213
+ expected: this._isExpected(causesProps),
214
+ clientMessage: this._getClosestPropValue(causesProps, 'clientMessage'),
215
+ cause,
216
+ stack,
217
+ anyMessage: causesProps[0].anyMessage,
218
+ meta,
219
+ zodError: this._getClosestPropValue(causesProps, 'zodError'),
220
+ axiosError: this._getClosestPropValue(causesProps, 'axiosError'),
221
+ }
222
+ return propsFloated
223
+ }
224
+
225
+ // sepcial
226
+
227
+ public static _getExtraError0PropsByZodError(zodError: ZodError): Partial<Error0GeneralProps> {
228
+ return {
229
+ message: `Zod Validation Error: ${zodError.message}`,
230
+ }
231
+ }
232
+
233
+ public static _getExtraError0PropsByAxiosError(axiosError: AxiosError): Partial<Error0GeneralProps> {
234
+ return {
235
+ message: 'Axios Error',
236
+ meta: {
237
+ axiosData: (() => {
238
+ try {
239
+ return JSON.stringify(axiosError.response?.data)
240
+ } catch {
241
+ return undefined
242
+ }
243
+ })(),
244
+ axiosStatus: axiosError.response?.status,
245
+ },
246
+ }
247
+ }
248
+
249
+ public static _assignError0Props(
250
+ error0Props: Error0GeneralProps,
251
+ extraError0Props: Partial<Error0GeneralProps>,
252
+ ): void {
253
+ const metaValue = Meta0.mergeValues(error0Props.meta, extraError0Props.meta)
254
+ Object.assign(error0Props, extraError0Props, { meta: metaValue })
255
+ }
256
+
257
+ // expected
258
+
259
+ public static _normalizeSelfExpected(
260
+ error0Props: Error0GeneralProps,
261
+ expectedProvided: Error0Input['expected'],
262
+ ): boolean | undefined {
263
+ if (typeof expectedProvided === 'function') {
264
+ return expectedProvided(error0Props)
265
+ }
266
+ return expectedProvided
267
+ }
268
+
269
+ public static _isExpected(causesProps: Error0GeneralProps[]): boolean {
270
+ let hasExpectedTrue = false
271
+ for (const causeProps of causesProps) {
272
+ if (causeProps.expected === false) {
273
+ return false
274
+ }
275
+ if (causeProps.expected === true) {
276
+ hasExpectedTrue = true
277
+ }
278
+ }
279
+ return hasExpectedTrue
280
+ }
281
+
282
+ // getters
283
+
284
+ public static _getPropsFromUnknown(error: unknown, defaults?: Error0Input): Error0GeneralProps {
285
+ if (typeof error !== 'object' || error === null) {
286
+ return {
287
+ message: undefined,
288
+ tag: undefined,
289
+ code: undefined,
290
+ httpStatus: undefined,
291
+ expected: undefined,
292
+ clientMessage: undefined,
293
+ anyMessage: this.defaultMessage,
294
+ cause: undefined,
295
+ stack: undefined,
296
+ zodError: undefined,
297
+ axiosError: undefined,
298
+ meta: {},
299
+ }
300
+ }
301
+ const message = 'message' in error && typeof error.message === 'string' ? error.message : undefined
302
+ const clientMessage =
303
+ 'clientMessage' in error && typeof error.clientMessage === 'string'
304
+ ? error.clientMessage
305
+ : defaults?.clientMessage || undefined
306
+ const result: Error0GeneralProps = {
307
+ message,
308
+ code: 'code' in error && typeof error.code === 'string' ? error.code : defaults?.code || undefined,
309
+ clientMessage,
310
+ anyMessage: clientMessage || message || this.defaultMessage,
311
+ expected: undefined,
312
+ stack: 'stack' in error && typeof error.stack === 'string' ? error.stack : undefined,
313
+ tag: 'tag' in error && typeof error.tag === 'string' ? error.tag : defaults?.tag || undefined,
314
+ cause: 'cause' in error ? error.cause : defaults?.cause || undefined,
315
+ meta:
316
+ 'meta' in error && typeof error.meta === 'object' && error.meta !== null
317
+ ? Meta0.getValue(error.meta as Meta0.ValueType)
318
+ : Meta0.getValue(defaults?.meta) || {},
319
+ httpStatus:
320
+ 'httpStatus' in error && typeof error.httpStatus === 'number' && error.httpStatus in HttpStatusCode
321
+ ? error.httpStatus
322
+ : typeof defaults?.httpStatus === 'string'
323
+ ? HttpStatusCode[defaults.httpStatus]
324
+ : defaults?.httpStatus,
325
+ zodError:
326
+ 'zodError' in error && error.zodError instanceof ZodError
327
+ ? error.zodError
328
+ : error instanceof ZodError
329
+ ? error
330
+ : defaults?.zodError,
331
+ axiosError:
332
+ 'axiosError' in error && isAxiosError(error.axiosError)
333
+ ? error.axiosError
334
+ : isAxiosError(error)
335
+ ? error
336
+ : defaults?.axiosError,
337
+ }
338
+ result.expected = this._normalizeSelfExpected(
339
+ result,
340
+ 'expected' in error && (typeof error.expected === 'boolean' || typeof error.expected === 'function')
341
+ ? (error.expected as ExpectedFn)
342
+ : defaults?.expected || undefined,
343
+ )
344
+ if (result.zodError) {
345
+ this._assignError0Props(result, this._getExtraError0PropsByZodError(result.zodError))
346
+ }
347
+ if (result.axiosError) {
348
+ this._assignError0Props(result, this._getExtraError0PropsByAxiosError(result.axiosError))
349
+ }
350
+ return result
351
+ }
352
+
353
+ public static _getCausesPropsFromUnknown(error: unknown, maxLevel: number): Error0GeneralProps[] {
354
+ if (!error) {
355
+ return []
356
+ }
357
+ const causeProps = this._getPropsFromUnknown(error)
358
+ const causesProps: Error0GeneralProps[] = [causeProps]
359
+ if (!causeProps.cause) {
360
+ return causesProps
361
+ }
362
+ if (maxLevel > 0) {
363
+ causesProps.push(...this._getCausesPropsFromUnknown(this._getPropsFromUnknown(causeProps.cause), maxLevel - 1))
364
+ }
365
+ return causesProps
366
+ }
367
+
368
+ public static _getCausesPropsFromError0Props(
369
+ error0Props: Error0GeneralProps,
370
+ maxLevel: number,
371
+ ): Error0GeneralProps[] {
372
+ return [error0Props, ...this._getCausesPropsFromUnknown(error0Props.cause, maxLevel - 1)]
373
+ }
374
+
375
+ public static _getClosestPropValue<TPropKey extends keyof Error0GeneralProps>(
376
+ causesProps: Error0GeneralProps[],
377
+ propKey: TPropKey,
378
+ ): NonNullable<Error0GeneralProps[TPropKey]> | undefined {
379
+ for (const causeProps of causesProps) {
380
+ const propValue = causeProps[propKey]
381
+ if (isFilled(propValue)) {
382
+ return propValue as NonNullable<Error0GeneralProps[TPropKey]>
383
+ }
384
+ }
385
+ return undefined
386
+ }
387
+
388
+ // private static getClosestByGetter<TResult>(
389
+ // causesProps: Error0GeneralProps[],
390
+ // getter: (props: Error0GeneralProps) => TResult,
391
+ // ): NonNullable<TResult> | undefined {
392
+ // for (const causeProps of causesProps) {
393
+ // const result = getter(causeProps)
394
+ // if (isFilled(result)) {
395
+ // return result
396
+ // }
397
+ // }
398
+ // return undefined
399
+ // }
400
+
401
+ public static _getFilledPropValues<TPropKey extends keyof Error0Input>(
402
+ causesProps: Error0GeneralProps[],
403
+ propKey: TPropKey,
404
+ ): NonNullable<Error0GeneralProps[TPropKey]>[] {
405
+ const values: NonNullable<Error0GeneralProps[TPropKey]>[] = []
406
+ for (const causeProps of causesProps) {
407
+ const propValue = causeProps[propKey]
408
+ if (isFilled(propValue)) {
409
+ values.push(propValue as NonNullable<Error0GeneralProps[TPropKey]>)
410
+ }
411
+ }
412
+ return values
413
+ }
414
+
415
+ public static _getMergedMetaValue(causesProps: Error0GeneralProps[]): Meta0.ValueType {
416
+ const metas = this._getFilledPropValues(causesProps, 'meta')
417
+ if (metas.length === 0) {
418
+ return {}
419
+ } else if (metas.length === 1) {
420
+ return metas[0]
421
+ } else {
422
+ return Meta0.mergeValues(metas[0], ...metas.slice(1))
423
+ }
424
+ }
425
+
426
+ // stack
427
+
428
+ public static _removeConstructorStackPart(stack: Error0GeneralProps['stack']): Error0GeneralProps['stack'] {
429
+ if (!stack) {
430
+ return stack
431
+ }
432
+ let lines = stack.split('\n')
433
+ const removeAllLinesContains = (search: string) => {
434
+ lines = lines.filter((line) => !line.includes(search))
435
+ }
436
+ removeAllLinesContains('at new Error0')
437
+ removeAllLinesContains('at _toError0')
438
+ removeAllLinesContains('at Error0.from')
439
+ removeAllLinesContains('at Error0._toError0')
440
+ return lines.join('\n')
441
+ }
442
+
443
+ public static _mergeStack(
444
+ prevStack: Error0GeneralProps['stack'],
445
+ nextStack: Error0GeneralProps['stack'],
446
+ ): Error0GeneralProps['stack'] {
447
+ return [nextStack, prevStack].filter(Boolean).join('\n\n') || undefined
448
+ }
449
+
450
+ // transformations
451
+
452
+ static isError0(error: unknown): error is Error0 {
453
+ return error instanceof Error0
454
+ }
455
+
456
+ static isLikelyError0(error: unknown): error is Error0 {
457
+ if (error instanceof Error0) {
458
+ return true
459
+ }
460
+
461
+ if (typeof error === 'object' && error !== null) {
462
+ if ('__I_AM_ERROR_0' in error && error.__I_AM_ERROR_0 === true) {
463
+ return true
464
+ }
465
+ }
466
+
467
+ return false
468
+ }
469
+
470
+ public static _toError0(error: unknown, inputOverride: Error0Input = {}): Error0 {
471
+ if (error instanceof Error0) {
472
+ return error
473
+ }
474
+
475
+ if (typeof error === 'string') {
476
+ return new Error0(error, inputOverride)
477
+ }
478
+
479
+ if (typeof error !== 'object' || error === null) {
480
+ return new Error0({
481
+ message: this.defaultMessage,
482
+ ...inputOverride,
483
+ })
484
+ }
485
+
486
+ const inputFromData = get(error, 'data')
487
+ if (inputFromData) {
488
+ if (Error0.isLikelyError0(inputFromData)) {
489
+ return this._toError0(inputFromData, inputOverride)
490
+ }
491
+ }
492
+
493
+ const inputFromDataError0 = get(error, 'data.error0')
494
+ if (inputFromDataError0) {
495
+ if (Error0.isLikelyError0(inputFromDataError0)) {
496
+ return this._toError0(inputFromDataError0, inputOverride)
497
+ }
498
+ }
499
+
500
+ return new Error0(this._getPropsFromUnknown(error, inputOverride))
501
+ }
502
+
503
+ static from(error: unknown, inputOverride?: Error0Input): Error0 {
504
+ return this._toError0(error, inputOverride)
505
+ }
506
+
507
+ static extend(props: {
508
+ defaultMessage?: Error0GeneralProps['message']
509
+ defaultCode?: Error0GeneralProps['code']
510
+ defaultHttpStatus?: Error0GeneralProps['httpStatus']
511
+ defaultExpected?: Error0GeneralProps['expected']
512
+ defaultClientMessage?: Error0GeneralProps['clientMessage']
513
+ defaultMeta?: Meta0.Meta0OrValueTypeNullish
514
+ }) {
515
+ const parent = this
516
+ return class Error0 extends parent {
517
+ static override defaultMessage = props.defaultMessage ?? parent.defaultMessage
518
+ static override defaultCode = props.defaultCode ?? parent.defaultCode
519
+ static override defaultHttpStatus = props.defaultHttpStatus ?? parent.defaultHttpStatus
520
+ static override defaultExpected = props.defaultExpected ?? parent.defaultExpected
521
+ static override defaultClientMessage = props.defaultClientMessage ?? parent.defaultClientMessage
522
+ static override defaultMeta = Meta0.extend(props.defaultMeta, parent.defaultMeta)
523
+ }
524
+ }
525
+
526
+ static extendCollection<T extends Record<string, typeof Error0>>(
527
+ classes: T,
528
+ props: {
529
+ defaultMessage?: Error0GeneralProps['message']
530
+ defaultCode?: Error0GeneralProps['code']
531
+ defaultHttpStatus?: Error0GeneralProps['httpStatus']
532
+ defaultExpected?: Error0GeneralProps['expected']
533
+ defaultClientMessage?: Error0GeneralProps['clientMessage']
534
+ defaultMeta?: Meta0.Meta0OrValueTypeNullish
535
+ },
536
+ ): T {
537
+ return Object.fromEntries(Object.entries(classes).map(([name, Class]) => [name, Class.extend(props)])) as T
538
+ }
539
+
540
+ toJSON() {
541
+ return {
542
+ message: this.message,
543
+ tag: this.tag,
544
+ code: this.code,
545
+ httpStatus: this.httpStatus,
546
+ expected: this.expected,
547
+ clientMessage: this.clientMessage,
548
+ anyMessage: this.anyMessage,
549
+ cause: this.cause,
550
+ meta: Meta0.getValue(this.meta),
551
+ stack: this.stack,
552
+ __I_AM_ERROR_0: this.__I_AM_ERROR_0,
553
+ }
554
+ }
555
+ static toJSON(error: unknown, inputOverride?: Error0Input) {
556
+ const error0 = this.from(error, inputOverride)
557
+ return error0.toJSON()
558
+ }
559
+
560
+ toResponse(data?: Record<string, unknown>) {
561
+ return Response.json(
562
+ {
563
+ ...this.toJSON(),
564
+ ...data,
565
+ },
566
+ {
567
+ status: this.httpStatus,
568
+ statusText: this.message,
569
+ },
570
+ )
571
+ }
572
+ }
573
+
574
+ export namespace Error0 {
575
+ export type JSON = ReturnType<Error0['toJSON']>
576
+ export type Collection = Record<string, typeof Error0>
577
+ }
578
+
579
+ export const e0s = {
580
+ Default: Error0,
581
+ Expected: Error0.extend({
582
+ defaultExpected: true,
583
+ }),
584
+ } satisfies Error0.Collection