vona-module-a-web 5.0.10 → 5.0.12
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/index.js +614 -3
- package/dist/lib/decorator/request.d.ts +2 -2
- package/dist/types/request.d.ts +0 -9
- package/dist/types/router.d.ts +2 -2
- package/package.json +2 -2
- package/dist/.metadata/index.js +0 -38
- package/dist/.metadata/this.js +0 -2
- package/dist/bean/bean.router.js +0 -188
- package/dist/bean/startup.listen.js +0 -34
- package/dist/config/config.js +0 -8
- package/dist/lib/decorator/bean.js +0 -42
- package/dist/lib/decorator/index.js +0 -3
- package/dist/lib/decorator/request.js +0 -46
- package/dist/lib/decorator/response.js +0 -12
- package/dist/lib/index.js +0 -2
- package/dist/lib/middleware/extractValue.js +0 -48
- package/dist/lib/middleware/middlewareGuard.js +0 -12
- package/dist/lib/middleware/middlewareInterceptor.js +0 -8
- package/dist/lib/middleware/middlewarePipe.js +0 -118
- package/dist/lib/utils.js +0 -7
- package/dist/main.js +0 -63
- package/dist/service/web.js +0 -28
- package/dist/types/controller.js +0 -1
- package/dist/types/dto.js +0 -1
- package/dist/types/index.js +0 -6
- package/dist/types/request.js +0 -11
- package/dist/types/response.js +0 -4
- package/dist/types/router.js +0 -1
- package/dist/types/service.js +0 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,614 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { appMetadata, BeanInfo, BeanBase, appResource, deepExtend, compose, cast, BeanSimple, BeanScopeBase, createBeanDecorator } from 'vona';
|
|
2
|
+
import { Bean, Scope } from 'vona-module-a-bean';
|
|
3
|
+
import * as ModuleInfo from '@cabloy/module-info';
|
|
4
|
+
import { SymbolUseOnionOptions } from 'vona-module-a-onion';
|
|
5
|
+
import { SymbolRouteHandlersArgumentsValue, SymbolRouteHandlersArgumentsMeta, SymbolOpenApiOptions, mergeFieldsOpenAPIMetadata } from 'vona-module-a-openapi';
|
|
6
|
+
import { valid } from 'vona-module-a-validation';
|
|
7
|
+
import { SymbolUploadValue } from 'vona-module-a-upload';
|
|
8
|
+
import http from 'node:http';
|
|
9
|
+
import { Startup } from 'vona-module-a-startup';
|
|
10
|
+
import Router from 'find-my-way';
|
|
11
|
+
import { SymbolRouterMiddleware } from 'vona-module-a-executor';
|
|
12
|
+
import { Service as Service$1, SymbolRequestMappingHandler as SymbolRequestMappingHandler$1 } from 'vona-module-a-web';
|
|
13
|
+
import { combineParamsAndQuery } from '@cabloy/utils';
|
|
14
|
+
|
|
15
|
+
async function middlewareGuard(ctx, next) {
|
|
16
|
+
// check handler
|
|
17
|
+
const handler = ctx.getHandler();
|
|
18
|
+
if (!handler) return next();
|
|
19
|
+
// compose
|
|
20
|
+
const result = await ctx.app.bean.onion.guard.compose(ctx)(ctx);
|
|
21
|
+
if (result === false) ctx.app.throw(403);
|
|
22
|
+
// next
|
|
23
|
+
return next();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function middlewareInterceptor(ctx, next) {
|
|
27
|
+
// check handler
|
|
28
|
+
const handler = ctx.getHandler();
|
|
29
|
+
if (!handler) return next();
|
|
30
|
+
// compose
|
|
31
|
+
return await ctx.app.bean.onion.interceptor.compose(ctx)(ctx, next);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function extractValue(ctx, argMeta) {
|
|
35
|
+
return exchangeKeyForValue(ctx, argMeta.type, argMeta.field);
|
|
36
|
+
}
|
|
37
|
+
function exchangeKeyForValue(ctx, type, field) {
|
|
38
|
+
const req = ctx.request;
|
|
39
|
+
const res = ctx.response;
|
|
40
|
+
const modes = {
|
|
41
|
+
request: () => req,
|
|
42
|
+
response: () => res,
|
|
43
|
+
body: () => field && req.body ? req.body[field] : req.body,
|
|
44
|
+
query: () => field ? req.query[field] : req.query,
|
|
45
|
+
param: () => field ? req.params[field] : req.params,
|
|
46
|
+
headers: () => field ? req.headers[field.toLowerCase()] : req.headers,
|
|
47
|
+
host: () => {
|
|
48
|
+
const hosts = req.hosts || {};
|
|
49
|
+
return field ? hosts[field] : hosts;
|
|
50
|
+
},
|
|
51
|
+
ip: () => req.ip,
|
|
52
|
+
rawBody: () => req.rawBody,
|
|
53
|
+
user: () => ctx.app.bean.passport.getCurrentUser(),
|
|
54
|
+
fields: () => {
|
|
55
|
+
const uploadValue = ctx[SymbolUploadValue];
|
|
56
|
+
if (!uploadValue) throw new Error('should use interceptor: a-upload:upload');
|
|
57
|
+
return field ? uploadValue.fields.filter(item => item.name === field).map(item => item.value) : uploadValue.fields;
|
|
58
|
+
},
|
|
59
|
+
field: () => {
|
|
60
|
+
const uploadValue = ctx[SymbolUploadValue];
|
|
61
|
+
if (!uploadValue) throw new Error('should use interceptor: a-upload:upload');
|
|
62
|
+
return field ? uploadValue.fields.find(item => item.name === field)?.value : uploadValue.fields[0]?.value;
|
|
63
|
+
},
|
|
64
|
+
files: () => {
|
|
65
|
+
const uploadValue = ctx[SymbolUploadValue];
|
|
66
|
+
if (!uploadValue) throw new Error('should use interceptor: a-upload:upload');
|
|
67
|
+
return field ? uploadValue.files.filter(item => item.name === field) : uploadValue.files;
|
|
68
|
+
},
|
|
69
|
+
file: () => {
|
|
70
|
+
const uploadValue = ctx[SymbolUploadValue];
|
|
71
|
+
if (!uploadValue) throw new Error('should use interceptor: a-upload:upload');
|
|
72
|
+
return field ? uploadValue.files.find(item => item.name === field) : uploadValue.files[0];
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
return modes[type]?.();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function middlewarePipe(ctx, next) {
|
|
79
|
+
// check handler
|
|
80
|
+
const handler = ctx.getHandler();
|
|
81
|
+
if (!handler) return next();
|
|
82
|
+
// body parser
|
|
83
|
+
await ctx.app.bean._getBean('a-body.service.body').parse(true);
|
|
84
|
+
// arguments
|
|
85
|
+
ctx[SymbolRouteHandlersArgumentsValue] = await _transformArguments(ctx, ctx.getController(), handler);
|
|
86
|
+
// next
|
|
87
|
+
return next();
|
|
88
|
+
}
|
|
89
|
+
async function _transformArguments(ctx, controller, handler) {
|
|
90
|
+
const paramtypes = appMetadata.getMetadata('design:paramtypes', controller.prototype, handler.name);
|
|
91
|
+
if (!paramtypes) return;
|
|
92
|
+
|
|
93
|
+
// meta
|
|
94
|
+
const argsMeta = appMetadata.getMetadata(SymbolRouteHandlersArgumentsMeta, controller.prototype, handler.name);
|
|
95
|
+
if (!argsMeta) return;
|
|
96
|
+
|
|
97
|
+
// args
|
|
98
|
+
const args = Array.from({
|
|
99
|
+
length: paramtypes.length
|
|
100
|
+
});
|
|
101
|
+
for (let index = args.length - 1; index >= 0; index--) {
|
|
102
|
+
const argMeta = argsMeta.find(item => item.index === index);
|
|
103
|
+
if (!argMeta) continue;
|
|
104
|
+
// extractValue
|
|
105
|
+
const value = await _extractArgumentValue(ctx, argMeta);
|
|
106
|
+
// metadata
|
|
107
|
+
const metadata = {
|
|
108
|
+
type: argMeta.type,
|
|
109
|
+
field: argMeta.field,
|
|
110
|
+
metaType: paramtypes[index],
|
|
111
|
+
controller,
|
|
112
|
+
method: handler.name,
|
|
113
|
+
index: argMeta.index
|
|
114
|
+
};
|
|
115
|
+
// transform
|
|
116
|
+
args[index] = await _transformArgument(ctx, argMeta, metadata, value);
|
|
117
|
+
}
|
|
118
|
+
return args;
|
|
119
|
+
}
|
|
120
|
+
async function _transformArgument(ctx, argMeta, metadata, value) {
|
|
121
|
+
// pipes
|
|
122
|
+
const pipes = composePipes(ctx, argMeta, (beanInstance, value, options, _next) => {
|
|
123
|
+
return beanInstance.transform(value, metadata, options);
|
|
124
|
+
});
|
|
125
|
+
if (pipes.length === 0) return value;
|
|
126
|
+
// apply
|
|
127
|
+
for (const pipe of pipes) {
|
|
128
|
+
value = await pipe(value, _pipeNextDefault);
|
|
129
|
+
}
|
|
130
|
+
return value;
|
|
131
|
+
}
|
|
132
|
+
function _pipeNextDefault(value) {
|
|
133
|
+
return value;
|
|
134
|
+
}
|
|
135
|
+
async function _extractArgumentValue(ctx, argMeta) {
|
|
136
|
+
if (argMeta.extractValue) {
|
|
137
|
+
return await argMeta.extractValue(ctx, argMeta);
|
|
138
|
+
}
|
|
139
|
+
return extractValue(ctx, argMeta);
|
|
140
|
+
}
|
|
141
|
+
const SymbolCacheMiddlewaresArgument = Symbol('SymbolCacheMiddlewaresArgument');
|
|
142
|
+
function composePipes(ctx, argMeta, executeCustom) {
|
|
143
|
+
if (!ctx.app.meta[SymbolCacheMiddlewaresArgument]) ctx.app.meta[SymbolCacheMiddlewaresArgument] = {};
|
|
144
|
+
const __cacheMiddlewaresArgument = ctx.app.meta[SymbolCacheMiddlewaresArgument];
|
|
145
|
+
const onionPipe = ctx.app.bean.onion.pipe;
|
|
146
|
+
const beanFullName = ctx.getControllerBeanFullName();
|
|
147
|
+
const handlerName = ctx.getHandler().name;
|
|
148
|
+
const key = `${beanFullName}:${handlerName}:${argMeta.index}`;
|
|
149
|
+
if (!__cacheMiddlewaresArgument[key]) {
|
|
150
|
+
const middlewares = [];
|
|
151
|
+
// pipes: global
|
|
152
|
+
for (const item of onionPipe.onionsGlobal) {
|
|
153
|
+
middlewares.push(onionPipe._wrapOnion(item, executeCustom));
|
|
154
|
+
}
|
|
155
|
+
// pipes: route
|
|
156
|
+
const middlewaresLocal = onionPipe._collectOnionsHandler(ctx);
|
|
157
|
+
for (const item of middlewaresLocal) {
|
|
158
|
+
middlewares.push(onionPipe._wrapOnion(item, executeCustom));
|
|
159
|
+
}
|
|
160
|
+
// pipes: arguments
|
|
161
|
+
const middlewaresArgument = _collectArgumentMiddlewares(onionPipe, argMeta);
|
|
162
|
+
if (middlewaresArgument) {
|
|
163
|
+
for (const item of middlewaresArgument) {
|
|
164
|
+
middlewares.push(onionPipe._wrapOnion(item, executeCustom));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
__cacheMiddlewaresArgument[key] = middlewares;
|
|
168
|
+
}
|
|
169
|
+
return __cacheMiddlewaresArgument[key];
|
|
170
|
+
}
|
|
171
|
+
function _collectArgumentMiddlewares(onionPipe, argMeta) {
|
|
172
|
+
if (!argMeta.pipes) return;
|
|
173
|
+
return argMeta.pipes.map(pipe => {
|
|
174
|
+
if (typeof pipe !== 'function') {
|
|
175
|
+
pipe = valid({
|
|
176
|
+
schema: pipe
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
const {
|
|
180
|
+
pipeName,
|
|
181
|
+
options
|
|
182
|
+
} = pipe();
|
|
183
|
+
const item = onionPipe.onionsNormal[pipeName];
|
|
184
|
+
if (!item) throw new Error(`${onionPipe.sceneName} not found: ${pipeName}`);
|
|
185
|
+
return {
|
|
186
|
+
...item,
|
|
187
|
+
argumentPipe: {
|
|
188
|
+
options
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const SymbolRequestMappingHandler = Symbol('SymbolRequestMappingHandler');
|
|
195
|
+
|
|
196
|
+
// export enum RequestMethod {
|
|
197
|
+
// GET = 'get',
|
|
198
|
+
// POST = 'post',
|
|
199
|
+
// PUT = 'put',
|
|
200
|
+
// DELETE = 'delete',
|
|
201
|
+
// PATCH = 'patch',
|
|
202
|
+
// OPTIONS = 'options',
|
|
203
|
+
// HEAD = 'head',
|
|
204
|
+
// }
|
|
205
|
+
|
|
206
|
+
var _dec$3, _dec2$3, _class$3;
|
|
207
|
+
const SymbolRouteComposeMiddlewaresCache = Symbol('SymbolRouteComposeMiddlewaresCache');
|
|
208
|
+
let BeanRouter = (_dec$3 = Bean(), _dec2$3 = BeanInfo({
|
|
209
|
+
module: "a-web"
|
|
210
|
+
}), _dec$3(_class$3 = _dec2$3(_class$3 = class BeanRouter extends BeanBase {
|
|
211
|
+
registerController(moduleName, controller) {
|
|
212
|
+
// info
|
|
213
|
+
const info = ModuleInfo.parseInfo(moduleName);
|
|
214
|
+
// controller options
|
|
215
|
+
const beanOptions = appResource.getBean(controller);
|
|
216
|
+
if (!beanOptions) return;
|
|
217
|
+
const controllerBeanFullName = beanOptions.beanFullName;
|
|
218
|
+
const controllerOptions = beanOptions.options;
|
|
219
|
+
const controllerPath = controllerOptions.path;
|
|
220
|
+
const controllerMiddlewaresOptions = appMetadata.getMetadata(SymbolUseOnionOptions, controller);
|
|
221
|
+
// descs
|
|
222
|
+
const descs = Object.getOwnPropertyDescriptors(controller.prototype);
|
|
223
|
+
for (const actionKey in descs) {
|
|
224
|
+
const desc = descs[actionKey];
|
|
225
|
+
if (['constructor'].includes(actionKey)) continue;
|
|
226
|
+
if (!desc.value || typeof desc.value !== 'function') continue;
|
|
227
|
+
this._registerControllerAction(info, controller, controllerBeanFullName, controllerPath, controllerMiddlewaresOptions, actionKey, desc);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
register(method, moduleName, path, simplify, fn) {
|
|
231
|
+
const app = this.app;
|
|
232
|
+
const _path = app.util.combineApiPath(path, moduleName, true, simplify);
|
|
233
|
+
app.router.on(method, _path, fn);
|
|
234
|
+
}
|
|
235
|
+
unRegister(method, moduleName, path, simplify) {
|
|
236
|
+
const app = this.app;
|
|
237
|
+
const _path = app.util.combineApiPath(path, moduleName, true, simplify);
|
|
238
|
+
app.router.off(method, _path);
|
|
239
|
+
}
|
|
240
|
+
findByPath(method, moduleName, path, simplify) {
|
|
241
|
+
const app = this.app;
|
|
242
|
+
const _path = app.util.combineApiPath(path, moduleName, true, simplify);
|
|
243
|
+
return app.router.findRoute(method, _path);
|
|
244
|
+
}
|
|
245
|
+
_registerControllerAction(info, controller, controllerBeanFullName, controllerPath, controllerMiddlewaresOptions, actionKey, desc) {
|
|
246
|
+
// app
|
|
247
|
+
const app = this.app;
|
|
248
|
+
|
|
249
|
+
// actionPath/actionMethod
|
|
250
|
+
if (!appMetadata.hasMetadata(SymbolRequestMappingHandler, controller.prototype, actionKey)) return;
|
|
251
|
+
const handlerMetadata = appMetadata.getMetadata(SymbolRequestMappingHandler, controller.prototype, actionKey);
|
|
252
|
+
const actionPath = handlerMetadata.path || '';
|
|
253
|
+
const actionMethod = handlerMetadata.method || 'get';
|
|
254
|
+
// routePath
|
|
255
|
+
const routePath = app.util.combineApiPathControllerAndAction(info.relativeName, controllerPath, actionPath, true, true);
|
|
256
|
+
const routePathRaw = app.util.combineApiPathControllerAndActionRaw(info.relativeName, controllerPath, actionPath, true);
|
|
257
|
+
|
|
258
|
+
// middlewares options
|
|
259
|
+
const actionMiddlewaresOptions = appMetadata.getMetadata(SymbolUseOnionOptions, controller.prototype, actionKey);
|
|
260
|
+
|
|
261
|
+
// route
|
|
262
|
+
const route = {
|
|
263
|
+
meta: deepExtend({}, controllerMiddlewaresOptions, actionMiddlewaresOptions)
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// route
|
|
267
|
+
const _route = {
|
|
268
|
+
pid: info.pid,
|
|
269
|
+
module: info.name,
|
|
270
|
+
controller,
|
|
271
|
+
actionDescriptor: desc,
|
|
272
|
+
controllerBeanFullName,
|
|
273
|
+
action: actionKey,
|
|
274
|
+
route,
|
|
275
|
+
routeMethod: actionMethod,
|
|
276
|
+
routePath,
|
|
277
|
+
routePathRaw
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// fn
|
|
281
|
+
const self = this;
|
|
282
|
+
const fn = function (_req, _res, params, _store, searchParams) {
|
|
283
|
+
const ctx = this;
|
|
284
|
+
ctx.route = _route;
|
|
285
|
+
ctx.request.params = params;
|
|
286
|
+
ctx.request.query = searchParams;
|
|
287
|
+
if (!_route[SymbolRouteComposeMiddlewaresCache]) {
|
|
288
|
+
_route[SymbolRouteComposeMiddlewaresCache] = self._registerComposeMiddlewares(ctx);
|
|
289
|
+
}
|
|
290
|
+
return _route[SymbolRouteComposeMiddlewaresCache](ctx);
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// register
|
|
294
|
+
app.router.on(_route.routeMethod.toUpperCase(), _route.routePath.toString(), fn);
|
|
295
|
+
}
|
|
296
|
+
_registerComposeMiddlewares(ctx) {
|
|
297
|
+
// start
|
|
298
|
+
const fnStart = routeStartMiddleware;
|
|
299
|
+
// mid: guard/interceptor/pipes/tail
|
|
300
|
+
const fnMid = [];
|
|
301
|
+
fnMid.push(middlewareGuard);
|
|
302
|
+
fnMid.push(middlewareInterceptor);
|
|
303
|
+
fnMid.push(middlewarePipe);
|
|
304
|
+
fnMid.push(routeTailDoneMiddleware);
|
|
305
|
+
// end: controller
|
|
306
|
+
const fnEnd = classControllerMiddleware;
|
|
307
|
+
// compose
|
|
308
|
+
return this.app.bean.onion.middleware.compose(ctx, fnStart, fnMid, fnEnd);
|
|
309
|
+
}
|
|
310
|
+
}) || _class$3) || _class$3);
|
|
311
|
+
function classControllerMiddleware(ctx) {
|
|
312
|
+
const beanFullName = ctx.getControllerBeanFullName();
|
|
313
|
+
const handlerName = ctx.getHandler().name;
|
|
314
|
+
const controller = ctx.app.bean._getBean(beanFullName);
|
|
315
|
+
return controller[handlerName](...(ctx[SymbolRouteHandlersArgumentsValue] || []));
|
|
316
|
+
}
|
|
317
|
+
async function routeStartMiddleware(ctx, next) {
|
|
318
|
+
// next
|
|
319
|
+
const res = await next();
|
|
320
|
+
// invoke callbackes: handle secondly
|
|
321
|
+
await ctx.commitDone();
|
|
322
|
+
// ok
|
|
323
|
+
return res;
|
|
324
|
+
}
|
|
325
|
+
async function routeTailDoneMiddleware(ctx, next) {
|
|
326
|
+
// next
|
|
327
|
+
const res = await next();
|
|
328
|
+
// invoke callbackes: handle firstly
|
|
329
|
+
await ctx.commitDone();
|
|
330
|
+
// ok
|
|
331
|
+
return res;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// _registerInner(route, middlewaresLocal) {
|
|
335
|
+
// // app
|
|
336
|
+
// const app = this.app;
|
|
337
|
+
// // args
|
|
338
|
+
// let args: any[] = [];
|
|
339
|
+
// // middlewares: start
|
|
340
|
+
// const fnStart = async (ctx: VonaContext, next: Next) => {
|
|
341
|
+
// // route
|
|
342
|
+
// ctx.route = route;
|
|
343
|
+
// // next
|
|
344
|
+
// const res = await next();
|
|
345
|
+
// // invoke callbackes: handle secondly
|
|
346
|
+
// await ctx.commitDone();
|
|
347
|
+
// // ok
|
|
348
|
+
// return res;
|
|
349
|
+
// };
|
|
350
|
+
// fnStart._name = 'start';
|
|
351
|
+
// args.push(fnStart);
|
|
352
|
+
|
|
353
|
+
// // middlewares: globals
|
|
354
|
+
// args.push(...app.bean.onion.middleware.composedOnionsGlobal);
|
|
355
|
+
// // middlewares: guard/interceptor/pipes
|
|
356
|
+
// args.push(middlewareGuard);
|
|
357
|
+
// args.push(middlewareInterceptor);
|
|
358
|
+
// args.push(middlewarePipe);
|
|
359
|
+
|
|
360
|
+
// // middlewares: tailDone
|
|
361
|
+
// const fnTailDone = async (ctx, next) => {
|
|
362
|
+
// // next
|
|
363
|
+
// const res = await next();
|
|
364
|
+
// // invoke callbackes: handle firstly
|
|
365
|
+
// await ctx.commitDone();
|
|
366
|
+
// // ok
|
|
367
|
+
// return res;
|
|
368
|
+
// };
|
|
369
|
+
// fnTailDone._name = 'tailDone';
|
|
370
|
+
// args.push(fnTailDone);
|
|
371
|
+
|
|
372
|
+
// // middlewares
|
|
373
|
+
// if (middlewaresLocal.length > 0) {
|
|
374
|
+
// args = args.concat(middlewaresLocal);
|
|
375
|
+
// }
|
|
376
|
+
|
|
377
|
+
// // load
|
|
378
|
+
// if (route.routeName) {
|
|
379
|
+
// app.router[route.routeMethod](route.routeName, route.routePath, ...args);
|
|
380
|
+
// } else {
|
|
381
|
+
// app.router[route.routeMethod](route.routePath, ...args);
|
|
382
|
+
// }
|
|
383
|
+
// }
|
|
384
|
+
|
|
385
|
+
var _dec$2, _dec2$2, _class$2;
|
|
386
|
+
let StartupListen = (_dec$2 = Startup({
|
|
387
|
+
after: true
|
|
388
|
+
}), _dec2$2 = BeanInfo({
|
|
389
|
+
module: "a-web"
|
|
390
|
+
}), _dec$2(_class$2 = _dec2$2(_class$2 = class StartupListen extends BeanBase {
|
|
391
|
+
async execute() {
|
|
392
|
+
if (!this.app.config.server.listen.disable) {
|
|
393
|
+
this.app.server = this._listen(this.app.config.server.listen.port, this.app.config.server.listen.hostname);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
_listen(port, hostname) {
|
|
397
|
+
const server = http.createServer(this._callback());
|
|
398
|
+
return server.listen(port, hostname);
|
|
399
|
+
}
|
|
400
|
+
_callback() {
|
|
401
|
+
const fn = compose(this.app.middleware);
|
|
402
|
+
if (!this.app.listenerCount('error')) this.app.on('error', this.app.onerror);
|
|
403
|
+
return (req, res) => {
|
|
404
|
+
return this.app.bean.executor.newCtx(() => {
|
|
405
|
+
return cast(this.app).handleRequest(this.app.ctx, fn);
|
|
406
|
+
}, {
|
|
407
|
+
dbInfo: {
|
|
408
|
+
level: 0
|
|
409
|
+
},
|
|
410
|
+
innerAccess: false,
|
|
411
|
+
req,
|
|
412
|
+
res
|
|
413
|
+
}); // not set instanceName
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
}) || _class$2) || _class$2);
|
|
417
|
+
|
|
418
|
+
function config(_app) {
|
|
419
|
+
return {
|
|
420
|
+
router: {
|
|
421
|
+
maxParamLength: 500,
|
|
422
|
+
defaultRoute: (_req, _res) => {}
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const __ThisModule__ = 'a-web';
|
|
428
|
+
|
|
429
|
+
const SymbolRouter = Symbol('SymbolRouter');
|
|
430
|
+
class Main extends BeanSimple {
|
|
431
|
+
constructor(...args) {
|
|
432
|
+
super(...args);
|
|
433
|
+
this[SymbolRouter] = void 0;
|
|
434
|
+
}
|
|
435
|
+
async moduleLoading() {}
|
|
436
|
+
async moduleLoaded() {
|
|
437
|
+
const config = this.bean.scope(__ThisModule__).config;
|
|
438
|
+
const self = this;
|
|
439
|
+
// router
|
|
440
|
+
Object.defineProperty(this.app, 'router', {
|
|
441
|
+
get() {
|
|
442
|
+
if (!self[SymbolRouter]) {
|
|
443
|
+
self[SymbolRouter] = Router(config.router);
|
|
444
|
+
}
|
|
445
|
+
return self[SymbolRouter];
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
// register controllers
|
|
449
|
+
for (const controller of this.bean.onion.controller.getOnionsEnabled()) {
|
|
450
|
+
this.bean.router.registerController(controller.beanOptions.module, controller.beanOptions.beanClass);
|
|
451
|
+
}
|
|
452
|
+
// middleware: system
|
|
453
|
+
const middlewares = this.bean.onion.middlewareSystem.getOnionsEnabledWrapped(item => {
|
|
454
|
+
return this._wrapOnion(item);
|
|
455
|
+
});
|
|
456
|
+
this.app.use(compose(middlewares));
|
|
457
|
+
// middleware: router
|
|
458
|
+
this.app[SymbolRouterMiddleware] = routerMiddleware(this[SymbolRouter]);
|
|
459
|
+
this.app.use(this.app[SymbolRouterMiddleware]);
|
|
460
|
+
}
|
|
461
|
+
async configLoaded(_config) {}
|
|
462
|
+
_wrapOnion(item) {
|
|
463
|
+
const fn = (_ctx, next) => {
|
|
464
|
+
const options = item.beanOptions.options;
|
|
465
|
+
if (!this.bean.onion.checkOnionOptionsEnabled(options, this.ctx.path)) {
|
|
466
|
+
return next();
|
|
467
|
+
}
|
|
468
|
+
// execute
|
|
469
|
+
const beanFullName = item.beanOptions.beanFullName;
|
|
470
|
+
const beanInstance = this.app.bean._getBean(beanFullName);
|
|
471
|
+
if (!beanInstance) {
|
|
472
|
+
throw new Error(`middlewareSystem bean not found: ${beanFullName}`);
|
|
473
|
+
}
|
|
474
|
+
return beanInstance.execute(options, next);
|
|
475
|
+
};
|
|
476
|
+
fn._name = item.name;
|
|
477
|
+
return fn;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
function routerMiddleware(router) {
|
|
481
|
+
return function (ctx) {
|
|
482
|
+
return new Promise((resolve, reject) => {
|
|
483
|
+
router.lookup(ctx.req, ctx.res, ctx, (err, result) => {
|
|
484
|
+
if (err) reject(err);
|
|
485
|
+
resolve(result);
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
var _dec$1, _dec2$1, _class$1;
|
|
492
|
+
let ServiceWeb = (_dec$1 = Service$1(), _dec2$1 = BeanInfo({
|
|
493
|
+
module: "a-web"
|
|
494
|
+
}), _dec$1(_class$1 = _dec2$1(_class$1 = class ServiceWeb extends BeanBase {
|
|
495
|
+
combineControllerActionApiPath(controller, actionKey, prefix, simplify) {
|
|
496
|
+
// beanOptions
|
|
497
|
+
const beanOptions = appResource.getBean(controller);
|
|
498
|
+
if (!beanOptions) return undefined;
|
|
499
|
+
// controllerPath
|
|
500
|
+
const controllerOptions = beanOptions.options;
|
|
501
|
+
const controllerPath = controllerOptions.path;
|
|
502
|
+
// actionPath
|
|
503
|
+
const handlerMetadata = appMetadata.getMetadata(SymbolRequestMappingHandler$1, controller.prototype, actionKey);
|
|
504
|
+
const actionPath = handlerMetadata.path || '';
|
|
505
|
+
// combine
|
|
506
|
+
return this.app.util.combineApiPathControllerAndAction(beanOptions.module, controllerPath, actionPath, prefix, simplify);
|
|
507
|
+
}
|
|
508
|
+
}) || _class$1) || _class$1);
|
|
509
|
+
|
|
510
|
+
var _dec, _dec2, _class;
|
|
511
|
+
let ScopeModuleAWeb = (_dec = Scope(), _dec2 = BeanInfo({
|
|
512
|
+
module: "a-web"
|
|
513
|
+
}), _dec(_class = _dec2(_class = class ScopeModuleAWeb extends BeanScopeBase {}) || _class) || _class);
|
|
514
|
+
|
|
515
|
+
/** scope: end */
|
|
516
|
+
|
|
517
|
+
function Controller(path, options) {
|
|
518
|
+
if (typeof path === 'string') {
|
|
519
|
+
options = Object.assign({}, options, {
|
|
520
|
+
path
|
|
521
|
+
});
|
|
522
|
+
} else {
|
|
523
|
+
options = path || {};
|
|
524
|
+
}
|
|
525
|
+
return createBeanDecorator('controller', options, false, false, target => {
|
|
526
|
+
// IOpenApiOptions
|
|
527
|
+
const optionsMeta = appMetadata.getOwnMetadataMap(false, SymbolOpenApiOptions, target);
|
|
528
|
+
for (const key of ['exclude', 'tags']) {
|
|
529
|
+
if (options[key] !== undefined) optionsMeta[key] = options[key];
|
|
530
|
+
}
|
|
531
|
+
// IOpenApiOptions
|
|
532
|
+
mergeActionsOpenAPIMetadata(target);
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
function Service() {
|
|
536
|
+
return createBeanDecorator('service');
|
|
537
|
+
}
|
|
538
|
+
function Dto(options) {
|
|
539
|
+
return createBeanDecorator('dto', options, false, false, target => {
|
|
540
|
+
mergeFieldsOpenAPIMetadata(target);
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
function mergeActionsOpenAPIMetadata(target) {
|
|
544
|
+
// beanOptions
|
|
545
|
+
const beanOptions = appResource.getBean(target);
|
|
546
|
+
const actions = cast(beanOptions?.options)?.actions;
|
|
547
|
+
if (!actions) return;
|
|
548
|
+
for (const key in actions) {
|
|
549
|
+
const action = actions[key];
|
|
550
|
+
if (!action) continue;
|
|
551
|
+
const options = appMetadata.getOwnMetadataMap(false, SymbolOpenApiOptions, target.prototype, key);
|
|
552
|
+
deepExtend(options, action);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const defaultMetadata = {
|
|
557
|
+
method: 'get',
|
|
558
|
+
path: '',
|
|
559
|
+
options: undefined
|
|
560
|
+
};
|
|
561
|
+
function RequestMapping(metadata = defaultMetadata) {
|
|
562
|
+
const path = metadata.path || '';
|
|
563
|
+
const method = metadata.method || 'get';
|
|
564
|
+
const options = metadata.options;
|
|
565
|
+
return (target, prop, descriptor) => {
|
|
566
|
+
appMetadata.defineMetadata(SymbolRequestMappingHandler, {
|
|
567
|
+
path,
|
|
568
|
+
method
|
|
569
|
+
}, target, prop);
|
|
570
|
+
if (options) {
|
|
571
|
+
const optionsMeta = appMetadata.getOwnMetadataMap(false, SymbolOpenApiOptions, target, prop);
|
|
572
|
+
Object.assign(optionsMeta, options);
|
|
573
|
+
}
|
|
574
|
+
return descriptor;
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
function createMappingDecorator(method) {
|
|
578
|
+
return (path, options) => {
|
|
579
|
+
if (path && typeof path === 'object') {
|
|
580
|
+
options = path;
|
|
581
|
+
path = undefined;
|
|
582
|
+
}
|
|
583
|
+
return RequestMapping({
|
|
584
|
+
method,
|
|
585
|
+
path,
|
|
586
|
+
options
|
|
587
|
+
});
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
const Post = createMappingDecorator('post');
|
|
591
|
+
const Get = createMappingDecorator('get');
|
|
592
|
+
const Delete = createMappingDecorator('delete');
|
|
593
|
+
const Put = createMappingDecorator('put');
|
|
594
|
+
const Patch = createMappingDecorator('patch');
|
|
595
|
+
const Options = createMappingDecorator('options');
|
|
596
|
+
const Head = createMappingDecorator('head');
|
|
597
|
+
const Web = {
|
|
598
|
+
post: Post,
|
|
599
|
+
get: Get,
|
|
600
|
+
delete: Delete,
|
|
601
|
+
put: Put,
|
|
602
|
+
patch: Patch,
|
|
603
|
+
options: Options,
|
|
604
|
+
head: Head
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
function $apiPath(path) {
|
|
608
|
+
return path;
|
|
609
|
+
}
|
|
610
|
+
function $apiPathAndCombineParamsAndQuery(path, options) {
|
|
611
|
+
return combineParamsAndQuery(path, options);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
export { $apiPath, $apiPathAndCombineParamsAndQuery, BeanRouter, Controller, Dto, Main, RequestMapping, ScopeModuleAWeb, Service, ServiceWeb, StartupListen, SymbolRequestMappingHandler, Web, config, mergeActionsOpenAPIMetadata };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { IOpenApiOptions } from 'vona-module-a-openapi';
|
|
2
|
-
import {
|
|
2
|
+
import type { TypeRequestMethod } from '../../types/request.ts';
|
|
3
3
|
export interface RequestMappingMetadata {
|
|
4
4
|
path?: string;
|
|
5
|
-
method?:
|
|
5
|
+
method?: TypeRequestMethod;
|
|
6
6
|
options?: IOpenApiOptions;
|
|
7
7
|
}
|
|
8
8
|
export declare function RequestMapping(metadata?: RequestMappingMetadata): MethodDecorator;
|
package/dist/types/request.d.ts
CHANGED
|
@@ -1,11 +1,2 @@
|
|
|
1
1
|
export declare const SymbolRequestMappingHandler: unique symbol;
|
|
2
2
|
export type TypeRequestMethod = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head';
|
|
3
|
-
export declare enum RequestMethod {
|
|
4
|
-
GET = "get",
|
|
5
|
-
POST = "post",
|
|
6
|
-
PUT = "put",
|
|
7
|
-
DELETE = "delete",
|
|
8
|
-
PATCH = "patch",
|
|
9
|
-
OPTIONS = "options",
|
|
10
|
-
HEAD = "head"
|
|
11
|
-
}
|
package/dist/types/router.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type Router from 'find-my-way';
|
|
2
2
|
import type { Constructable } from 'vona';
|
|
3
|
-
import type {
|
|
3
|
+
import type { TypeRequestMethod } from './request.ts';
|
|
4
4
|
export interface ContextRouteMetadata {
|
|
5
5
|
meta: any;
|
|
6
6
|
}
|
|
@@ -12,7 +12,7 @@ export interface ContextRoute {
|
|
|
12
12
|
controllerBeanFullName: string;
|
|
13
13
|
action: string;
|
|
14
14
|
route: ContextRouteMetadata;
|
|
15
|
-
routeMethod:
|
|
15
|
+
routeMethod: TypeRequestMethod;
|
|
16
16
|
routePath: string | RegExp;
|
|
17
17
|
routePathRaw: string | RegExp;
|
|
18
18
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vona-module-a-web",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "5.0.
|
|
4
|
+
"version": "5.0.12",
|
|
5
5
|
"title": "a-web",
|
|
6
6
|
"vonaModule": {
|
|
7
7
|
"capabilities": {
|
|
@@ -61,6 +61,6 @@
|
|
|
61
61
|
},
|
|
62
62
|
"scripts": {
|
|
63
63
|
"clean": "rimraf dist tsconfig.build.tsbuildinfo",
|
|
64
|
-
"tsc:publish": "npm run clean && tsc -p tsconfig.build.json"
|
|
64
|
+
"tsc:publish": "npm run clean && vona :bin:buildModule && tsc -p tsconfig.build.json"
|
|
65
65
|
}
|
|
66
66
|
}
|