@emoyly/problem 7.0.4 → 7.0.5
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/README.md +4 -1
- package/SECURITY.md +2 -2
- package/cjs/middleware/base.js +10 -20
- package/cjs/parsers/jsonwebtoken.js +6 -2
- package/cjs/parsers/mikroorm.js +1 -1
- package/cjs/parsers/tsoa.js +2 -1
- package/cjs/parsers/zod.d.ts +3 -0
- package/cjs/parsers/zod.js +19 -0
- package/cjs/tsconfig.tsbuildinfo +1 -1
- package/cjs/typings/parser.d.ts +1 -1
- package/cjs/util/getProblems.d.ts +7 -1
- package/cjs/util/getProblems.js +19 -6
- package/cjs/util/index.d.ts +1 -1
- package/cjs/util/index.js +1 -1
- package/cjs/util/problemArray.d.ts +7 -0
- package/cjs/util/problemArray.js +21 -0
- package/cjs/util/version.d.ts +1 -1
- package/cjs/util/version.js +1 -1
- package/esm/middleware/base.js +10 -20
- package/esm/parsers/jsonwebtoken.js +6 -2
- package/esm/parsers/mikroorm.js +1 -1
- package/esm/parsers/tsoa.js +2 -1
- package/esm/parsers/zod.d.ts +3 -0
- package/esm/parsers/zod.js +17 -0
- package/esm/tsconfig.tsbuildinfo +1 -1
- package/esm/typings/parser.d.ts +1 -1
- package/esm/util/getProblems.d.ts +7 -1
- package/esm/util/getProblems.js +19 -6
- package/esm/util/index.d.ts +1 -1
- package/esm/util/index.js +1 -1
- package/esm/util/problemArray.d.ts +7 -0
- package/esm/util/problemArray.js +18 -0
- package/esm/util/version.d.ts +1 -1
- package/esm/util/version.js +1 -1
- package/package.json +28 -17
- package/scripts/ensureCorrectVersion.js +1 -1
- package/src/middleware/base.ts +9 -21
- package/src/parsers/axios.ts +0 -1
- package/src/parsers/jsonwebtoken.ts +6 -3
- package/src/parsers/mikroorm.ts +1 -1
- package/src/parsers/tsoa.ts +2 -1
- package/src/parsers/zod.ts +21 -0
- package/src/typings/parser.ts +1 -1
- package/src/util/getProblems.ts +21 -8
- package/src/util/index.ts +1 -1
- package/src/util/misc.ts +1 -0
- package/src/util/problemArray.ts +21 -0
- package/src/util/version.ts +1 -1
- package/cjs/util/isProblemArray.d.ts +0 -2
- package/cjs/util/isProblemArray.js +0 -9
- package/esm/util/isProblemArray.d.ts +0 -2
- package/esm/util/isProblemArray.js +0 -6
- package/src/util/isProblemArray.ts +0 -6
package/esm/util/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emoyly/problem",
|
|
3
|
-
"version": "7.0.
|
|
4
|
-
"description": "A simple error library based around the RFC-7807 standard with optional support for
|
|
3
|
+
"version": "7.0.5",
|
|
4
|
+
"description": "A simple error library based around the RFC-7807 standard with optional support for different parsers and middleware.",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"repository": "https://github.com/emoyly/problem",
|
|
7
7
|
"author": "Emil Petersen <emoyly@gmail.com>",
|
|
@@ -9,29 +9,33 @@
|
|
|
9
9
|
"type": "module",
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "yarn dualBuild",
|
|
12
|
-
"lint": "eslint src",
|
|
12
|
+
"lint": "eslint src && node ./scripts/ensureCorrectVersion.js",
|
|
13
13
|
"publish": "yarn npm publish --access public --tolerate-republish"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"@emoyly/devutils": "^1.0.
|
|
17
|
-
"@emoyly/eslint-config": "^1.
|
|
18
|
-
"@emoyly/utils": "^1.0.
|
|
19
|
-
"@mikro-orm/core": "^6.
|
|
20
|
-
"@
|
|
21
|
-
"@
|
|
22
|
-
"@types/
|
|
23
|
-
"
|
|
24
|
-
"
|
|
16
|
+
"@emoyly/devutils": "^1.0.5",
|
|
17
|
+
"@emoyly/eslint-config": "^1.1.2",
|
|
18
|
+
"@emoyly/utils": "^1.0.4",
|
|
19
|
+
"@mikro-orm/core": "^6.4.0",
|
|
20
|
+
"@stylistic/eslint-plugin-js": "^2.11.0",
|
|
21
|
+
"@stylistic/eslint-plugin-ts": "^2.11.0",
|
|
22
|
+
"@types/express": "^5.0.0",
|
|
23
|
+
"@types/jsonwebtoken": "^9.0.7",
|
|
24
|
+
"@types/node": "^22.10.1",
|
|
25
|
+
"axios": "^1.7.8",
|
|
26
|
+
"eslint": "^9.16.0",
|
|
25
27
|
"jsonwebtoken": "^9.0.2",
|
|
26
|
-
"tsoa": "^6.
|
|
27
|
-
"typescript": "^5.
|
|
28
|
-
"typescript-eslint": "^
|
|
28
|
+
"tsoa": "^6.5.1",
|
|
29
|
+
"typescript": "^5.7.2",
|
|
30
|
+
"typescript-eslint": "^8.17.0",
|
|
31
|
+
"zod": "^3.23.8"
|
|
29
32
|
},
|
|
30
33
|
"peerDependencies": {
|
|
31
34
|
"@mikro-orm/core": "*",
|
|
32
35
|
"axios": "*",
|
|
33
36
|
"jsonwebtoken": "*",
|
|
34
|
-
"tsoa": "*"
|
|
37
|
+
"tsoa": "*",
|
|
38
|
+
"zod": "*"
|
|
35
39
|
},
|
|
36
40
|
"peerDependenciesMeta": {
|
|
37
41
|
"@mikro-orm/core": {
|
|
@@ -45,9 +49,12 @@
|
|
|
45
49
|
},
|
|
46
50
|
"tsoa": {
|
|
47
51
|
"optional": true
|
|
52
|
+
},
|
|
53
|
+
"zod": {
|
|
54
|
+
"optional": true
|
|
48
55
|
}
|
|
49
56
|
},
|
|
50
|
-
"packageManager": "yarn@4.3
|
|
57
|
+
"packageManager": "yarn@4.5.3",
|
|
51
58
|
"publishConfig": {
|
|
52
59
|
"access": "public",
|
|
53
60
|
"registry": "https://registry.npmjs.org"
|
|
@@ -84,6 +91,10 @@
|
|
|
84
91
|
"./parsers/tsoa": {
|
|
85
92
|
"import": "./esm/parsers/tsoa.js",
|
|
86
93
|
"require": "./cjs/parsers/tsoa.js"
|
|
94
|
+
},
|
|
95
|
+
"./parsers/zod": {
|
|
96
|
+
"import": "./esm/parsers/zod.js",
|
|
97
|
+
"require": "./cjs/parsers/zod.js"
|
|
87
98
|
}
|
|
88
99
|
}
|
|
89
100
|
}
|
|
@@ -17,4 +17,4 @@ if (match[0] !== version){
|
|
|
17
17
|
throw new Error(`Version in version.ts (${match[0]}) does not match package.json (${version})`)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
console.log(`Version in version.ts matches package.json: ${version}`)
|
|
20
|
+
//console.log(`Version in version.ts matches package.json: ${version}`)
|
package/src/middleware/base.ts
CHANGED
|
@@ -28,29 +28,17 @@ export abstract class MiddlewareBase {
|
|
|
28
28
|
* Parse input using parsers
|
|
29
29
|
*/
|
|
30
30
|
parse = async (input: unknown): Promise<Problem[]> => {
|
|
31
|
-
const problems
|
|
31
|
+
const problems = getProblems(input, this.options.parsers)
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
if (!problems || !Array.isArray(problems) || problems.length < 1) {
|
|
34
|
+
if (this.enableFallback) return [new Problem({
|
|
35
|
+
...this.fallback,
|
|
36
|
+
'errorObject': input,
|
|
37
|
+
'stack': (typeof input === 'object' && input !== null && 'stack' in input && typeof input.stack === 'string') ? input.stack : undefined,
|
|
38
|
+
'middleware': this.name
|
|
39
|
+
})]
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
for (const parse of this.options.parsers) {
|
|
37
|
-
const resp = parse(input)
|
|
38
|
-
|
|
39
|
-
if (!resp.length) continue
|
|
40
|
-
|
|
41
|
-
problems.push(...resp)
|
|
42
|
-
break
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (!problems.length && this.enableFallback) {
|
|
46
|
-
problems.push(new Problem({
|
|
47
|
-
...this.fallback,
|
|
48
|
-
'errorObject': input,
|
|
49
|
-
'stack': (typeof input === 'object' && input !== null && 'stack' in input && typeof input.stack === 'string') ? input.stack : undefined
|
|
50
|
-
}))
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
problems.push(...prob)
|
|
41
|
+
return []
|
|
54
42
|
}
|
|
55
43
|
|
|
56
44
|
for (const p of problems) {
|
package/src/parsers/axios.ts
CHANGED
|
@@ -9,7 +9,6 @@ function isAxiosError<T = unknown, D = unknown>(payload: unknown): payload is Ax
|
|
|
9
9
|
return typeof payload === 'object' && payload !== null && 'isAxiosError' in payload && payload.isAxiosError === true
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
13
12
|
const parse: Parser = (input) => {
|
|
14
13
|
if (typeof input !== 'object' || input == null) return []
|
|
15
14
|
if (!isAxiosError(input)) return []
|
|
@@ -80,7 +80,10 @@ const parse: Parser = (input) => {
|
|
|
80
80
|
const found = errorMap.find(val => typeof val.search === 'string' ? val.search === input.message : val.search.test(input.message))
|
|
81
81
|
|
|
82
82
|
if (found) {
|
|
83
|
-
return [new Problem(
|
|
83
|
+
return [new Problem({
|
|
84
|
+
...found.result,
|
|
85
|
+
'errorObject': input,
|
|
86
|
+
})]
|
|
84
87
|
}
|
|
85
88
|
} else if (input instanceof TokenExpiredError && input.name === 'TokenExpiredError') {
|
|
86
89
|
return [new Problem({
|
|
@@ -88,6 +91,7 @@ const parse: Parser = (input) => {
|
|
|
88
91
|
'type': '/errors/jsonwebtoken/tokenexpired',
|
|
89
92
|
'detail': `The JSON Web Token expired at ${input.expiredAt}`,
|
|
90
93
|
'status': 400,
|
|
94
|
+
'errorObject': input,
|
|
91
95
|
})]
|
|
92
96
|
} else if (input instanceof NotBeforeError && input.name === 'NotBeforeError') {
|
|
93
97
|
return [new Problem({
|
|
@@ -95,10 +99,9 @@ const parse: Parser = (input) => {
|
|
|
95
99
|
'type': '/errors/jsonwebtoken/notbefore',
|
|
96
100
|
'detail': `The JSON Web Token is not valid before ${input.date}`,
|
|
97
101
|
'status': 400,
|
|
102
|
+
'errorObject': input,
|
|
98
103
|
})]
|
|
99
104
|
}
|
|
100
|
-
|
|
101
|
-
return []
|
|
102
105
|
}
|
|
103
106
|
|
|
104
107
|
export default parse
|
package/src/parsers/mikroorm.ts
CHANGED
package/src/parsers/tsoa.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { Parser } from '../typings/parser.js'
|
|
|
5
5
|
|
|
6
6
|
const parse: Parser = (input) => {
|
|
7
7
|
if (!(input instanceof ValidateError)) {
|
|
8
|
-
return
|
|
8
|
+
return
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
// TODO: Give actual useful responses instead of this shit
|
|
@@ -18,6 +18,7 @@ const parse: Parser = (input) => {
|
|
|
18
18
|
'fields': input.fields,
|
|
19
19
|
},
|
|
20
20
|
'stack': input.stack,
|
|
21
|
+
'errorObject': input
|
|
21
22
|
})
|
|
22
23
|
]
|
|
23
24
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ZodError } from 'zod'
|
|
2
|
+
import type { Parser } from '../typings/parser.js'
|
|
3
|
+
import { Problem } from '../problem.js'
|
|
4
|
+
import { otherErrors } from '../defaults/others.js'
|
|
5
|
+
|
|
6
|
+
const parse: Parser = (input) => {
|
|
7
|
+
if (!(input instanceof ZodError)) {
|
|
8
|
+
return
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return [new Problem({
|
|
12
|
+
...otherErrors.inputValidationError,
|
|
13
|
+
'detail': input.message,
|
|
14
|
+
'status': 400,
|
|
15
|
+
'stack': input.stack,
|
|
16
|
+
'errorObject': input,
|
|
17
|
+
'data': input.issues
|
|
18
|
+
})]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default parse
|
package/src/typings/parser.ts
CHANGED
package/src/util/getProblems.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Problem } from '../problem.js'
|
|
2
|
+
import { Parser } from '../typings/parser.js'
|
|
2
3
|
import type { JsonProblem } from '../typings/problem.js'
|
|
3
|
-
import { isProblemArray } from './
|
|
4
|
+
import { isProblemArray } from './problemArray.js'
|
|
4
5
|
import { isCompatibleVersion } from './version.js'
|
|
5
6
|
|
|
6
|
-
const strings = ['title', 'type', 'instance', 'detail', '__problemVersion']
|
|
7
|
+
const strings = ['title', 'type', 'instance', 'detail', '__problemVersion'] as const
|
|
7
8
|
export function isJsonProblem(input: unknown): input is JsonProblem {
|
|
8
9
|
if (input === null) return false
|
|
9
10
|
if (typeof input !== 'object') return false
|
|
@@ -20,24 +21,36 @@ export function createFromJson({ title, type, instance, detail, status, data }:
|
|
|
20
21
|
return new Problem({ title, type, instance, detail, status, data })
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Get an array of Problems from a given input.
|
|
26
|
+
* Handles existing Problems, arrays of Problems, JSON Problems, JSON Problem arrays and optionally attempts to parse any input with the given parsers.
|
|
27
|
+
* Only returns an array of Problems if it can successfully parse the input.
|
|
28
|
+
*/
|
|
29
|
+
export function getProblems(input: unknown, parsers?: Parser[]): Problem[] | undefined {
|
|
24
30
|
if (typeof input === 'string') {
|
|
25
31
|
try {
|
|
26
32
|
const p = JSON.parse(input)
|
|
27
33
|
input = p
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
28
35
|
} catch (err) { /**/ }
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
if (input instanceof Problem) return [input]
|
|
32
|
-
if (isProblemArray(input)) return input
|
|
39
|
+
if (isProblemArray(input, false)) return input
|
|
33
40
|
|
|
34
|
-
if (Array.isArray(input) && input.every(val => isJsonProblem(val))) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return _input.map(val => createFromJson(val))
|
|
41
|
+
if (Array.isArray(input) && input.length > 0 && input.every(val => isJsonProblem(val))) {
|
|
42
|
+
return input.map(val => createFromJson(val))
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
if (isJsonProblem(input)) {
|
|
41
46
|
return [createFromJson(input)]
|
|
42
47
|
}
|
|
48
|
+
|
|
49
|
+
if (parsers) {
|
|
50
|
+
for (const parser of parsers) {
|
|
51
|
+
const problems = parser(input)
|
|
52
|
+
if (!problems || !problems.length) continue
|
|
53
|
+
return problems
|
|
54
|
+
}
|
|
55
|
+
}
|
|
43
56
|
}
|
package/src/util/index.ts
CHANGED
package/src/util/misc.ts
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Problem } from '../problem.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checks whether a given object is an array of Problem objects
|
|
5
|
+
* @param input Object to test
|
|
6
|
+
* @param allowEmpty If true or undefined, an empty array is considered a Problem array. If false, an empty array is not considered a Problem array.
|
|
7
|
+
*/
|
|
8
|
+
export function isProblemArray(input: unknown, allowEmpty?: boolean): input is Problem[] {
|
|
9
|
+
if (!Array.isArray(input)) return false
|
|
10
|
+
|
|
11
|
+
if (input.length < 1) {
|
|
12
|
+
if (typeof allowEmpty !== 'boolean') {
|
|
13
|
+
console.warn(new Error('@emoyly/problem -> isProblemArray: input is an empty array, and therefore is considered a Problem array. If this is not the intended behavior, consider setting the "onlyWhenContent" argument to true.'))
|
|
14
|
+
return true
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return allowEmpty
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return input.every(val => val instanceof Problem)
|
|
21
|
+
}
|
package/src/util/version.ts
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isProblemArray = isProblemArray;
|
|
4
|
-
const problem_js_1 = require("../problem.js");
|
|
5
|
-
function isProblemArray(input) {
|
|
6
|
-
if (!Array.isArray(input))
|
|
7
|
-
return false;
|
|
8
|
-
return input.every(val => val instanceof problem_js_1.Problem);
|
|
9
|
-
}
|