@devp0nt/error0 1.0.0-next.48 → 1.0.0-next.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +158 -85
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +44 -16
- package/dist/cjs/plugins/cause-serialize.cjs +4 -1
- package/dist/cjs/plugins/cause-serialize.cjs.map +1 -1
- package/dist/cjs/plugins/cause-serialize.d.cts +3 -1
- package/dist/cjs/plugins/expected.cjs +7 -2
- package/dist/cjs/plugins/expected.cjs.map +1 -1
- package/dist/cjs/plugins/expected.d.cts +3 -1
- package/dist/cjs/plugins/message-merge.cjs +5 -2
- package/dist/cjs/plugins/message-merge.cjs.map +1 -1
- package/dist/cjs/plugins/message-merge.d.cts +4 -1
- package/dist/cjs/plugins/meta.cjs +7 -2
- package/dist/cjs/plugins/meta.cjs.map +1 -1
- package/dist/cjs/plugins/meta.d.cts +3 -1
- package/dist/cjs/plugins/stack-merge.cjs +6 -3
- package/dist/cjs/plugins/stack-merge.cjs.map +1 -1
- package/dist/cjs/plugins/stack-merge.d.cts +4 -1
- package/dist/cjs/plugins/tags.cjs +7 -2
- package/dist/cjs/plugins/tags.cjs.map +1 -1
- package/dist/cjs/plugins/tags.d.cts +3 -1
- package/dist/esm/index.d.ts +44 -16
- package/dist/esm/index.js +158 -85
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/plugins/cause-serialize.d.ts +3 -1
- package/dist/esm/plugins/cause-serialize.js +4 -1
- package/dist/esm/plugins/cause-serialize.js.map +1 -1
- package/dist/esm/plugins/expected.d.ts +3 -1
- package/dist/esm/plugins/expected.js +7 -2
- package/dist/esm/plugins/expected.js.map +1 -1
- package/dist/esm/plugins/message-merge.d.ts +4 -1
- package/dist/esm/plugins/message-merge.js +5 -2
- package/dist/esm/plugins/message-merge.js.map +1 -1
- package/dist/esm/plugins/meta.d.ts +3 -1
- package/dist/esm/plugins/meta.js +7 -2
- package/dist/esm/plugins/meta.js.map +1 -1
- package/dist/esm/plugins/stack-merge.d.ts +4 -1
- package/dist/esm/plugins/stack-merge.js +6 -3
- package/dist/esm/plugins/stack-merge.js.map +1 -1
- package/dist/esm/plugins/tags.d.ts +3 -1
- package/dist/esm/plugins/tags.js +7 -2
- package/dist/esm/plugins/tags.js.map +1 -1
- package/package.json +1 -1
- package/src/index.test.ts +79 -21
- package/src/index.ts +216 -101
- package/src/plugins/cause-serialize.test.ts +6 -4
- package/src/plugins/cause-serialize.ts +13 -9
- package/src/plugins/expected.test.ts +4 -4
- package/src/plugins/expected.ts +16 -10
- package/src/plugins/message-merge.test.ts +3 -3
- package/src/plugins/message-merge.ts +17 -13
- package/src/plugins/meta.test.ts +2 -2
- package/src/plugins/meta.ts +28 -22
- package/src/plugins/stack-merge.test.ts +4 -4
- package/src/plugins/stack-merge.ts +18 -14
- package/src/plugins/tags.test.ts +2 -2
- package/src/plugins/tags.ts +24 -18
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { Error0 } from '../index.js'
|
|
2
2
|
|
|
3
|
-
export const messageMergePlugin =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
export const messageMergePlugin = ({
|
|
4
|
+
delimiter = ': ',
|
|
5
|
+
fallback = 'Unknown error',
|
|
6
|
+
}: { delimiter?: string; fallback?: string } = {}) =>
|
|
7
|
+
Error0.plugin().use('message', {
|
|
8
|
+
serialize: ({ error }) => {
|
|
9
|
+
return (
|
|
10
|
+
error
|
|
11
|
+
.causes()
|
|
12
|
+
.map((cause) => {
|
|
13
|
+
return cause instanceof Error ? cause.message : undefined
|
|
14
|
+
})
|
|
15
|
+
.filter((value): value is string => typeof value === 'string')
|
|
16
|
+
.join(delimiter) || fallback
|
|
17
|
+
)
|
|
18
|
+
},
|
|
19
|
+
})
|
package/src/plugins/meta.test.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { metaPlugin } from './meta.js'
|
|
|
4
4
|
|
|
5
5
|
describe('metaPlugin', () => {
|
|
6
6
|
it('merges meta across causes into current error', () => {
|
|
7
|
-
const AppError = Error0.use(metaPlugin)
|
|
7
|
+
const AppError = Error0.use(metaPlugin())
|
|
8
8
|
const root = new AppError('root', { meta: { requestId: 'r1', source: 'db' } })
|
|
9
9
|
const leaf = new AppError('leaf', { meta: { route: '/ideas', source: 'api' }, cause: root })
|
|
10
10
|
expect(leaf.resolve().meta).toEqual({
|
|
@@ -15,7 +15,7 @@ describe('metaPlugin', () => {
|
|
|
15
15
|
})
|
|
16
16
|
|
|
17
17
|
it('serializes meta only for private output and keeps json-safe values', () => {
|
|
18
|
-
const AppError = Error0.use(metaPlugin)
|
|
18
|
+
const AppError = Error0.use(metaPlugin())
|
|
19
19
|
const error = new AppError('test', {
|
|
20
20
|
meta: {
|
|
21
21
|
ok: true,
|
package/src/plugins/meta.ts
CHANGED
|
@@ -28,26 +28,32 @@ const toJsonSafe = (input: unknown): Json | undefined => {
|
|
|
28
28
|
const isMetaRecord = (value: unknown): value is Record<string, unknown> =>
|
|
29
29
|
typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
30
30
|
|
|
31
|
-
export const metaPlugin =
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
export const metaPlugin = ({ hideWhenPublic = true }: { hideWhenPublic?: boolean } = {}) =>
|
|
32
|
+
Error0.plugin().use('prop', 'meta', {
|
|
33
|
+
init: (input: Record<string, unknown>) => input,
|
|
34
|
+
resolve: ({ flow }) => {
|
|
35
|
+
const values = flow.filter(isMetaRecord)
|
|
36
|
+
if (values.length === 0) {
|
|
37
|
+
return undefined
|
|
38
|
+
}
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
40
|
+
// Merge cause meta into the current error; nearer errors win on conflicts.
|
|
41
|
+
const merged: Record<string, unknown> = {}
|
|
42
|
+
for (const value of [...values].reverse()) {
|
|
43
|
+
Object.assign(merged, value)
|
|
44
|
+
}
|
|
45
|
+
return merged
|
|
46
|
+
},
|
|
47
|
+
serialize: ({ resolved, isPublic }) => {
|
|
48
|
+
if (hideWhenPublic && isPublic) {
|
|
49
|
+
return undefined
|
|
50
|
+
}
|
|
51
|
+
return toJsonSafe(resolved)
|
|
52
|
+
},
|
|
53
|
+
deserialize: ({ value }) => {
|
|
54
|
+
if (!isMetaRecord(value)) {
|
|
55
|
+
return undefined
|
|
56
|
+
}
|
|
57
|
+
return value
|
|
58
|
+
},
|
|
59
|
+
})
|
|
@@ -18,7 +18,7 @@ describe('stackMergePlugin', () => {
|
|
|
18
18
|
const statusPlugin = Error0.plugin().use('prop', 'status', {
|
|
19
19
|
init: (input: number) => input,
|
|
20
20
|
resolve: ({ flow }) => flow.find((value) => typeof value === 'number'),
|
|
21
|
-
serialize: ({
|
|
21
|
+
serialize: ({ resolved }) => resolved,
|
|
22
22
|
deserialize: ({ value }) => (typeof value === 'number' ? value : undefined),
|
|
23
23
|
})
|
|
24
24
|
|
|
@@ -27,13 +27,13 @@ describe('stackMergePlugin', () => {
|
|
|
27
27
|
const codePlugin = Error0.plugin().use('prop', 'code', {
|
|
28
28
|
init: (input: Code) => input,
|
|
29
29
|
resolve: ({ flow }) => flow.find((value) => typeof value === 'string' && codes.includes(value)),
|
|
30
|
-
serialize: ({
|
|
30
|
+
serialize: ({ resolved, isPublic }) => (isPublic ? undefined : resolved),
|
|
31
31
|
deserialize: ({ value }) =>
|
|
32
32
|
typeof value === 'string' && codes.includes(value as Code) ? (value as Code) : undefined,
|
|
33
33
|
})
|
|
34
34
|
|
|
35
35
|
it('can merge stack across causes in one serialized value', () => {
|
|
36
|
-
const AppError = Error0.use(statusPlugin).use(codePlugin).use(stackMergePlugin)
|
|
36
|
+
const AppError = Error0.use(statusPlugin).use(codePlugin).use(stackMergePlugin())
|
|
37
37
|
const error1 = new AppError('test1', { status: 400, code: 'NOT_FOUND' })
|
|
38
38
|
const error2 = new AppError('test2', { status: 401, cause: error1 })
|
|
39
39
|
const mergedStack1 = error1.serialize(false).stack as string
|
|
@@ -56,7 +56,7 @@ describe('stackMergePlugin', () => {
|
|
|
56
56
|
})
|
|
57
57
|
|
|
58
58
|
it('by default serializes stack of this error only', () => {
|
|
59
|
-
const AppError = Error0.use(statusPlugin).use(codePlugin).use(stackMergePlugin)
|
|
59
|
+
const AppError = Error0.use(statusPlugin).use(codePlugin).use(stackMergePlugin())
|
|
60
60
|
const error = new AppError('test', { status: 400, code: 'NOT_FOUND' })
|
|
61
61
|
const json = AppError.serialize(error, false)
|
|
62
62
|
expect(json.stack).toBe(error.stack)
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { Error0 } from '../index.js'
|
|
2
2
|
|
|
3
|
-
export const stackMergePlugin =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
})
|
|
3
|
+
export const stackMergePlugin = ({
|
|
4
|
+
hideWhenPublic = true,
|
|
5
|
+
delimiter = '\n',
|
|
6
|
+
}: { hideWhenPublic?: boolean; delimiter?: string } = {}) =>
|
|
7
|
+
Error0.plugin().use('stack', {
|
|
8
|
+
serialize: ({ error, isPublic }) => {
|
|
9
|
+
if (hideWhenPublic && isPublic) {
|
|
10
|
+
return undefined
|
|
11
|
+
}
|
|
12
|
+
return error
|
|
13
|
+
.causes()
|
|
14
|
+
.map((cause) => {
|
|
15
|
+
return cause instanceof Error ? cause.stack : undefined
|
|
16
|
+
})
|
|
17
|
+
.filter((value): value is string => typeof value === 'string')
|
|
18
|
+
.join(delimiter)
|
|
19
|
+
},
|
|
20
|
+
})
|
package/src/plugins/tags.test.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { tagsPlugin } from './tags.js'
|
|
|
4
4
|
|
|
5
5
|
describe('tagsPlugin', () => {
|
|
6
6
|
it('merges and deduplicates tags across causes', () => {
|
|
7
|
-
const AppError = Error0.use(tagsPlugin)
|
|
7
|
+
const AppError = Error0.use(tagsPlugin())
|
|
8
8
|
const root = new AppError('root', { tags: ['db', 'retry'] })
|
|
9
9
|
const leaf = new AppError('leaf', { tags: ['api', 'retry'], cause: root })
|
|
10
10
|
expect(leaf.resolve().tags).toEqual(['api', 'retry', 'db'])
|
|
@@ -14,7 +14,7 @@ describe('tagsPlugin', () => {
|
|
|
14
14
|
})
|
|
15
15
|
|
|
16
16
|
it('serializes tags only for private output', () => {
|
|
17
|
-
const AppError = Error0.use(tagsPlugin)
|
|
17
|
+
const AppError = Error0.use(tagsPlugin())
|
|
18
18
|
const error = new AppError('test', { tags: ['internal'] })
|
|
19
19
|
expect(AppError.serialize(error, false).tags).toEqual(['internal'])
|
|
20
20
|
expect('tags' in AppError.serialize(error, true)).toBe(false)
|
package/src/plugins/tags.ts
CHANGED
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
import { Error0 } from '../index.js'
|
|
2
2
|
|
|
3
|
-
export const tagsPlugin =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
export const tagsPlugin = ({ hideWhenPublic = true }: { hideWhenPublic?: boolean } = {}) =>
|
|
4
|
+
Error0.plugin().use('prop', 'tags', {
|
|
5
|
+
init: (input: string[]) => input,
|
|
6
|
+
resolve: ({ flow }) => {
|
|
7
|
+
const merged: string[] = []
|
|
8
|
+
for (const value of flow) {
|
|
9
|
+
if (Array.isArray(value)) {
|
|
10
|
+
merged.push(...value.filter((item): item is string => typeof item === 'string'))
|
|
11
|
+
}
|
|
10
12
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
return merged.length > 0 ? Array.from(new Set(merged)) : undefined
|
|
14
|
+
},
|
|
15
|
+
serialize: ({ resolved, isPublic }) => {
|
|
16
|
+
if (hideWhenPublic && isPublic) {
|
|
17
|
+
return undefined
|
|
18
|
+
}
|
|
19
|
+
return resolved
|
|
20
|
+
},
|
|
21
|
+
deserialize: ({ value }) => {
|
|
22
|
+
if (!Array.isArray(value)) {
|
|
23
|
+
return undefined
|
|
24
|
+
}
|
|
25
|
+
return value.filter((item): item is string => typeof item === 'string')
|
|
26
|
+
},
|
|
27
|
+
})
|