@moostjs/event-http 0.3.23 → 0.3.25
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 +1 -1
- package/dist/index.cjs +139 -299
- package/dist/index.d.ts +64 -57
- package/dist/index.mjs +134 -294
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -54,4 +54,4 @@ Here are some basic steps to get you started:
|
|
|
54
54
|
|
|
55
55
|
Don't hesitate to ask for help if you need it. We believe in fostering a friendly and respectful environment for all contributors.
|
|
56
56
|
|
|
57
|
-
Thank you for your interest in Moostjs. We look forward to building something amazing together!
|
|
57
|
+
Thank you for your interest in Moostjs. We look forward to building something amazing together!
|
package/dist/index.cjs
CHANGED
|
@@ -1,124 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var eventHttp = require('@wooksjs/event-http');
|
|
4
3
|
var moost = require('moost');
|
|
4
|
+
var eventCore = require('@wooksjs/event-core');
|
|
5
|
+
var eventHttp = require('@wooksjs/event-http');
|
|
6
|
+
var httpBody = require('@wooksjs/http-body');
|
|
5
7
|
var infact = require('@prostojs/infact');
|
|
6
8
|
var http = require('http');
|
|
7
9
|
var https = require('https');
|
|
8
|
-
var eventCore = require('@wooksjs/event-core');
|
|
9
|
-
|
|
10
|
-
const LOGGER_TITLE = 'moost-http';
|
|
11
|
-
const CONTEXT_TYPE = 'HTTP';
|
|
12
|
-
class MoostHttp {
|
|
13
|
-
constructor(httpApp) {
|
|
14
|
-
this.pathBuilders = {};
|
|
15
|
-
if (httpApp && httpApp instanceof eventHttp.WooksHttp) {
|
|
16
|
-
this.httpApp = httpApp;
|
|
17
|
-
}
|
|
18
|
-
else if (httpApp) {
|
|
19
|
-
this.httpApp = eventHttp.createHttpApp({
|
|
20
|
-
...httpApp,
|
|
21
|
-
onNotFound: this.onNotFound.bind(this),
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
25
|
-
this.httpApp = eventHttp.createHttpApp({
|
|
26
|
-
onNotFound: this.onNotFound.bind(this),
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
getHttpApp() {
|
|
31
|
-
return this.httpApp;
|
|
32
|
-
}
|
|
33
|
-
getServerCb() {
|
|
34
|
-
return this.httpApp.getServerCb();
|
|
35
|
-
}
|
|
36
|
-
listen(...args) {
|
|
37
|
-
return this.httpApp.listen(...args);
|
|
38
|
-
}
|
|
39
|
-
async onNotFound() {
|
|
40
|
-
const response = await moost.defineMoostEventHandler({
|
|
41
|
-
loggerTitle: LOGGER_TITLE,
|
|
42
|
-
getIterceptorHandler: () => this.moost?.getGlobalInterceptorHandler(),
|
|
43
|
-
getControllerInstance: () => this.moost,
|
|
44
|
-
callControllerMethod: () => undefined,
|
|
45
|
-
})();
|
|
46
|
-
if (!response) {
|
|
47
|
-
throw new eventHttp.HttpError(404, 'Resource Not Found');
|
|
48
|
-
}
|
|
49
|
-
return response;
|
|
50
|
-
}
|
|
51
|
-
onInit(moost) {
|
|
52
|
-
this.moost = moost;
|
|
53
|
-
}
|
|
54
|
-
getProvideRegistry() {
|
|
55
|
-
return infact.createProvideRegistry([eventHttp.WooksHttp, () => this.getHttpApp()], ['WooksHttp', () => this.getHttpApp()], [
|
|
56
|
-
http.Server,
|
|
57
|
-
() => this.getHttpApp().getServer(),
|
|
58
|
-
], [
|
|
59
|
-
https.Server,
|
|
60
|
-
() => this.getHttpApp().getServer(),
|
|
61
|
-
]);
|
|
62
|
-
}
|
|
63
|
-
getLogger() {
|
|
64
|
-
return this.getHttpApp().getLogger('moost-http');
|
|
65
|
-
}
|
|
66
|
-
bindHandler(opts) {
|
|
67
|
-
let fn;
|
|
68
|
-
for (const handler of opts.handlers) {
|
|
69
|
-
if (handler.type !== 'HTTP')
|
|
70
|
-
continue;
|
|
71
|
-
const httpPath = handler.path;
|
|
72
|
-
const path = typeof httpPath === 'string'
|
|
73
|
-
? httpPath
|
|
74
|
-
: typeof opts.method === 'string'
|
|
75
|
-
? opts.method
|
|
76
|
-
: '';
|
|
77
|
-
const targetPath = `${opts.prefix || ''}/${path}`.replace(/\/\/+/g, '/') + `${path.endsWith('//') ? '/' : ''}`;
|
|
78
|
-
if (!fn) {
|
|
79
|
-
fn = moost.defineMoostEventHandler({
|
|
80
|
-
contextType: CONTEXT_TYPE,
|
|
81
|
-
loggerTitle: LOGGER_TITLE,
|
|
82
|
-
getIterceptorHandler: opts.getIterceptorHandler,
|
|
83
|
-
getControllerInstance: opts.getInstance,
|
|
84
|
-
controllerMethod: opts.method,
|
|
85
|
-
resolveArgs: opts.resolveArgs,
|
|
86
|
-
manualUnscope: true,
|
|
87
|
-
hooks: {
|
|
88
|
-
init: ({ unscope }) => {
|
|
89
|
-
const { rawRequest } = eventHttp.useRequest();
|
|
90
|
-
rawRequest.on('end', unscope);
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
const routerBinding = this.httpApp.on(handler.method, targetPath, fn);
|
|
96
|
-
const { getPath: pathBuilder } = routerBinding;
|
|
97
|
-
const methodMeta = moost.getMoostMate().read(opts.fakeInstance, opts.method) ||
|
|
98
|
-
{};
|
|
99
|
-
const id = (methodMeta.id || opts.method);
|
|
100
|
-
if (id) {
|
|
101
|
-
const methods = (this.pathBuilders[id] =
|
|
102
|
-
this.pathBuilders[id] || {});
|
|
103
|
-
if (handler.method === '*') {
|
|
104
|
-
methods.GET = pathBuilder;
|
|
105
|
-
methods.PUT = pathBuilder;
|
|
106
|
-
methods.PATCH = pathBuilder;
|
|
107
|
-
methods.POST = pathBuilder;
|
|
108
|
-
methods.DELETE = pathBuilder;
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
methods[handler.method] = pathBuilder;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
opts.logHandler(`${'[36m'}(${handler.method})${'[32m'}${targetPath}`);
|
|
115
|
-
const args = routerBinding.getArgs();
|
|
116
|
-
const params = {};
|
|
117
|
-
args.forEach(a => params[a] = `{${a}}`);
|
|
118
|
-
opts.register(handler, routerBinding.getPath(params), args);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
10
|
|
|
123
11
|
function HttpMethod(method, path) {
|
|
124
12
|
return moost.getMoostMate().decorate('handlers', { method, path, type: 'HTTP' }, true);
|
|
@@ -130,154 +18,6 @@ const Put = (path) => HttpMethod('PUT', path);
|
|
|
130
18
|
const Delete = (path) => HttpMethod('DELETE', path);
|
|
131
19
|
const Patch = (path) => HttpMethod('PATCH', path);
|
|
132
20
|
|
|
133
|
-
const compressors = {
|
|
134
|
-
identity: {
|
|
135
|
-
compress: (v) => v,
|
|
136
|
-
uncompress: (v) => v,
|
|
137
|
-
},
|
|
138
|
-
};
|
|
139
|
-
async function uncompressBody(encodings, body) {
|
|
140
|
-
let newBody = body;
|
|
141
|
-
for (const e of encodings.reverse()) {
|
|
142
|
-
if (!compressors[e]) {
|
|
143
|
-
throw new Error(`Usupported compression type "${e}".`);
|
|
144
|
-
}
|
|
145
|
-
newBody = await compressors[e].uncompress(body);
|
|
146
|
-
}
|
|
147
|
-
return newBody;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function useBody() {
|
|
151
|
-
const { store } = eventHttp.useHttpContext();
|
|
152
|
-
const { init } = store('request');
|
|
153
|
-
const { rawBody } = eventHttp.useRequest();
|
|
154
|
-
const { 'content-type': contentType, 'content-encoding': contentEncoding } = eventHttp.useHeaders();
|
|
155
|
-
function contentIs(type) {
|
|
156
|
-
return (contentType || '').indexOf(type) >= 0;
|
|
157
|
-
}
|
|
158
|
-
const isJson = () => init('isJson', () => contentIs('application/json'));
|
|
159
|
-
const isHtml = () => init('isHtml', () => contentIs('text/html'));
|
|
160
|
-
const isXml = () => init('isXml', () => contentIs('text/xml'));
|
|
161
|
-
const isText = () => init('isText', () => contentIs('text/plain'));
|
|
162
|
-
const isBinary = () => init('isBinary', () => contentIs('application/octet-stream'));
|
|
163
|
-
const isFormData = () => init('isFormData', () => contentIs('multipart/form-data'));
|
|
164
|
-
const isUrlencoded = () => init('isUrlencoded', () => contentIs('application/x-www-form-urlencoded'));
|
|
165
|
-
const isCompressed = () => init('isCompressed', () => {
|
|
166
|
-
const parts = contentEncodings();
|
|
167
|
-
for (const p of parts) {
|
|
168
|
-
if (['deflate', 'gzip', 'br'].includes(p))
|
|
169
|
-
return true;
|
|
170
|
-
}
|
|
171
|
-
return false;
|
|
172
|
-
});
|
|
173
|
-
const contentEncodings = () => init('contentEncodings', () => (contentEncoding || '')
|
|
174
|
-
.split(',')
|
|
175
|
-
.map((p) => p.trim())
|
|
176
|
-
.filter((p) => !!p));
|
|
177
|
-
const parseBody = () => init('parsed', async () => {
|
|
178
|
-
const body = await uncompressBody(contentEncodings(), (await rawBody()).toString());
|
|
179
|
-
if (isJson())
|
|
180
|
-
return jsonParser(body);
|
|
181
|
-
else if (isFormData())
|
|
182
|
-
return formDataParser(body);
|
|
183
|
-
else if (isUrlencoded())
|
|
184
|
-
return urlEncodedParser(body);
|
|
185
|
-
else if (isBinary())
|
|
186
|
-
return textParser(body);
|
|
187
|
-
else
|
|
188
|
-
return textParser(body);
|
|
189
|
-
});
|
|
190
|
-
function jsonParser(v) {
|
|
191
|
-
try {
|
|
192
|
-
return JSON.parse(v);
|
|
193
|
-
}
|
|
194
|
-
catch (e) {
|
|
195
|
-
throw new eventHttp.HttpError(400, e.message);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
function textParser(v) {
|
|
199
|
-
return v;
|
|
200
|
-
}
|
|
201
|
-
function formDataParser(v) {
|
|
202
|
-
const boundary = '--' +
|
|
203
|
-
(/boundary=([^;]+)(?:;|$)/.exec(contentType || '') || [, ''])[1];
|
|
204
|
-
if (!boundary)
|
|
205
|
-
throw new eventHttp.HttpError(eventHttp.EHttpStatusCode.BadRequest, 'form-data boundary not recognized');
|
|
206
|
-
const parts = v.trim().split(boundary);
|
|
207
|
-
const result = {};
|
|
208
|
-
let key = '';
|
|
209
|
-
let partContentType = 'text/plain';
|
|
210
|
-
for (const part of parts) {
|
|
211
|
-
parsePart();
|
|
212
|
-
key = '';
|
|
213
|
-
partContentType = 'text/plain';
|
|
214
|
-
let valueMode = false;
|
|
215
|
-
const lines = part
|
|
216
|
-
.trim()
|
|
217
|
-
.split(/\n/g)
|
|
218
|
-
.map((s) => s.trim());
|
|
219
|
-
for (const line of lines) {
|
|
220
|
-
if (valueMode) {
|
|
221
|
-
if (!result[key]) {
|
|
222
|
-
result[key] = line;
|
|
223
|
-
}
|
|
224
|
-
else {
|
|
225
|
-
result[key] += '\n' + line;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
if (!line || line === '--') {
|
|
230
|
-
valueMode = !!key;
|
|
231
|
-
if (valueMode) {
|
|
232
|
-
key = key.replace(/^["']/, '').replace(/["']$/, '');
|
|
233
|
-
}
|
|
234
|
-
continue;
|
|
235
|
-
}
|
|
236
|
-
if (line
|
|
237
|
-
.toLowerCase()
|
|
238
|
-
.startsWith('content-disposition: form-data;')) {
|
|
239
|
-
key = (/name=([^;]+)/.exec(line) || [])[1];
|
|
240
|
-
if (!key)
|
|
241
|
-
throw new eventHttp.HttpError(eventHttp.EHttpStatusCode.BadRequest, 'Could not read multipart name: ' + line);
|
|
242
|
-
continue;
|
|
243
|
-
}
|
|
244
|
-
if (line.toLowerCase().startsWith('content-type:')) {
|
|
245
|
-
partContentType = (/content-type:\s?([^;]+)/i.exec(line) || [])[1];
|
|
246
|
-
if (!partContentType)
|
|
247
|
-
throw new eventHttp.HttpError(eventHttp.EHttpStatusCode.BadRequest, 'Could not read content-type: ' + line);
|
|
248
|
-
continue;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
parsePart();
|
|
254
|
-
function parsePart() {
|
|
255
|
-
if (key) {
|
|
256
|
-
if (partContentType.indexOf('application/json') >= 0) {
|
|
257
|
-
result[key] = JSON.parse(result[key]);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
return result;
|
|
262
|
-
}
|
|
263
|
-
function urlEncodedParser(v) {
|
|
264
|
-
return new eventHttp.WooksURLSearchParams(v.trim()).toJson();
|
|
265
|
-
}
|
|
266
|
-
return {
|
|
267
|
-
isJson,
|
|
268
|
-
isHtml,
|
|
269
|
-
isXml,
|
|
270
|
-
isText,
|
|
271
|
-
isBinary,
|
|
272
|
-
isFormData,
|
|
273
|
-
isUrlencoded,
|
|
274
|
-
isCompressed,
|
|
275
|
-
contentEncodings,
|
|
276
|
-
parseBody,
|
|
277
|
-
rawBody,
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
|
|
281
21
|
const StatusHook = () => moost.Resolve((metas, level) => {
|
|
282
22
|
const hook = eventHttp.useStatus();
|
|
283
23
|
if (level === 'PARAM') {
|
|
@@ -287,7 +27,7 @@ const StatusHook = () => moost.Resolve((metas, level) => {
|
|
|
287
27
|
const initialValue = metas.instance[metas.key];
|
|
288
28
|
eventCore.attachHook(metas.instance, {
|
|
289
29
|
get: () => hook.value,
|
|
290
|
-
set:
|
|
30
|
+
set: v => (hook.value = v),
|
|
291
31
|
}, metas.key);
|
|
292
32
|
return typeof initialValue === 'number' ? initialValue : 200;
|
|
293
33
|
}
|
|
@@ -301,7 +41,7 @@ const HeaderHook = (name) => moost.Resolve((metas, level) => {
|
|
|
301
41
|
const initialValue = metas.instance[metas.key];
|
|
302
42
|
eventCore.attachHook(metas.instance, {
|
|
303
43
|
get: () => hook.value,
|
|
304
|
-
set:
|
|
44
|
+
set: v => (hook.value = v),
|
|
305
45
|
}, metas.key);
|
|
306
46
|
return typeof initialValue === 'string' ? initialValue : '';
|
|
307
47
|
}
|
|
@@ -315,7 +55,7 @@ const CookieHook = (name) => moost.Resolve((metas, level) => {
|
|
|
315
55
|
const initialValue = metas.instance[metas.key];
|
|
316
56
|
eventCore.attachHook(metas.instance, {
|
|
317
57
|
get: () => hook.value,
|
|
318
|
-
set:
|
|
58
|
+
set: v => (hook.value = v),
|
|
319
59
|
}, metas.key);
|
|
320
60
|
return typeof initialValue === 'string' ? initialValue : '';
|
|
321
61
|
}
|
|
@@ -325,14 +65,14 @@ const CookieAttrsHook = (name) => moost.Resolve((metas, level) => {
|
|
|
325
65
|
if (level === 'PARAM') {
|
|
326
66
|
return eventCore.attachHook({}, {
|
|
327
67
|
get: () => hook.attrs,
|
|
328
|
-
set:
|
|
68
|
+
set: v => (hook.attrs = v),
|
|
329
69
|
});
|
|
330
70
|
}
|
|
331
71
|
if (level === 'PROP' && metas.instance && metas.key) {
|
|
332
72
|
const initialValue = metas.instance[metas.key];
|
|
333
73
|
eventCore.attachHook(metas.instance, {
|
|
334
74
|
get: () => hook.attrs,
|
|
335
|
-
set:
|
|
75
|
+
set: v => (hook.attrs = v),
|
|
336
76
|
}, metas.key);
|
|
337
77
|
return typeof initialValue === 'object' ? initialValue : {};
|
|
338
78
|
}
|
|
@@ -341,20 +81,21 @@ function Authorization(name) {
|
|
|
341
81
|
return moost.Resolve(() => {
|
|
342
82
|
const auth = eventHttp.useAuthorization();
|
|
343
83
|
switch (name) {
|
|
344
|
-
case 'username':
|
|
345
|
-
return auth.isBasic()
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
: undefined;
|
|
352
|
-
case 'bearer':
|
|
84
|
+
case 'username': {
|
|
85
|
+
return auth.isBasic() ? auth.basicCredentials()?.username : undefined;
|
|
86
|
+
}
|
|
87
|
+
case 'password': {
|
|
88
|
+
return auth.isBasic() ? auth.basicCredentials()?.password : undefined;
|
|
89
|
+
}
|
|
90
|
+
case 'bearer': {
|
|
353
91
|
return auth.isBearer() ? auth.authorization : undefined;
|
|
354
|
-
|
|
92
|
+
}
|
|
93
|
+
case 'raw': {
|
|
355
94
|
return auth.authRawCredentials();
|
|
356
|
-
|
|
95
|
+
}
|
|
96
|
+
case 'type': {
|
|
357
97
|
return auth.authType();
|
|
98
|
+
}
|
|
358
99
|
}
|
|
359
100
|
}, 'authorization');
|
|
360
101
|
}
|
|
@@ -362,10 +103,10 @@ function Header(name) {
|
|
|
362
103
|
return moost.Resolve(() => {
|
|
363
104
|
const headers = eventHttp.useHeaders();
|
|
364
105
|
return headers[name];
|
|
365
|
-
},
|
|
106
|
+
}, `header: ${name}`);
|
|
366
107
|
}
|
|
367
108
|
function Cookie(name) {
|
|
368
|
-
return moost.Resolve(() => eventHttp.useCookies().getCookie(name),
|
|
109
|
+
return moost.Resolve(() => eventHttp.useCookies().getCookie(name), `cookie: ${name}`);
|
|
369
110
|
}
|
|
370
111
|
function Query(name) {
|
|
371
112
|
const isItem = !!name;
|
|
@@ -378,7 +119,7 @@ function Query(name) {
|
|
|
378
119
|
return value === null ? undefined : value;
|
|
379
120
|
}
|
|
380
121
|
const json = jsonSearchParams();
|
|
381
|
-
return Object.keys(json).length ? json : undefined;
|
|
122
|
+
return Object.keys(json).length > 0 ? json : undefined;
|
|
382
123
|
}, _name));
|
|
383
124
|
}
|
|
384
125
|
function Url() {
|
|
@@ -403,10 +144,10 @@ function IpList() {
|
|
|
403
144
|
return moost.Resolve(() => eventHttp.useRequest().getIpList(), 'ipList');
|
|
404
145
|
}
|
|
405
146
|
function Body() {
|
|
406
|
-
return moost.getMoostMate().apply(moost.getMoostMate().decorate('paramSource', 'BODY'), moost.Resolve(() => useBody().parseBody(), 'body'));
|
|
147
|
+
return moost.getMoostMate().apply(moost.getMoostMate().decorate('paramSource', 'BODY'), moost.Resolve(() => httpBody.useBody().parseBody(), 'body'));
|
|
407
148
|
}
|
|
408
149
|
function RawBody() {
|
|
409
|
-
return moost.Resolve(() => useBody().rawBody(), 'body');
|
|
150
|
+
return moost.Resolve(() => httpBody.useBody().rawBody(), 'body');
|
|
410
151
|
}
|
|
411
152
|
|
|
412
153
|
const setHeaderInterceptor = (name, value, opts) => {
|
|
@@ -414,8 +155,7 @@ const setHeaderInterceptor = (name, value, opts) => {
|
|
|
414
155
|
const h = eventHttp.useSetHeader(name);
|
|
415
156
|
const status = eventHttp.useStatus();
|
|
416
157
|
const cb = () => {
|
|
417
|
-
if ((!h.value || opts?.force) &&
|
|
418
|
-
(!opts?.status || opts.status === status.value)) {
|
|
158
|
+
if ((!h.value || opts?.force) && (!opts?.status || opts.status === status.value)) {
|
|
419
159
|
h.value = value;
|
|
420
160
|
}
|
|
421
161
|
};
|
|
@@ -447,27 +187,127 @@ const setCookieInterceptor = (name, value, attrs) => {
|
|
|
447
187
|
function SetCookie(...args) {
|
|
448
188
|
return moost.Intercept(setCookieInterceptor(...args));
|
|
449
189
|
}
|
|
450
|
-
const setStatusInterceptor = (code, opts) => {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
}
|
|
457
|
-
});
|
|
190
|
+
const setStatusInterceptor = (code, opts) => moost.defineInterceptorFn((before, after) => {
|
|
191
|
+
const status = eventHttp.useStatus();
|
|
192
|
+
after(() => {
|
|
193
|
+
if (!status.isDefined || opts?.force) {
|
|
194
|
+
status.value = code;
|
|
195
|
+
}
|
|
458
196
|
});
|
|
459
|
-
};
|
|
197
|
+
});
|
|
460
198
|
function SetStatus(...args) {
|
|
461
199
|
return moost.Intercept(setStatusInterceptor(...args));
|
|
462
200
|
}
|
|
463
201
|
|
|
202
|
+
const LOGGER_TITLE = 'moost-http';
|
|
203
|
+
const CONTEXT_TYPE = 'HTTP';
|
|
204
|
+
class MoostHttp {
|
|
205
|
+
constructor(httpApp) {
|
|
206
|
+
this.pathBuilders = {};
|
|
207
|
+
if (httpApp && httpApp instanceof eventHttp.WooksHttp) {
|
|
208
|
+
this.httpApp = httpApp;
|
|
209
|
+
}
|
|
210
|
+
else if (httpApp) {
|
|
211
|
+
this.httpApp = eventHttp.createHttpApp({
|
|
212
|
+
...httpApp,
|
|
213
|
+
onNotFound: this.onNotFound.bind(this),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
this.httpApp = eventHttp.createHttpApp({
|
|
218
|
+
onNotFound: this.onNotFound.bind(this),
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
getHttpApp() {
|
|
223
|
+
return this.httpApp;
|
|
224
|
+
}
|
|
225
|
+
getServerCb() {
|
|
226
|
+
return this.httpApp.getServerCb();
|
|
227
|
+
}
|
|
228
|
+
listen(port, hostname, backlog, listeningListener) {
|
|
229
|
+
return this.httpApp.listen(port, hostname, backlog, listeningListener);
|
|
230
|
+
}
|
|
231
|
+
async onNotFound() {
|
|
232
|
+
const response = await moost.defineMoostEventHandler({
|
|
233
|
+
loggerTitle: LOGGER_TITLE,
|
|
234
|
+
getIterceptorHandler: () => this.moost?.getGlobalInterceptorHandler(),
|
|
235
|
+
getControllerInstance: () => this.moost,
|
|
236
|
+
callControllerMethod: () => undefined,
|
|
237
|
+
})();
|
|
238
|
+
if (!response) {
|
|
239
|
+
throw new eventHttp.HttpError(404, 'Resource Not Found');
|
|
240
|
+
}
|
|
241
|
+
return response;
|
|
242
|
+
}
|
|
243
|
+
onInit(moost) {
|
|
244
|
+
this.moost = moost;
|
|
245
|
+
}
|
|
246
|
+
getProvideRegistry() {
|
|
247
|
+
return infact.createProvideRegistry([eventHttp.WooksHttp, () => this.getHttpApp()], ['WooksHttp', () => this.getHttpApp()], [http.Server, () => this.getHttpApp().getServer()], [https.Server, () => this.getHttpApp().getServer()]);
|
|
248
|
+
}
|
|
249
|
+
getLogger() {
|
|
250
|
+
return this.getHttpApp().getLogger('moost-http');
|
|
251
|
+
}
|
|
252
|
+
bindHandler(opts) {
|
|
253
|
+
let fn;
|
|
254
|
+
for (const handler of opts.handlers) {
|
|
255
|
+
if (handler.type !== 'HTTP') {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
const httpPath = handler.path;
|
|
259
|
+
const path = typeof httpPath === 'string' ? httpPath : typeof opts.method === 'string' ? opts.method : '';
|
|
260
|
+
const targetPath = `${`${opts.prefix || ''}/${path}`.replace(/\/\/+/g, '/')}${path.endsWith('//') ? '/' : ''}`;
|
|
261
|
+
if (!fn) {
|
|
262
|
+
fn = moost.defineMoostEventHandler({
|
|
263
|
+
contextType: CONTEXT_TYPE,
|
|
264
|
+
loggerTitle: LOGGER_TITLE,
|
|
265
|
+
getIterceptorHandler: opts.getIterceptorHandler,
|
|
266
|
+
getControllerInstance: opts.getInstance,
|
|
267
|
+
controllerMethod: opts.method,
|
|
268
|
+
resolveArgs: opts.resolveArgs,
|
|
269
|
+
manualUnscope: true,
|
|
270
|
+
hooks: {
|
|
271
|
+
init: ({ unscope }) => {
|
|
272
|
+
const { rawRequest } = eventHttp.useRequest();
|
|
273
|
+
rawRequest.on('end', unscope);
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
const routerBinding = this.httpApp.on(handler.method, targetPath, fn);
|
|
279
|
+
const { getPath: pathBuilder } = routerBinding;
|
|
280
|
+
const methodMeta = moost.getMoostMate().read(opts.fakeInstance, opts.method) || {};
|
|
281
|
+
const id = (methodMeta.id || opts.method);
|
|
282
|
+
if (id) {
|
|
283
|
+
const methods = (this.pathBuilders[id] = this.pathBuilders[id] || {});
|
|
284
|
+
if (handler.method === '*') {
|
|
285
|
+
methods.GET = pathBuilder;
|
|
286
|
+
methods.PUT = pathBuilder;
|
|
287
|
+
methods.PATCH = pathBuilder;
|
|
288
|
+
methods.POST = pathBuilder;
|
|
289
|
+
methods.DELETE = pathBuilder;
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
methods[handler.method] = pathBuilder;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
opts.logHandler(`${'[36m'}(${handler.method})${'[32m'}${targetPath}`);
|
|
296
|
+
const args = routerBinding.getArgs();
|
|
297
|
+
const params = {};
|
|
298
|
+
args.forEach(a => (params[a] = `{${a}}`));
|
|
299
|
+
opts.register(handler, routerBinding.getPath(params), args);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
464
304
|
Object.defineProperty(exports, "HttpError", {
|
|
465
|
-
|
|
466
|
-
|
|
305
|
+
enumerable: true,
|
|
306
|
+
get: function () { return eventHttp.HttpError; }
|
|
467
307
|
});
|
|
468
308
|
Object.defineProperty(exports, "useHttpContext", {
|
|
469
|
-
|
|
470
|
-
|
|
309
|
+
enumerable: true,
|
|
310
|
+
get: function () { return eventHttp.useHttpContext; }
|
|
471
311
|
});
|
|
472
312
|
exports.All = All;
|
|
473
313
|
exports.Authorization = Authorization;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,63 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { THook } from '@wooksjs/event-core';
|
|
2
|
+
import { TCookieAttributes as TCookieAttributes$1, useSetCookies, WooksHttp, TWooksHttpOptions } from '@wooksjs/event-http';
|
|
3
|
+
export { HttpError, TCookieAttributesInput, useHttpContext } from '@wooksjs/event-http';
|
|
2
4
|
import * as moost from 'moost';
|
|
3
|
-
import { TMoostAdapter, Moost, TMoostAdapterOptions
|
|
5
|
+
import { TInterceptorFn, TMoostAdapter, Moost, TMoostAdapterOptions } from 'moost';
|
|
6
|
+
import * as _prostojs_logger from '@prostojs/logger';
|
|
4
7
|
import * as http from 'http';
|
|
5
|
-
import { WooksHttp, TWooksHttpOptions, TCookieAttributes as TCookieAttributes$1, useSetCookies } from '@wooksjs/event-http';
|
|
6
|
-
export { HttpError, TCookieAttributesInput, useHttpContext } from '@wooksjs/event-http';
|
|
7
8
|
import { TProstoRouterPathBuilder } from '@prostojs/router';
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
interface THttpHandlerMeta {
|
|
11
|
-
method: string;
|
|
12
|
-
path: string;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* ## Moost HTTP Adapter
|
|
16
|
-
*
|
|
17
|
-
* Moost Adapter for HTTP events
|
|
18
|
-
*
|
|
19
|
-
* ```ts
|
|
20
|
-
* │ // HTTP server example
|
|
21
|
-
* │ import { MoostHttp, Get } from '@moostjs/event-http'
|
|
22
|
-
* │ import { Moost, Param } from 'moost'
|
|
23
|
-
* │
|
|
24
|
-
* │ class MyServer extends Moost {
|
|
25
|
-
* │ @Get('test/:name')
|
|
26
|
-
* │ test(@Param('name') name: string) {
|
|
27
|
-
* │ return { message: `Hello ${name}!` }
|
|
28
|
-
* │ }
|
|
29
|
-
* │ }
|
|
30
|
-
* │
|
|
31
|
-
* │ const app = new MyServer()
|
|
32
|
-
* │ const http = new MoostHttp()
|
|
33
|
-
* │ app.adapter(http).listen(3000, () => {
|
|
34
|
-
* │ app.getLogger('MyApp').log('Up on port 3000')
|
|
35
|
-
* │ })
|
|
36
|
-
* │ app.init()
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
39
|
-
declare class MoostHttp implements TMoostAdapter<THttpHandlerMeta> {
|
|
40
|
-
protected httpApp: WooksHttp;
|
|
41
|
-
constructor(httpApp?: WooksHttp | TWooksHttpOptions);
|
|
42
|
-
getHttpApp(): WooksHttp;
|
|
43
|
-
getServerCb(): (req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>) => Promise<void>;
|
|
44
|
-
listen(...args: Parameters<WooksHttp['listen']>): Promise<unknown>;
|
|
45
|
-
readonly pathBuilders: {
|
|
46
|
-
[id: string]: {
|
|
47
|
-
GET?: TProstoRouterPathBuilder<Record<string, string | string[]>>;
|
|
48
|
-
PUT?: TProstoRouterPathBuilder<Record<string, string | string[]>>;
|
|
49
|
-
PATCH?: TProstoRouterPathBuilder<Record<string, string | string[]>>;
|
|
50
|
-
POST?: TProstoRouterPathBuilder<Record<string, string | string[]>>;
|
|
51
|
-
DELETE?: TProstoRouterPathBuilder<Record<string, string | string[]>>;
|
|
52
|
-
};
|
|
53
|
-
};
|
|
54
|
-
onNotFound(): Promise<{}>;
|
|
55
|
-
protected moost?: Moost;
|
|
56
|
-
onInit(moost: Moost): void;
|
|
57
|
-
getProvideRegistry(): moost.TProvideRegistry;
|
|
58
|
-
getLogger(): _prostojs_logger.TConsoleBase;
|
|
59
|
-
bindHandler<T extends object = object>(opts: TMoostAdapterOptions<THttpHandlerMeta, T>): void;
|
|
60
|
-
}
|
|
9
|
+
import { ListenOptions } from 'net';
|
|
61
10
|
|
|
62
11
|
declare function HttpMethod(method: '*' | 'GET' | 'PUT' | 'POST' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS', path?: string): MethodDecorator;
|
|
63
12
|
declare const All: (path?: string) => MethodDecorator;
|
|
@@ -276,4 +225,62 @@ declare const setStatusInterceptor: (code: number, opts?: {
|
|
|
276
225
|
*/
|
|
277
226
|
declare function SetStatus(...args: Parameters<typeof setStatusInterceptor>): ClassDecorator & MethodDecorator;
|
|
278
227
|
|
|
228
|
+
interface THttpHandlerMeta {
|
|
229
|
+
method: string;
|
|
230
|
+
path: string;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* ## Moost HTTP Adapter
|
|
234
|
+
*
|
|
235
|
+
* Moost Adapter for HTTP events
|
|
236
|
+
*
|
|
237
|
+
* ```ts
|
|
238
|
+
* │ // HTTP server example
|
|
239
|
+
* │ import { MoostHttp, Get } from '@moostjs/event-http'
|
|
240
|
+
* │ import { Moost, Param } from 'moost'
|
|
241
|
+
* │
|
|
242
|
+
* │ class MyServer extends Moost {
|
|
243
|
+
* │ @Get('test/:name')
|
|
244
|
+
* │ test(@Param('name') name: string) {
|
|
245
|
+
* │ return { message: `Hello ${name}!` }
|
|
246
|
+
* │ }
|
|
247
|
+
* │ }
|
|
248
|
+
* │
|
|
249
|
+
* │ const app = new MyServer()
|
|
250
|
+
* │ const http = new MoostHttp()
|
|
251
|
+
* │ app.adapter(http).listen(3000, () => {
|
|
252
|
+
* │ app.getLogger('MyApp').log('Up on port 3000')
|
|
253
|
+
* │ })
|
|
254
|
+
* │ app.init()
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
declare class MoostHttp implements TMoostAdapter<THttpHandlerMeta> {
|
|
258
|
+
protected httpApp: WooksHttp;
|
|
259
|
+
constructor(httpApp?: WooksHttp | TWooksHttpOptions);
|
|
260
|
+
getHttpApp(): WooksHttp;
|
|
261
|
+
getServerCb(): (req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>) => Promise<void>;
|
|
262
|
+
listen(port?: number, hostname?: string, backlog?: number, listeningListener?: () => void): Promise<void>;
|
|
263
|
+
listen(port?: number, hostname?: string, listeningListener?: () => void): Promise<void>;
|
|
264
|
+
listen(port?: number, backlog?: number, listeningListener?: () => void): Promise<void>;
|
|
265
|
+
listen(port?: number, listeningListener?: () => void): Promise<void>;
|
|
266
|
+
listen(path: string, backlog?: number, listeningListener?: () => void): Promise<void>;
|
|
267
|
+
listen(path: string, listeningListener?: () => void): Promise<void>;
|
|
268
|
+
listen(options: ListenOptions, listeningListener?: () => void): Promise<void>;
|
|
269
|
+
listen(handle: any, backlog?: number, listeningListener?: () => void): Promise<void>;
|
|
270
|
+
listen(handle: any, listeningListener?: () => void): Promise<void>;
|
|
271
|
+
readonly pathBuilders: Record<string, {
|
|
272
|
+
GET?: TProstoRouterPathBuilder<Record<string, string | string[]>>;
|
|
273
|
+
PUT?: TProstoRouterPathBuilder<Record<string, string | string[]>>;
|
|
274
|
+
PATCH?: TProstoRouterPathBuilder<Record<string, string | string[]>>;
|
|
275
|
+
POST?: TProstoRouterPathBuilder<Record<string, string | string[]>>;
|
|
276
|
+
DELETE?: TProstoRouterPathBuilder<Record<string, string | string[]>>;
|
|
277
|
+
}>;
|
|
278
|
+
onNotFound(): Promise<{}>;
|
|
279
|
+
protected moost?: Moost;
|
|
280
|
+
onInit(moost: Moost): void;
|
|
281
|
+
getProvideRegistry(): moost.TProvideRegistry;
|
|
282
|
+
getLogger(): _prostojs_logger.TConsoleBase;
|
|
283
|
+
bindHandler<T extends object = object>(opts: TMoostAdapterOptions<THttpHandlerMeta, T>): void;
|
|
284
|
+
}
|
|
285
|
+
|
|
279
286
|
export { All, Authorization, Body, Cookie, CookieAttrsHook, CookieHook, Delete, Get, Header, HeaderHook, HttpMethod, Ip, IpList, Method, MoostHttp, Patch, Post, Put, Query, RawBody, Req, ReqId, Res, SetCookie, SetHeader, SetStatus, StatusHook, type TCookieAttributes, type TCookieHook, type THeaderHook, type THttpHandlerMeta, type TStatusHook, Url };
|
package/dist/index.mjs
CHANGED
|
@@ -1,123 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getMoostMate, Resolve, Intercept, TInterceptorPriority, defineInterceptorFn, defineMoostEventHandler } from 'moost';
|
|
2
|
+
import { attachHook } from '@wooksjs/event-core';
|
|
3
|
+
import { useStatus, useSetHeader, useSetCookie, useAuthorization, useHeaders, useCookies, useSearchParams, useRequest, useResponse, useSetCookies, WooksHttp, createHttpApp, HttpError } from '@wooksjs/event-http';
|
|
2
4
|
export { HttpError, useHttpContext } from '@wooksjs/event-http';
|
|
3
|
-
import {
|
|
5
|
+
import { useBody } from '@wooksjs/http-body';
|
|
4
6
|
import { createProvideRegistry } from '@prostojs/infact';
|
|
5
7
|
import { Server } from 'http';
|
|
6
8
|
import { Server as Server$1 } from 'https';
|
|
7
|
-
import { attachHook } from '@wooksjs/event-core';
|
|
8
|
-
|
|
9
|
-
const LOGGER_TITLE = 'moost-http';
|
|
10
|
-
const CONTEXT_TYPE = 'HTTP';
|
|
11
|
-
class MoostHttp {
|
|
12
|
-
constructor(httpApp) {
|
|
13
|
-
this.pathBuilders = {};
|
|
14
|
-
if (httpApp && httpApp instanceof WooksHttp) {
|
|
15
|
-
this.httpApp = httpApp;
|
|
16
|
-
}
|
|
17
|
-
else if (httpApp) {
|
|
18
|
-
this.httpApp = createHttpApp({
|
|
19
|
-
...httpApp,
|
|
20
|
-
onNotFound: this.onNotFound.bind(this),
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
this.httpApp = createHttpApp({
|
|
25
|
-
onNotFound: this.onNotFound.bind(this),
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
getHttpApp() {
|
|
30
|
-
return this.httpApp;
|
|
31
|
-
}
|
|
32
|
-
getServerCb() {
|
|
33
|
-
return this.httpApp.getServerCb();
|
|
34
|
-
}
|
|
35
|
-
listen(...args) {
|
|
36
|
-
return this.httpApp.listen(...args);
|
|
37
|
-
}
|
|
38
|
-
async onNotFound() {
|
|
39
|
-
const response = await defineMoostEventHandler({
|
|
40
|
-
loggerTitle: LOGGER_TITLE,
|
|
41
|
-
getIterceptorHandler: () => this.moost?.getGlobalInterceptorHandler(),
|
|
42
|
-
getControllerInstance: () => this.moost,
|
|
43
|
-
callControllerMethod: () => undefined,
|
|
44
|
-
})();
|
|
45
|
-
if (!response) {
|
|
46
|
-
throw new HttpError(404, 'Resource Not Found');
|
|
47
|
-
}
|
|
48
|
-
return response;
|
|
49
|
-
}
|
|
50
|
-
onInit(moost) {
|
|
51
|
-
this.moost = moost;
|
|
52
|
-
}
|
|
53
|
-
getProvideRegistry() {
|
|
54
|
-
return createProvideRegistry([WooksHttp, () => this.getHttpApp()], ['WooksHttp', () => this.getHttpApp()], [
|
|
55
|
-
Server,
|
|
56
|
-
() => this.getHttpApp().getServer(),
|
|
57
|
-
], [
|
|
58
|
-
Server$1,
|
|
59
|
-
() => this.getHttpApp().getServer(),
|
|
60
|
-
]);
|
|
61
|
-
}
|
|
62
|
-
getLogger() {
|
|
63
|
-
return this.getHttpApp().getLogger('moost-http');
|
|
64
|
-
}
|
|
65
|
-
bindHandler(opts) {
|
|
66
|
-
let fn;
|
|
67
|
-
for (const handler of opts.handlers) {
|
|
68
|
-
if (handler.type !== 'HTTP')
|
|
69
|
-
continue;
|
|
70
|
-
const httpPath = handler.path;
|
|
71
|
-
const path = typeof httpPath === 'string'
|
|
72
|
-
? httpPath
|
|
73
|
-
: typeof opts.method === 'string'
|
|
74
|
-
? opts.method
|
|
75
|
-
: '';
|
|
76
|
-
const targetPath = `${opts.prefix || ''}/${path}`.replace(/\/\/+/g, '/') + `${path.endsWith('//') ? '/' : ''}`;
|
|
77
|
-
if (!fn) {
|
|
78
|
-
fn = defineMoostEventHandler({
|
|
79
|
-
contextType: CONTEXT_TYPE,
|
|
80
|
-
loggerTitle: LOGGER_TITLE,
|
|
81
|
-
getIterceptorHandler: opts.getIterceptorHandler,
|
|
82
|
-
getControllerInstance: opts.getInstance,
|
|
83
|
-
controllerMethod: opts.method,
|
|
84
|
-
resolveArgs: opts.resolveArgs,
|
|
85
|
-
manualUnscope: true,
|
|
86
|
-
hooks: {
|
|
87
|
-
init: ({ unscope }) => {
|
|
88
|
-
const { rawRequest } = useRequest();
|
|
89
|
-
rawRequest.on('end', unscope);
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
const routerBinding = this.httpApp.on(handler.method, targetPath, fn);
|
|
95
|
-
const { getPath: pathBuilder } = routerBinding;
|
|
96
|
-
const methodMeta = getMoostMate().read(opts.fakeInstance, opts.method) ||
|
|
97
|
-
{};
|
|
98
|
-
const id = (methodMeta.id || opts.method);
|
|
99
|
-
if (id) {
|
|
100
|
-
const methods = (this.pathBuilders[id] =
|
|
101
|
-
this.pathBuilders[id] || {});
|
|
102
|
-
if (handler.method === '*') {
|
|
103
|
-
methods.GET = pathBuilder;
|
|
104
|
-
methods.PUT = pathBuilder;
|
|
105
|
-
methods.PATCH = pathBuilder;
|
|
106
|
-
methods.POST = pathBuilder;
|
|
107
|
-
methods.DELETE = pathBuilder;
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
methods[handler.method] = pathBuilder;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
opts.logHandler(`${'[36m'}(${handler.method})${'[32m'}${targetPath}`);
|
|
114
|
-
const args = routerBinding.getArgs();
|
|
115
|
-
const params = {};
|
|
116
|
-
args.forEach(a => params[a] = `{${a}}`);
|
|
117
|
-
opts.register(handler, routerBinding.getPath(params), args);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
9
|
|
|
122
10
|
function HttpMethod(method, path) {
|
|
123
11
|
return getMoostMate().decorate('handlers', { method, path, type: 'HTTP' }, true);
|
|
@@ -129,154 +17,6 @@ const Put = (path) => HttpMethod('PUT', path);
|
|
|
129
17
|
const Delete = (path) => HttpMethod('DELETE', path);
|
|
130
18
|
const Patch = (path) => HttpMethod('PATCH', path);
|
|
131
19
|
|
|
132
|
-
const compressors = {
|
|
133
|
-
identity: {
|
|
134
|
-
compress: (v) => v,
|
|
135
|
-
uncompress: (v) => v,
|
|
136
|
-
},
|
|
137
|
-
};
|
|
138
|
-
async function uncompressBody(encodings, body) {
|
|
139
|
-
let newBody = body;
|
|
140
|
-
for (const e of encodings.reverse()) {
|
|
141
|
-
if (!compressors[e]) {
|
|
142
|
-
throw new Error(`Usupported compression type "${e}".`);
|
|
143
|
-
}
|
|
144
|
-
newBody = await compressors[e].uncompress(body);
|
|
145
|
-
}
|
|
146
|
-
return newBody;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function useBody() {
|
|
150
|
-
const { store } = useHttpContext();
|
|
151
|
-
const { init } = store('request');
|
|
152
|
-
const { rawBody } = useRequest();
|
|
153
|
-
const { 'content-type': contentType, 'content-encoding': contentEncoding } = useHeaders();
|
|
154
|
-
function contentIs(type) {
|
|
155
|
-
return (contentType || '').indexOf(type) >= 0;
|
|
156
|
-
}
|
|
157
|
-
const isJson = () => init('isJson', () => contentIs('application/json'));
|
|
158
|
-
const isHtml = () => init('isHtml', () => contentIs('text/html'));
|
|
159
|
-
const isXml = () => init('isXml', () => contentIs('text/xml'));
|
|
160
|
-
const isText = () => init('isText', () => contentIs('text/plain'));
|
|
161
|
-
const isBinary = () => init('isBinary', () => contentIs('application/octet-stream'));
|
|
162
|
-
const isFormData = () => init('isFormData', () => contentIs('multipart/form-data'));
|
|
163
|
-
const isUrlencoded = () => init('isUrlencoded', () => contentIs('application/x-www-form-urlencoded'));
|
|
164
|
-
const isCompressed = () => init('isCompressed', () => {
|
|
165
|
-
const parts = contentEncodings();
|
|
166
|
-
for (const p of parts) {
|
|
167
|
-
if (['deflate', 'gzip', 'br'].includes(p))
|
|
168
|
-
return true;
|
|
169
|
-
}
|
|
170
|
-
return false;
|
|
171
|
-
});
|
|
172
|
-
const contentEncodings = () => init('contentEncodings', () => (contentEncoding || '')
|
|
173
|
-
.split(',')
|
|
174
|
-
.map((p) => p.trim())
|
|
175
|
-
.filter((p) => !!p));
|
|
176
|
-
const parseBody = () => init('parsed', async () => {
|
|
177
|
-
const body = await uncompressBody(contentEncodings(), (await rawBody()).toString());
|
|
178
|
-
if (isJson())
|
|
179
|
-
return jsonParser(body);
|
|
180
|
-
else if (isFormData())
|
|
181
|
-
return formDataParser(body);
|
|
182
|
-
else if (isUrlencoded())
|
|
183
|
-
return urlEncodedParser(body);
|
|
184
|
-
else if (isBinary())
|
|
185
|
-
return textParser(body);
|
|
186
|
-
else
|
|
187
|
-
return textParser(body);
|
|
188
|
-
});
|
|
189
|
-
function jsonParser(v) {
|
|
190
|
-
try {
|
|
191
|
-
return JSON.parse(v);
|
|
192
|
-
}
|
|
193
|
-
catch (e) {
|
|
194
|
-
throw new HttpError(400, e.message);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
function textParser(v) {
|
|
198
|
-
return v;
|
|
199
|
-
}
|
|
200
|
-
function formDataParser(v) {
|
|
201
|
-
const boundary = '--' +
|
|
202
|
-
(/boundary=([^;]+)(?:;|$)/.exec(contentType || '') || [, ''])[1];
|
|
203
|
-
if (!boundary)
|
|
204
|
-
throw new HttpError(EHttpStatusCode.BadRequest, 'form-data boundary not recognized');
|
|
205
|
-
const parts = v.trim().split(boundary);
|
|
206
|
-
const result = {};
|
|
207
|
-
let key = '';
|
|
208
|
-
let partContentType = 'text/plain';
|
|
209
|
-
for (const part of parts) {
|
|
210
|
-
parsePart();
|
|
211
|
-
key = '';
|
|
212
|
-
partContentType = 'text/plain';
|
|
213
|
-
let valueMode = false;
|
|
214
|
-
const lines = part
|
|
215
|
-
.trim()
|
|
216
|
-
.split(/\n/g)
|
|
217
|
-
.map((s) => s.trim());
|
|
218
|
-
for (const line of lines) {
|
|
219
|
-
if (valueMode) {
|
|
220
|
-
if (!result[key]) {
|
|
221
|
-
result[key] = line;
|
|
222
|
-
}
|
|
223
|
-
else {
|
|
224
|
-
result[key] += '\n' + line;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
if (!line || line === '--') {
|
|
229
|
-
valueMode = !!key;
|
|
230
|
-
if (valueMode) {
|
|
231
|
-
key = key.replace(/^["']/, '').replace(/["']$/, '');
|
|
232
|
-
}
|
|
233
|
-
continue;
|
|
234
|
-
}
|
|
235
|
-
if (line
|
|
236
|
-
.toLowerCase()
|
|
237
|
-
.startsWith('content-disposition: form-data;')) {
|
|
238
|
-
key = (/name=([^;]+)/.exec(line) || [])[1];
|
|
239
|
-
if (!key)
|
|
240
|
-
throw new HttpError(EHttpStatusCode.BadRequest, 'Could not read multipart name: ' + line);
|
|
241
|
-
continue;
|
|
242
|
-
}
|
|
243
|
-
if (line.toLowerCase().startsWith('content-type:')) {
|
|
244
|
-
partContentType = (/content-type:\s?([^;]+)/i.exec(line) || [])[1];
|
|
245
|
-
if (!partContentType)
|
|
246
|
-
throw new HttpError(EHttpStatusCode.BadRequest, 'Could not read content-type: ' + line);
|
|
247
|
-
continue;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
parsePart();
|
|
253
|
-
function parsePart() {
|
|
254
|
-
if (key) {
|
|
255
|
-
if (partContentType.indexOf('application/json') >= 0) {
|
|
256
|
-
result[key] = JSON.parse(result[key]);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
return result;
|
|
261
|
-
}
|
|
262
|
-
function urlEncodedParser(v) {
|
|
263
|
-
return new WooksURLSearchParams(v.trim()).toJson();
|
|
264
|
-
}
|
|
265
|
-
return {
|
|
266
|
-
isJson,
|
|
267
|
-
isHtml,
|
|
268
|
-
isXml,
|
|
269
|
-
isText,
|
|
270
|
-
isBinary,
|
|
271
|
-
isFormData,
|
|
272
|
-
isUrlencoded,
|
|
273
|
-
isCompressed,
|
|
274
|
-
contentEncodings,
|
|
275
|
-
parseBody,
|
|
276
|
-
rawBody,
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
|
|
280
20
|
const StatusHook = () => Resolve((metas, level) => {
|
|
281
21
|
const hook = useStatus();
|
|
282
22
|
if (level === 'PARAM') {
|
|
@@ -286,7 +26,7 @@ const StatusHook = () => Resolve((metas, level) => {
|
|
|
286
26
|
const initialValue = metas.instance[metas.key];
|
|
287
27
|
attachHook(metas.instance, {
|
|
288
28
|
get: () => hook.value,
|
|
289
|
-
set:
|
|
29
|
+
set: v => (hook.value = v),
|
|
290
30
|
}, metas.key);
|
|
291
31
|
return typeof initialValue === 'number' ? initialValue : 200;
|
|
292
32
|
}
|
|
@@ -300,7 +40,7 @@ const HeaderHook = (name) => Resolve((metas, level) => {
|
|
|
300
40
|
const initialValue = metas.instance[metas.key];
|
|
301
41
|
attachHook(metas.instance, {
|
|
302
42
|
get: () => hook.value,
|
|
303
|
-
set:
|
|
43
|
+
set: v => (hook.value = v),
|
|
304
44
|
}, metas.key);
|
|
305
45
|
return typeof initialValue === 'string' ? initialValue : '';
|
|
306
46
|
}
|
|
@@ -314,7 +54,7 @@ const CookieHook = (name) => Resolve((metas, level) => {
|
|
|
314
54
|
const initialValue = metas.instance[metas.key];
|
|
315
55
|
attachHook(metas.instance, {
|
|
316
56
|
get: () => hook.value,
|
|
317
|
-
set:
|
|
57
|
+
set: v => (hook.value = v),
|
|
318
58
|
}, metas.key);
|
|
319
59
|
return typeof initialValue === 'string' ? initialValue : '';
|
|
320
60
|
}
|
|
@@ -324,14 +64,14 @@ const CookieAttrsHook = (name) => Resolve((metas, level) => {
|
|
|
324
64
|
if (level === 'PARAM') {
|
|
325
65
|
return attachHook({}, {
|
|
326
66
|
get: () => hook.attrs,
|
|
327
|
-
set:
|
|
67
|
+
set: v => (hook.attrs = v),
|
|
328
68
|
});
|
|
329
69
|
}
|
|
330
70
|
if (level === 'PROP' && metas.instance && metas.key) {
|
|
331
71
|
const initialValue = metas.instance[metas.key];
|
|
332
72
|
attachHook(metas.instance, {
|
|
333
73
|
get: () => hook.attrs,
|
|
334
|
-
set:
|
|
74
|
+
set: v => (hook.attrs = v),
|
|
335
75
|
}, metas.key);
|
|
336
76
|
return typeof initialValue === 'object' ? initialValue : {};
|
|
337
77
|
}
|
|
@@ -340,20 +80,21 @@ function Authorization(name) {
|
|
|
340
80
|
return Resolve(() => {
|
|
341
81
|
const auth = useAuthorization();
|
|
342
82
|
switch (name) {
|
|
343
|
-
case 'username':
|
|
344
|
-
return auth.isBasic()
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
: undefined;
|
|
351
|
-
case 'bearer':
|
|
83
|
+
case 'username': {
|
|
84
|
+
return auth.isBasic() ? auth.basicCredentials()?.username : undefined;
|
|
85
|
+
}
|
|
86
|
+
case 'password': {
|
|
87
|
+
return auth.isBasic() ? auth.basicCredentials()?.password : undefined;
|
|
88
|
+
}
|
|
89
|
+
case 'bearer': {
|
|
352
90
|
return auth.isBearer() ? auth.authorization : undefined;
|
|
353
|
-
|
|
91
|
+
}
|
|
92
|
+
case 'raw': {
|
|
354
93
|
return auth.authRawCredentials();
|
|
355
|
-
|
|
94
|
+
}
|
|
95
|
+
case 'type': {
|
|
356
96
|
return auth.authType();
|
|
97
|
+
}
|
|
357
98
|
}
|
|
358
99
|
}, 'authorization');
|
|
359
100
|
}
|
|
@@ -361,10 +102,10 @@ function Header(name) {
|
|
|
361
102
|
return Resolve(() => {
|
|
362
103
|
const headers = useHeaders();
|
|
363
104
|
return headers[name];
|
|
364
|
-
},
|
|
105
|
+
}, `header: ${name}`);
|
|
365
106
|
}
|
|
366
107
|
function Cookie(name) {
|
|
367
|
-
return Resolve(() => useCookies().getCookie(name),
|
|
108
|
+
return Resolve(() => useCookies().getCookie(name), `cookie: ${name}`);
|
|
368
109
|
}
|
|
369
110
|
function Query(name) {
|
|
370
111
|
const isItem = !!name;
|
|
@@ -377,7 +118,7 @@ function Query(name) {
|
|
|
377
118
|
return value === null ? undefined : value;
|
|
378
119
|
}
|
|
379
120
|
const json = jsonSearchParams();
|
|
380
|
-
return Object.keys(json).length ? json : undefined;
|
|
121
|
+
return Object.keys(json).length > 0 ? json : undefined;
|
|
381
122
|
}, _name));
|
|
382
123
|
}
|
|
383
124
|
function Url() {
|
|
@@ -413,8 +154,7 @@ const setHeaderInterceptor = (name, value, opts) => {
|
|
|
413
154
|
const h = useSetHeader(name);
|
|
414
155
|
const status = useStatus();
|
|
415
156
|
const cb = () => {
|
|
416
|
-
if ((!h.value || opts?.force) &&
|
|
417
|
-
(!opts?.status || opts.status === status.value)) {
|
|
157
|
+
if ((!h.value || opts?.force) && (!opts?.status || opts.status === status.value)) {
|
|
418
158
|
h.value = value;
|
|
419
159
|
}
|
|
420
160
|
};
|
|
@@ -446,18 +186,118 @@ const setCookieInterceptor = (name, value, attrs) => {
|
|
|
446
186
|
function SetCookie(...args) {
|
|
447
187
|
return Intercept(setCookieInterceptor(...args));
|
|
448
188
|
}
|
|
449
|
-
const setStatusInterceptor = (code, opts) => {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
}
|
|
456
|
-
});
|
|
189
|
+
const setStatusInterceptor = (code, opts) => defineInterceptorFn((before, after) => {
|
|
190
|
+
const status = useStatus();
|
|
191
|
+
after(() => {
|
|
192
|
+
if (!status.isDefined || opts?.force) {
|
|
193
|
+
status.value = code;
|
|
194
|
+
}
|
|
457
195
|
});
|
|
458
|
-
};
|
|
196
|
+
});
|
|
459
197
|
function SetStatus(...args) {
|
|
460
198
|
return Intercept(setStatusInterceptor(...args));
|
|
461
199
|
}
|
|
462
200
|
|
|
201
|
+
const LOGGER_TITLE = 'moost-http';
|
|
202
|
+
const CONTEXT_TYPE = 'HTTP';
|
|
203
|
+
class MoostHttp {
|
|
204
|
+
constructor(httpApp) {
|
|
205
|
+
this.pathBuilders = {};
|
|
206
|
+
if (httpApp && httpApp instanceof WooksHttp) {
|
|
207
|
+
this.httpApp = httpApp;
|
|
208
|
+
}
|
|
209
|
+
else if (httpApp) {
|
|
210
|
+
this.httpApp = createHttpApp({
|
|
211
|
+
...httpApp,
|
|
212
|
+
onNotFound: this.onNotFound.bind(this),
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
this.httpApp = createHttpApp({
|
|
217
|
+
onNotFound: this.onNotFound.bind(this),
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
getHttpApp() {
|
|
222
|
+
return this.httpApp;
|
|
223
|
+
}
|
|
224
|
+
getServerCb() {
|
|
225
|
+
return this.httpApp.getServerCb();
|
|
226
|
+
}
|
|
227
|
+
listen(port, hostname, backlog, listeningListener) {
|
|
228
|
+
return this.httpApp.listen(port, hostname, backlog, listeningListener);
|
|
229
|
+
}
|
|
230
|
+
async onNotFound() {
|
|
231
|
+
const response = await defineMoostEventHandler({
|
|
232
|
+
loggerTitle: LOGGER_TITLE,
|
|
233
|
+
getIterceptorHandler: () => this.moost?.getGlobalInterceptorHandler(),
|
|
234
|
+
getControllerInstance: () => this.moost,
|
|
235
|
+
callControllerMethod: () => undefined,
|
|
236
|
+
})();
|
|
237
|
+
if (!response) {
|
|
238
|
+
throw new HttpError(404, 'Resource Not Found');
|
|
239
|
+
}
|
|
240
|
+
return response;
|
|
241
|
+
}
|
|
242
|
+
onInit(moost) {
|
|
243
|
+
this.moost = moost;
|
|
244
|
+
}
|
|
245
|
+
getProvideRegistry() {
|
|
246
|
+
return createProvideRegistry([WooksHttp, () => this.getHttpApp()], ['WooksHttp', () => this.getHttpApp()], [Server, () => this.getHttpApp().getServer()], [Server$1, () => this.getHttpApp().getServer()]);
|
|
247
|
+
}
|
|
248
|
+
getLogger() {
|
|
249
|
+
return this.getHttpApp().getLogger('moost-http');
|
|
250
|
+
}
|
|
251
|
+
bindHandler(opts) {
|
|
252
|
+
let fn;
|
|
253
|
+
for (const handler of opts.handlers) {
|
|
254
|
+
if (handler.type !== 'HTTP') {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
const httpPath = handler.path;
|
|
258
|
+
const path = typeof httpPath === 'string' ? httpPath : typeof opts.method === 'string' ? opts.method : '';
|
|
259
|
+
const targetPath = `${`${opts.prefix || ''}/${path}`.replace(/\/\/+/g, '/')}${path.endsWith('//') ? '/' : ''}`;
|
|
260
|
+
if (!fn) {
|
|
261
|
+
fn = defineMoostEventHandler({
|
|
262
|
+
contextType: CONTEXT_TYPE,
|
|
263
|
+
loggerTitle: LOGGER_TITLE,
|
|
264
|
+
getIterceptorHandler: opts.getIterceptorHandler,
|
|
265
|
+
getControllerInstance: opts.getInstance,
|
|
266
|
+
controllerMethod: opts.method,
|
|
267
|
+
resolveArgs: opts.resolveArgs,
|
|
268
|
+
manualUnscope: true,
|
|
269
|
+
hooks: {
|
|
270
|
+
init: ({ unscope }) => {
|
|
271
|
+
const { rawRequest } = useRequest();
|
|
272
|
+
rawRequest.on('end', unscope);
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
const routerBinding = this.httpApp.on(handler.method, targetPath, fn);
|
|
278
|
+
const { getPath: pathBuilder } = routerBinding;
|
|
279
|
+
const methodMeta = getMoostMate().read(opts.fakeInstance, opts.method) || {};
|
|
280
|
+
const id = (methodMeta.id || opts.method);
|
|
281
|
+
if (id) {
|
|
282
|
+
const methods = (this.pathBuilders[id] = this.pathBuilders[id] || {});
|
|
283
|
+
if (handler.method === '*') {
|
|
284
|
+
methods.GET = pathBuilder;
|
|
285
|
+
methods.PUT = pathBuilder;
|
|
286
|
+
methods.PATCH = pathBuilder;
|
|
287
|
+
methods.POST = pathBuilder;
|
|
288
|
+
methods.DELETE = pathBuilder;
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
methods[handler.method] = pathBuilder;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
opts.logHandler(`${'[36m'}(${handler.method})${'[32m'}${targetPath}`);
|
|
295
|
+
const args = routerBinding.getArgs();
|
|
296
|
+
const params = {};
|
|
297
|
+
args.forEach(a => (params[a] = `{${a}}`));
|
|
298
|
+
opts.register(handler, routerBinding.getPath(params), args);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
463
303
|
export { All, Authorization, Body, Cookie, CookieAttrsHook, CookieHook, Delete, Get, Header, HeaderHook, HttpMethod, Ip, IpList, Method, MoostHttp, Patch, Post, Put, Query, RawBody, Req, ReqId, Res, SetCookie, SetHeader, SetStatus, StatusHook, Url };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moostjs/event-http",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.25",
|
|
4
4
|
"description": "@moostjs/event-http",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -38,9 +38,10 @@
|
|
|
38
38
|
"homepage": "https://github.com/moostjs/moostjs/tree/main/packages/event-http#readme",
|
|
39
39
|
"peerDependencies": {},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"moost": "0.3.
|
|
42
|
-
"@wooksjs/event-core": "^0.4.
|
|
43
|
-
"@wooksjs/event-http": "^0.4.
|
|
41
|
+
"moost": "0.3.25",
|
|
42
|
+
"@wooksjs/event-core": "^0.4.30",
|
|
43
|
+
"@wooksjs/event-http": "^0.4.30",
|
|
44
|
+
"@wooksjs/http-body": "^0.4.30",
|
|
44
45
|
"@prostojs/infact": "^0.1.13",
|
|
45
46
|
"@prostojs/router": "^0.2.1"
|
|
46
47
|
}
|