sleepy-serv 0.4.0 → 0.6.0
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 +38 -47
- package/package.json +8 -9
- package/src/errors.js +53 -41
- package/src/index.js +176 -101
- package/src/messages.js +164 -0
- package/src/middleware.js +83 -61
- package/src/socket.js +542 -0
- package/src/utils.js +49 -0
package/src/middleware.js
CHANGED
|
@@ -1,37 +1,33 @@
|
|
|
1
1
|
import Ajv from 'ajv'
|
|
2
2
|
import addFormats from 'ajv-formats'
|
|
3
3
|
|
|
4
|
+
import { formatError } from './utils'
|
|
5
|
+
|
|
4
6
|
import {
|
|
5
7
|
BadRequestError,
|
|
6
8
|
UnsupportedMediaTypeError,
|
|
7
9
|
UnprocessableContentError,
|
|
8
10
|
} from './errors'
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
properties: {},
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
let _customFormats = {}
|
|
12
|
+
let _schemasCompiled = false
|
|
13
|
+
let _customFormats = null
|
|
16
14
|
|
|
17
|
-
function
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
async function parseBody (req) {
|
|
16
|
+
try {
|
|
17
|
+
const result = await req.json()
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
return result
|
|
20
|
+
} catch {
|
|
21
|
+
throw new BadRequestError('Invalid JSON')
|
|
24
22
|
}
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
function buildFormatterSchema (schema) {
|
|
28
|
-
if (!schema) {
|
|
29
|
-
return SCHEMA_EMPTY
|
|
30
|
-
}
|
|
31
|
-
|
|
32
26
|
const properties = Object
|
|
33
27
|
.entries(schema)
|
|
34
|
-
.map(([key, config]) => [
|
|
28
|
+
.map(([key, config]) => [
|
|
29
|
+
key,
|
|
30
|
+
{
|
|
35
31
|
type: 'string',
|
|
36
32
|
[config.type]: config.value,
|
|
37
33
|
},
|
|
@@ -47,70 +43,96 @@ function buildFormatterSchema (schema) {
|
|
|
47
43
|
}
|
|
48
44
|
}
|
|
49
45
|
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
function compileSchemas (schemas) {
|
|
47
|
+
return Object
|
|
48
|
+
.entries(schemas)
|
|
49
|
+
.reduce((accum, [key, schema]) => {
|
|
50
|
+
const formattedSchema = key !== 'body'
|
|
51
|
+
? buildFormatterSchema(schema)
|
|
52
|
+
: schema
|
|
53
|
+
|
|
54
|
+
return [
|
|
55
|
+
...accum,
|
|
56
|
+
[key, formattedSchema],
|
|
57
|
+
]
|
|
58
|
+
}, [])
|
|
59
|
+
.map(([key, schema]) => {
|
|
60
|
+
const ajv = new Ajv({
|
|
61
|
+
allErrors: true,
|
|
62
|
+
removeAdditional: 'all',
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
addFormats(ajv)
|
|
66
|
+
|
|
67
|
+
Object
|
|
68
|
+
.entries(_customFormats ?? [])
|
|
69
|
+
.forEach(([k, v]) => ajv.addFormat(k, v))
|
|
70
|
+
|
|
71
|
+
const validator = ajv.compile(schema)
|
|
72
|
+
|
|
73
|
+
return [key, validator]
|
|
74
|
+
})
|
|
75
|
+
}
|
|
52
76
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
77
|
+
export function parseJsonBody () {
|
|
78
|
+
return async (req, res, next) => {
|
|
79
|
+
const contentType = req.headers.get('content-type')
|
|
56
80
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
81
|
+
if (!contentType) {
|
|
82
|
+
return next(res)
|
|
83
|
+
}
|
|
60
84
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
console.error(err)
|
|
85
|
+
if (!contentType.startsWith('application/json')) {
|
|
86
|
+
throw new UnsupportedMediaTypeError('content-type')
|
|
87
|
+
}
|
|
65
88
|
|
|
66
|
-
|
|
67
|
-
}
|
|
89
|
+
const body = await parseBody(req)
|
|
68
90
|
|
|
69
|
-
|
|
91
|
+
return next(body)
|
|
92
|
+
}
|
|
70
93
|
}
|
|
71
94
|
|
|
72
95
|
export function setValidationFormats (formats) {
|
|
96
|
+
if (_customFormats) {
|
|
97
|
+
console.warn('setValidationFormats() - already initialized')
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (_schemasCompiled) {
|
|
101
|
+
console.warn('setValidationFormats() - called after compilation')
|
|
102
|
+
}
|
|
103
|
+
|
|
73
104
|
_customFormats = formats
|
|
74
105
|
}
|
|
75
106
|
|
|
76
|
-
|
|
77
|
-
return function (req, res, next) {
|
|
78
|
-
const formattedSchemas = {
|
|
79
|
-
headers: buildFormatterSchema(schemas.headers),
|
|
80
|
-
params: buildFormatterSchema(schemas.params),
|
|
81
|
-
query: buildFormatterSchema(schemas.query),
|
|
82
|
-
body: schemas.body || SCHEMA_EMPTY,
|
|
83
|
-
}
|
|
107
|
+
/* only for testing purposes */
|
|
84
108
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
109
|
+
export function resetValidationFormatsState () {
|
|
110
|
+
_customFormats = null
|
|
111
|
+
_schemasCompiled = false
|
|
112
|
+
}
|
|
89
113
|
|
|
90
|
-
|
|
114
|
+
export function validateSchemas (schemas) {
|
|
115
|
+
const entries = compileSchemas(schemas)
|
|
91
116
|
|
|
92
|
-
|
|
93
|
-
.entries(_customFormats)
|
|
94
|
-
.forEach(([k, v]) => ajv.addFormat(k, v))
|
|
117
|
+
_schemasCompiled = true
|
|
95
118
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const valid = schema ? ajv.validate(schema, data) : true
|
|
119
|
+
return (req, res, next) => {
|
|
120
|
+
const errors = entries.reduce((accum, [key, validator]) => {
|
|
121
|
+
const data = key === 'body' ? res : req[key]
|
|
122
|
+
const valid = validator(data)
|
|
101
123
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
124
|
+
return !valid
|
|
125
|
+
? [
|
|
126
|
+
...accum,
|
|
127
|
+
...validator.errors.map(item => formatError(key, item)),
|
|
128
|
+
]
|
|
129
|
+
: accum
|
|
130
|
+
}, [])
|
|
109
131
|
|
|
110
132
|
if (errors.length > 0) {
|
|
111
133
|
throw new UnprocessableContentError(errors)
|
|
112
134
|
}
|
|
113
135
|
|
|
114
|
-
return next()
|
|
136
|
+
return next(res)
|
|
115
137
|
}
|
|
116
138
|
}
|