@pangza/core 1.1.5 → 1.1.7
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 +3 -3
- package/dist/Application/aop.d.ts +91 -0
- package/dist/Application/aop.d.ts.map +1 -0
- package/dist/Application/aop.js +274 -0
- package/dist/Application/aop.js.map +1 -0
- package/dist/Application/callbackArgs.js +20 -0
- package/dist/Application/callbackArgs.js.map +1 -1
- package/dist/Application/container.d.ts +1 -0
- package/dist/Application/container.d.ts.map +1 -1
- package/dist/Application/container.js +6 -0
- package/dist/Application/container.js.map +1 -1
- package/dist/Application/decorators.d.ts +15 -0
- package/dist/Application/decorators.d.ts.map +1 -1
- package/dist/Application/decorators.js +26 -0
- package/dist/Application/decorators.js.map +1 -1
- package/dist/Application/filters.d.ts +67 -0
- package/dist/Application/filters.d.ts.map +1 -0
- package/dist/Application/filters.js +113 -0
- package/dist/Application/filters.js.map +1 -0
- package/dist/Application/index.d.ts +43 -5
- package/dist/Application/index.d.ts.map +1 -1
- package/dist/Application/index.js +166 -6
- package/dist/Application/index.js.map +1 -1
- package/dist/Application/interceptors.d.ts +61 -0
- package/dist/Application/interceptors.d.ts.map +1 -1
- package/dist/Application/interceptors.js +105 -0
- package/dist/Application/interceptors.js.map +1 -1
- package/dist/Application/pathMatch.d.ts +13 -0
- package/dist/Application/pathMatch.d.ts.map +1 -0
- package/dist/Application/pathMatch.js +90 -0
- package/dist/Application/pathMatch.js.map +1 -0
- package/dist/Application/types.d.ts +6 -2
- package/dist/Application/types.d.ts.map +1 -1
- package/dist/Application/types.js +2 -0
- package/dist/Application/types.js.map +1 -1
- package/dist/config/ConditionOnProperty.d.ts +8 -6
- package/dist/config/ConditionOnProperty.d.ts.map +1 -1
- package/dist/config/ConditionOnProperty.js +30 -10
- package/dist/config/ConditionOnProperty.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import type { Request, RequestHandler, Response } from "express";
|
|
3
|
+
export declare const WEB_FILTER_KEY: unique symbol;
|
|
4
|
+
/**
|
|
5
|
+
* Filter 链(对齐 Servlet FilterChain)。
|
|
6
|
+
* `await chain.doFilter(req, res)` 会跑完后续 Filter + 路由并等到响应结束。
|
|
7
|
+
*/
|
|
8
|
+
export interface FilterChain {
|
|
9
|
+
doFilter(req: Request, res: Response): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Servlet 风格 Filter:在 Dispatcher(路由)之外包裹请求。
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* class TimingFilter implements Filter {
|
|
16
|
+
* async doFilter(req, res, chain) {
|
|
17
|
+
* const t = Date.now();
|
|
18
|
+
* await chain.doFilter(req, res);
|
|
19
|
+
* console.log(req.path, Date.now() - t);
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
*/
|
|
23
|
+
export interface Filter {
|
|
24
|
+
doFilter(req: Request, res: Response, chain: FilterChain): void | Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
/** @WebFilter / addFilter 注册选项(对齐 FilterRegistrationBean) */
|
|
27
|
+
export interface FilterOptions {
|
|
28
|
+
/** 越小越靠前,默认 0 */
|
|
29
|
+
order?: number;
|
|
30
|
+
/** 生效路径,默认 `["/**"]` */
|
|
31
|
+
urlPatterns?: string[];
|
|
32
|
+
/** 排除路径 */
|
|
33
|
+
excludePatterns?: string[];
|
|
34
|
+
}
|
|
35
|
+
export interface FilterRegistration {
|
|
36
|
+
filter: Filter;
|
|
37
|
+
order: number;
|
|
38
|
+
urlPatterns: string[];
|
|
39
|
+
excludePatterns: string[];
|
|
40
|
+
}
|
|
41
|
+
export declare function isFilter(bean: unknown): bean is Filter;
|
|
42
|
+
export declare function addFilterRegistration(filter: Filter, options?: FilterOptions): void;
|
|
43
|
+
export declare function getFilterRegistrations(): readonly FilterRegistration[];
|
|
44
|
+
export declare function clearFilters(): void;
|
|
45
|
+
export declare function isFiltersMounted(): boolean;
|
|
46
|
+
export declare function markFiltersMounted(): void;
|
|
47
|
+
/** 按 order 升序得到注册表副本 */
|
|
48
|
+
export declare function sortedFilterRegistrations(): FilterRegistration[];
|
|
49
|
+
/**
|
|
50
|
+
* 将单个 Filter 转为 Express 中间件。
|
|
51
|
+
* `await chain.doFilter()` 在响应 `finish`/`close` 后 resolve,便于写 after 逻辑。
|
|
52
|
+
*/
|
|
53
|
+
export declare function createFilterMiddleware(reg: FilterRegistration): RequestHandler;
|
|
54
|
+
/**
|
|
55
|
+
* 类装饰器:标记 Servlet 风格 Filter(类加载时自动注册)。
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* @WebFilter({ urlPatterns: ["/api/**"], order: 1 })
|
|
59
|
+
* class TimingFilter implements Filter {
|
|
60
|
+
* async doFilter(req, res, chain) {
|
|
61
|
+
* await chain.doFilter(req, res);
|
|
62
|
+
* }
|
|
63
|
+
* }
|
|
64
|
+
*/
|
|
65
|
+
export declare function WebFilter(options?: FilterOptions): ClassDecorator;
|
|
66
|
+
export declare function getWebFilterOptions(ctor: Function): FilterOptions;
|
|
67
|
+
//# sourceMappingURL=filters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filters.d.ts","sourceRoot":"","sources":["../../src/Application/filters.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAgB,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG/E,eAAO,MAAM,cAAc,eAAyC,CAAC;AAErE;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtD;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,CACN,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,KAAK,EAAE,WAAW,GACjB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED,6DAA6D;AAC7D,MAAM,WAAW,aAAa;IAC5B,iBAAiB;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW;IACX,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAKD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,MAAM,CAMtD;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,aAAkB,GAC1B,IAAI,CASN;AAED,wBAAgB,sBAAsB,IAAI,SAAS,kBAAkB,EAAE,CAEtE;AAED,wBAAgB,YAAY,IAAI,IAAI,CAGnC;AAED,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED,wBAAwB;AACxB,wBAAgB,yBAAyB,IAAI,kBAAkB,EAAE,CAEhE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,kBAAkB,GACtB,cAAc,CAuChB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,aAAkB,GAAG,cAAc,CASrE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,GAAG,aAAa,CAEjE"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WEB_FILTER_KEY = void 0;
|
|
4
|
+
exports.isFilter = isFilter;
|
|
5
|
+
exports.addFilterRegistration = addFilterRegistration;
|
|
6
|
+
exports.getFilterRegistrations = getFilterRegistrations;
|
|
7
|
+
exports.clearFilters = clearFilters;
|
|
8
|
+
exports.isFiltersMounted = isFiltersMounted;
|
|
9
|
+
exports.markFiltersMounted = markFiltersMounted;
|
|
10
|
+
exports.sortedFilterRegistrations = sortedFilterRegistrations;
|
|
11
|
+
exports.createFilterMiddleware = createFilterMiddleware;
|
|
12
|
+
exports.WebFilter = WebFilter;
|
|
13
|
+
exports.getWebFilterOptions = getWebFilterOptions;
|
|
14
|
+
require("reflect-metadata");
|
|
15
|
+
const pathMatch_1 = require("./pathMatch");
|
|
16
|
+
exports.WEB_FILTER_KEY = Symbol.for("pangza.webFilter.options");
|
|
17
|
+
const registrations = [];
|
|
18
|
+
let filtersMounted = false;
|
|
19
|
+
function isFilter(bean) {
|
|
20
|
+
return (!!bean &&
|
|
21
|
+
typeof bean === "object" &&
|
|
22
|
+
typeof bean.doFilter === "function");
|
|
23
|
+
}
|
|
24
|
+
function addFilterRegistration(filter, options = {}) {
|
|
25
|
+
registrations.push({
|
|
26
|
+
filter,
|
|
27
|
+
order: options.order ?? 0,
|
|
28
|
+
urlPatterns: options.urlPatterns?.length
|
|
29
|
+
? options.urlPatterns
|
|
30
|
+
: ["/**"],
|
|
31
|
+
excludePatterns: options.excludePatterns ?? [],
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function getFilterRegistrations() {
|
|
35
|
+
return registrations;
|
|
36
|
+
}
|
|
37
|
+
function clearFilters() {
|
|
38
|
+
registrations.length = 0;
|
|
39
|
+
filtersMounted = false;
|
|
40
|
+
}
|
|
41
|
+
function isFiltersMounted() {
|
|
42
|
+
return filtersMounted;
|
|
43
|
+
}
|
|
44
|
+
function markFiltersMounted() {
|
|
45
|
+
filtersMounted = true;
|
|
46
|
+
}
|
|
47
|
+
/** 按 order 升序得到注册表副本 */
|
|
48
|
+
function sortedFilterRegistrations() {
|
|
49
|
+
return [...registrations].sort((a, b) => a.order - b.order);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 将单个 Filter 转为 Express 中间件。
|
|
53
|
+
* `await chain.doFilter()` 在响应 `finish`/`close` 后 resolve,便于写 after 逻辑。
|
|
54
|
+
*/
|
|
55
|
+
function createFilterMiddleware(reg) {
|
|
56
|
+
return (req, res, next) => {
|
|
57
|
+
if (!(0, pathMatch_1.matchPathPatterns)(req.path, reg.urlPatterns, reg.excludePatterns)) {
|
|
58
|
+
next();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const chain = {
|
|
62
|
+
doFilter: (_r = req, s = res) => new Promise((resolve, reject) => {
|
|
63
|
+
let settled = false;
|
|
64
|
+
const finish = () => {
|
|
65
|
+
if (settled)
|
|
66
|
+
return;
|
|
67
|
+
settled = true;
|
|
68
|
+
resolve();
|
|
69
|
+
};
|
|
70
|
+
s.once("finish", finish);
|
|
71
|
+
s.once("close", finish);
|
|
72
|
+
next((err) => {
|
|
73
|
+
if (err) {
|
|
74
|
+
s.removeListener("finish", finish);
|
|
75
|
+
s.removeListener("close", finish);
|
|
76
|
+
reject(err);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// 下游已同步结束响应时尽快放开 after;否则等 finish
|
|
80
|
+
if (s.writableEnded) {
|
|
81
|
+
finish();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}),
|
|
85
|
+
};
|
|
86
|
+
Promise.resolve(reg.filter.doFilter(req, res, chain)).catch((err) => {
|
|
87
|
+
next(err);
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 类装饰器:标记 Servlet 风格 Filter(类加载时自动注册)。
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* @WebFilter({ urlPatterns: ["/api/**"], order: 1 })
|
|
96
|
+
* class TimingFilter implements Filter {
|
|
97
|
+
* async doFilter(req, res, chain) {
|
|
98
|
+
* await chain.doFilter(req, res);
|
|
99
|
+
* }
|
|
100
|
+
* }
|
|
101
|
+
*/
|
|
102
|
+
function WebFilter(options = {}) {
|
|
103
|
+
return (ctor) => {
|
|
104
|
+
const Ctor = ctor;
|
|
105
|
+
Reflect.defineMetadata(exports.WEB_FILTER_KEY, options, Ctor);
|
|
106
|
+
const { default: Application } = require("./index");
|
|
107
|
+
Application.registerFilter(Ctor);
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function getWebFilterOptions(ctor) {
|
|
111
|
+
return Reflect.getMetadata(exports.WEB_FILTER_KEY, ctor) ?? {};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=filters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filters.js","sourceRoot":"","sources":["../../src/Application/filters.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import type { RouteOption } from './types';
|
|
3
3
|
import { ParamType } from './types';
|
|
4
|
-
import { type RequestInterceptor, type ResponseInterceptor } from './interceptors';
|
|
4
|
+
import { type RequestInterceptor, type ResponseInterceptor, type HandlerInterceptor, type InterceptorOptions } from './interceptors';
|
|
5
|
+
import { type Filter, type FilterOptions } from './filters';
|
|
5
6
|
export declare function applicationStart(): import("node:http").Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse>;
|
|
6
7
|
export declare class Application {
|
|
7
8
|
private static routerMounted;
|
|
@@ -16,6 +17,9 @@ export declare class Application {
|
|
|
16
17
|
private static ormRegistered;
|
|
17
18
|
/** 已注册过的 Controller,防止重复挂路由 */
|
|
18
19
|
private static registeredControllers;
|
|
20
|
+
/** 已注册过的 Filter / Interceptor 类 */
|
|
21
|
+
private static registeredFilters;
|
|
22
|
+
private static registeredInterceptors;
|
|
19
23
|
/** 已 require 过的模块文件 */
|
|
20
24
|
private static loadedFiles;
|
|
21
25
|
/**
|
|
@@ -51,14 +55,43 @@ export declare class Application {
|
|
|
51
55
|
* });
|
|
52
56
|
*/
|
|
53
57
|
static addResponseInterceptor(fn: ResponseInterceptor): typeof Application;
|
|
54
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* 注册 Servlet 风格 Filter(实例或类)。
|
|
60
|
+
* start() 时按 order 挂到路由之前;也可用 `@WebFilter()`。
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* Application.addFilter(new TimingFilter(), { urlPatterns: ["/api/**"], order: 1 });
|
|
64
|
+
*/
|
|
65
|
+
static addFilter(filter: Filter | (new () => Filter), options?: FilterOptions): typeof Application;
|
|
66
|
+
/**
|
|
67
|
+
* 注册 Spring MVC 风格 HandlerInterceptor(实例或类)。
|
|
68
|
+
* 也可用 `@Interceptor()`。
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* Application.addInterceptor(new LogInterceptor(), { include: ["/api/**"] });
|
|
72
|
+
*/
|
|
73
|
+
static addInterceptor(interceptor: HandlerInterceptor | (new () => HandlerInterceptor), options?: InterceptorOptions): typeof Application;
|
|
74
|
+
/** 装饰器 / 扫描:注册 Filter 类 */
|
|
75
|
+
static registerFilter(Ctor: new () => object, options?: FilterOptions): typeof Application;
|
|
76
|
+
/** 装饰器 / 扫描:注册 HandlerInterceptor 类 */
|
|
77
|
+
static registerInterceptor(Ctor: new () => object, options?: InterceptorOptions): typeof Application;
|
|
78
|
+
/**
|
|
79
|
+
* 将已注册 Filter 按 order 挂到 Express(路由之前)。
|
|
80
|
+
* start() 会自动调用;一般无需手动。
|
|
81
|
+
*/
|
|
82
|
+
static mountFilters(): typeof Application;
|
|
83
|
+
/** 清空函数式请求/响应拦截器与 HandlerInterceptor 注册 */
|
|
55
84
|
static clearInterceptors(): typeof Application;
|
|
85
|
+
/** 清空 Filter 注册(需在 start / mountFilters 之前) */
|
|
86
|
+
static clearFilters(): typeof Application;
|
|
56
87
|
/**
|
|
57
88
|
* 追加模块扫描目录(可多次调用)。
|
|
58
89
|
* 目录内带 @Controller 的类会被自动注册进路由。
|
|
90
|
+
* 推荐 `.scan(__dirname)`:ts-node 跑 src 时扫源码,`node dist/main.js` 时扫编译产物。
|
|
59
91
|
*
|
|
60
92
|
* @example
|
|
61
93
|
* Application
|
|
94
|
+
* .scan(__dirname)
|
|
62
95
|
* .scan('src/business')
|
|
63
96
|
* .scan('src/modules', 'src/plugins')
|
|
64
97
|
* .registry(...).start();
|
|
@@ -84,7 +117,7 @@ export declare class Application {
|
|
|
84
117
|
static getScanRoots(): string[];
|
|
85
118
|
/**
|
|
86
119
|
* 启动服务:
|
|
87
|
-
* 自动 loadControllers → routes → listen
|
|
120
|
+
* 自动 loadControllers → mountFilters → routes → listen
|
|
88
121
|
* 使用者通常只需 registry(...).start()
|
|
89
122
|
*/
|
|
90
123
|
static start(): typeof Application;
|
|
@@ -144,9 +177,14 @@ export declare class Application {
|
|
|
144
177
|
export default Application;
|
|
145
178
|
export { ParamType };
|
|
146
179
|
export type { RouteOption, ApplicationInit, ApplicationDestroy } from './types';
|
|
147
|
-
export type { RequestInterceptor, ResponseInterceptor, RequestInterceptorContext, ResponseInterceptorContext, } from './interceptors';
|
|
180
|
+
export type { RequestInterceptor, ResponseInterceptor, RequestInterceptorContext, ResponseInterceptorContext, HandlerInterceptor, HandlerInfo, InterceptorOptions, } from './interceptors';
|
|
181
|
+
export { Interceptor } from './interceptors';
|
|
182
|
+
export type { Filter, FilterChain, FilterOptions, } from './filters';
|
|
183
|
+
export { WebFilter } from './filters';
|
|
184
|
+
export type { MethodInvocation, MethodInvocationContext, AroundAdvice, BeforeAdvice, AfterAdvice, AfterReturningAdvice, AfterThrowingAdvice, AdviceOptions, } from './aop';
|
|
185
|
+
export { Around, Before, After, AfterReturning, AfterThrowing, createAroundDecorator, createBeforeDecorator, createAfterDecorator, createAfterReturningDecorator, createAfterThrowingDecorator, markAdvice, registerAroundAdvice, createMarkDecorator, getMethodInvocationContext, getMethodAdvices, } from './aop';
|
|
148
186
|
export { runApplicationInits, runApplicationDestroys, hookProcessDestroy, isApplicationInit, isApplicationDestroy, } from './lifecycle';
|
|
149
|
-
export { Controller, GetMapping, PostMapping, PutMapping, DeleteMapping, AuthCheckLogin, AuthCheckRole, AuthCheckPermission, AuthIgnore, Log, Flux, RequestBody, RequestQuery, RequestPath, RequestHeader, RequestCookie, Value, } from "./decorators";
|
|
187
|
+
export { Controller, GetMapping, PostMapping, PutMapping, DeleteMapping, AuthCheckLogin, AuthCheckRole, AuthCheckPermission, AuthIgnore, Log, Flux, RequestBody, RequestQuery, RequestPath, RequestHeader, RequestCookie, RequestForm, Value, } from "./decorators";
|
|
150
188
|
export { Container } from "./container";
|
|
151
189
|
export type { Ctor } from "./container";
|
|
152
190
|
export { Component, Resource, Service, Inject, } from "./iocDecorators";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Application/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAqC,MAAM,SAAS,CAAC;AAyB5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAQpC,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Application/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,7 +36,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.
|
|
39
|
+
exports.registerBeansFromComponent = exports.getBeanMethods = exports.Bean = exports.Inject = exports.Service = exports.Resource = exports.Component = exports.Container = exports.Value = exports.RequestForm = exports.RequestCookie = exports.RequestHeader = exports.RequestPath = exports.RequestQuery = exports.RequestBody = exports.Flux = exports.Log = exports.AuthIgnore = exports.AuthCheckPermission = exports.AuthCheckRole = exports.AuthCheckLogin = exports.DeleteMapping = exports.PutMapping = exports.PostMapping = exports.GetMapping = exports.Controller = exports.isApplicationDestroy = exports.isApplicationInit = exports.hookProcessDestroy = exports.runApplicationDestroys = exports.runApplicationInits = exports.getMethodAdvices = exports.getMethodInvocationContext = exports.createMarkDecorator = exports.registerAroundAdvice = exports.markAdvice = exports.createAfterThrowingDecorator = exports.createAfterReturningDecorator = exports.createAfterDecorator = exports.createBeforeDecorator = exports.createAroundDecorator = exports.AfterThrowing = exports.AfterReturning = exports.After = exports.Before = exports.Around = exports.WebFilter = exports.Interceptor = exports.ParamType = exports.Application = void 0;
|
|
40
|
+
exports.MAPPER_DELEGATE_METHODS = exports.BaseService = void 0;
|
|
40
41
|
exports.applicationStart = applicationStart;
|
|
41
42
|
const express_1 = __importStar(require("express"));
|
|
42
43
|
const fs_1 = __importDefault(require("fs"));
|
|
@@ -56,6 +57,8 @@ const lifecycle_1 = require("./lifecycle");
|
|
|
56
57
|
const processGuards_1 = require("./processGuards");
|
|
57
58
|
const warmup_1 = require("./warmup");
|
|
58
59
|
const interceptors_1 = require("./interceptors");
|
|
60
|
+
const filters_1 = require("./filters");
|
|
61
|
+
const aop_1 = require("./aop");
|
|
59
62
|
/** 可选分包:未安装时鉴权/审计/限流/ORM 相关能力降级跳过 */
|
|
60
63
|
function validateMod() {
|
|
61
64
|
return (0, optional_1.optionalRequire)('@pangza/validate');
|
|
@@ -176,17 +179,98 @@ class Application {
|
|
|
176
179
|
(0, interceptors_1.addResponseInterceptor)(fn);
|
|
177
180
|
return this;
|
|
178
181
|
}
|
|
179
|
-
/**
|
|
182
|
+
/**
|
|
183
|
+
* 注册 Servlet 风格 Filter(实例或类)。
|
|
184
|
+
* start() 时按 order 挂到路由之前;也可用 `@WebFilter()`。
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* Application.addFilter(new TimingFilter(), { urlPatterns: ["/api/**"], order: 1 });
|
|
188
|
+
*/
|
|
189
|
+
static addFilter(filter, options) {
|
|
190
|
+
if (typeof filter === "function") {
|
|
191
|
+
return this.registerFilter(filter, options);
|
|
192
|
+
}
|
|
193
|
+
(0, filters_1.addFilterRegistration)(filter, options);
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* 注册 Spring MVC 风格 HandlerInterceptor(实例或类)。
|
|
198
|
+
* 也可用 `@Interceptor()`。
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* Application.addInterceptor(new LogInterceptor(), { include: ["/api/**"] });
|
|
202
|
+
*/
|
|
203
|
+
static addInterceptor(interceptor, options) {
|
|
204
|
+
if (typeof interceptor === "function") {
|
|
205
|
+
return this.registerInterceptor(interceptor, options);
|
|
206
|
+
}
|
|
207
|
+
(0, interceptors_1.addInterceptorRegistration)(interceptor, options);
|
|
208
|
+
return this;
|
|
209
|
+
}
|
|
210
|
+
/** 装饰器 / 扫描:注册 Filter 类 */
|
|
211
|
+
static registerFilter(Ctor, options) {
|
|
212
|
+
if (this.registeredFilters.has(Ctor)) {
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
215
|
+
this.registeredFilters.add(Ctor);
|
|
216
|
+
const { Container } = require("./container");
|
|
217
|
+
Container.bindClass(Ctor);
|
|
218
|
+
const instance = Container.get(Ctor);
|
|
219
|
+
if (!(0, filters_1.isFilter)(instance)) {
|
|
220
|
+
throw new Error(`[Application] ${Ctor.name} 需实现 Filter.doFilter`);
|
|
221
|
+
}
|
|
222
|
+
(0, filters_1.addFilterRegistration)(instance, options ?? (0, filters_1.getWebFilterOptions)(Ctor));
|
|
223
|
+
return this;
|
|
224
|
+
}
|
|
225
|
+
/** 装饰器 / 扫描:注册 HandlerInterceptor 类 */
|
|
226
|
+
static registerInterceptor(Ctor, options) {
|
|
227
|
+
if (this.registeredInterceptors.has(Ctor)) {
|
|
228
|
+
return this;
|
|
229
|
+
}
|
|
230
|
+
this.registeredInterceptors.add(Ctor);
|
|
231
|
+
const { Container } = require("./container");
|
|
232
|
+
Container.bindClass(Ctor);
|
|
233
|
+
const instance = Container.get(Ctor);
|
|
234
|
+
if (!(0, interceptors_1.isHandlerInterceptor)(instance)) {
|
|
235
|
+
throw new Error(`[Application] ${Ctor.name} 需实现 HandlerInterceptor 的 preHandle / postHandle / afterCompletion 之一`);
|
|
236
|
+
}
|
|
237
|
+
(0, interceptors_1.addInterceptorRegistration)(instance, options ?? (0, interceptors_1.getHandlerInterceptorOptions)(Ctor));
|
|
238
|
+
return this;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* 将已注册 Filter 按 order 挂到 Express(路由之前)。
|
|
242
|
+
* start() 会自动调用;一般无需手动。
|
|
243
|
+
*/
|
|
244
|
+
static mountFilters() {
|
|
245
|
+
if ((0, filters_1.isFiltersMounted)()) {
|
|
246
|
+
return this;
|
|
247
|
+
}
|
|
248
|
+
for (const reg of (0, filters_1.sortedFilterRegistrations)()) {
|
|
249
|
+
app.use((0, filters_1.createFilterMiddleware)(reg));
|
|
250
|
+
}
|
|
251
|
+
(0, filters_1.markFiltersMounted)();
|
|
252
|
+
return this;
|
|
253
|
+
}
|
|
254
|
+
/** 清空函数式请求/响应拦截器与 HandlerInterceptor 注册 */
|
|
180
255
|
static clearInterceptors() {
|
|
181
256
|
(0, interceptors_1.clearInterceptors)();
|
|
257
|
+
this.registeredInterceptors = new WeakSet();
|
|
258
|
+
return this;
|
|
259
|
+
}
|
|
260
|
+
/** 清空 Filter 注册(需在 start / mountFilters 之前) */
|
|
261
|
+
static clearFilters() {
|
|
262
|
+
(0, filters_1.clearFilters)();
|
|
263
|
+
this.registeredFilters = new WeakSet();
|
|
182
264
|
return this;
|
|
183
265
|
}
|
|
184
266
|
/**
|
|
185
267
|
* 追加模块扫描目录(可多次调用)。
|
|
186
268
|
* 目录内带 @Controller 的类会被自动注册进路由。
|
|
269
|
+
* 推荐 `.scan(__dirname)`:ts-node 跑 src 时扫源码,`node dist/main.js` 时扫编译产物。
|
|
187
270
|
*
|
|
188
271
|
* @example
|
|
189
272
|
* Application
|
|
273
|
+
* .scan(__dirname)
|
|
190
274
|
* .scan('src/business')
|
|
191
275
|
* .scan('src/modules', 'src/plugins')
|
|
192
276
|
* .registry(...).start();
|
|
@@ -253,7 +337,7 @@ class Application {
|
|
|
253
337
|
}
|
|
254
338
|
/**
|
|
255
339
|
* 启动服务:
|
|
256
|
-
* 自动 loadControllers → routes → listen
|
|
340
|
+
* 自动 loadControllers → mountFilters → routes → listen
|
|
257
341
|
* 使用者通常只需 registry(...).start()
|
|
258
342
|
*/
|
|
259
343
|
static start() {
|
|
@@ -261,6 +345,7 @@ class Application {
|
|
|
261
345
|
if (!this.controllersLoaded) {
|
|
262
346
|
this.loadControllers();
|
|
263
347
|
}
|
|
348
|
+
this.mountFilters();
|
|
264
349
|
this.routes();
|
|
265
350
|
applicationStart();
|
|
266
351
|
return this;
|
|
@@ -386,6 +471,10 @@ class Application {
|
|
|
386
471
|
"entity",
|
|
387
472
|
"mapper",
|
|
388
473
|
"service",
|
|
474
|
+
"filter",
|
|
475
|
+
"filters",
|
|
476
|
+
"interceptor",
|
|
477
|
+
"interceptors",
|
|
389
478
|
"controller",
|
|
390
479
|
"controllers",
|
|
391
480
|
"advice",
|
|
@@ -407,6 +496,12 @@ class Application {
|
|
|
407
496
|
if (!fs_1.default.existsSync(dir)) {
|
|
408
497
|
return;
|
|
409
498
|
}
|
|
499
|
+
// 无 ts-node/tsx 等 hook 时,require(.ts) 会 SyntaxError;只加载可执行的 JS
|
|
500
|
+
const canRequireTs = Boolean(require
|
|
501
|
+
.extensions?.[".ts"]);
|
|
502
|
+
const entryFile = require.main?.filename
|
|
503
|
+
? path_1.default.normalize(require.main.filename)
|
|
504
|
+
: "";
|
|
410
505
|
for (const entry of fs_1.default.readdirSync(dir, { withFileTypes: true })) {
|
|
411
506
|
const full = path_1.default.join(dir, entry.name);
|
|
412
507
|
if (entry.isDirectory()) {
|
|
@@ -422,7 +517,21 @@ class Application {
|
|
|
422
517
|
entry.name.endsWith(".map")) {
|
|
423
518
|
continue;
|
|
424
519
|
}
|
|
520
|
+
// 打包运行时不要 require 源码;同名优先 .js(避免 src 与产物混扫)
|
|
521
|
+
if (/\.(ts|mts|cts)$/.test(entry.name)) {
|
|
522
|
+
if (!canRequireTs) {
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
const jsSibling = full.replace(/\.(mts|cts|ts)$/, ".js");
|
|
526
|
+
if (fs_1.default.existsSync(jsSibling)) {
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
425
530
|
const resolved = path_1.default.normalize(full);
|
|
531
|
+
// 跳过入口自身,避免 scan(dist) 时二次执行 main 导致 Application already started
|
|
532
|
+
if (entryFile && resolved === entryFile) {
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
426
535
|
if (this.loadedFiles.has(resolved)) {
|
|
427
536
|
continue;
|
|
428
537
|
}
|
|
@@ -568,13 +677,34 @@ class Application {
|
|
|
568
677
|
const startTime = Date.now();
|
|
569
678
|
let result;
|
|
570
679
|
let error;
|
|
680
|
+
const meta = option;
|
|
681
|
+
const handler = {
|
|
682
|
+
path,
|
|
683
|
+
method: method.toUpperCase(),
|
|
684
|
+
controllerName: meta?.__controllerName,
|
|
685
|
+
handlerName: meta?.__handlerName,
|
|
686
|
+
option,
|
|
687
|
+
};
|
|
571
688
|
try {
|
|
572
689
|
await this.applyRouteAuth(option, req);
|
|
573
690
|
await this.applyRouteGuards(option, req);
|
|
691
|
+
const preOk = await (0, interceptors_1.runHandlerPreHandle)(req, response, handler);
|
|
692
|
+
if (!preOk || response.headersSent) {
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
574
695
|
const reqCtx = await (0, interceptors_1.runRequestInterceptors)(req, response, option);
|
|
575
696
|
if (response.headersSent) {
|
|
576
697
|
return;
|
|
577
698
|
}
|
|
699
|
+
const invocationCtx = {
|
|
700
|
+
req,
|
|
701
|
+
res: response,
|
|
702
|
+
option,
|
|
703
|
+
path,
|
|
704
|
+
httpMethod: method.toUpperCase(),
|
|
705
|
+
controllerName: meta?.__controllerName,
|
|
706
|
+
handlerName: meta?.__handlerName,
|
|
707
|
+
};
|
|
578
708
|
if (option?.flux || option?.raw) {
|
|
579
709
|
if (reqCtx.skipHandler) {
|
|
580
710
|
return;
|
|
@@ -588,7 +718,7 @@ class Application {
|
|
|
588
718
|
if (vm)
|
|
589
719
|
await vm(args, option.paramTypes ?? []);
|
|
590
720
|
}
|
|
591
|
-
await callback(...args);
|
|
721
|
+
await (0, aop_1.runWithMethodInvocationContext)(invocationCtx, () => callback(...args));
|
|
592
722
|
}
|
|
593
723
|
else {
|
|
594
724
|
if (!reqCtx.skipHandler) {
|
|
@@ -598,12 +728,17 @@ class Application {
|
|
|
598
728
|
if (vm)
|
|
599
729
|
await vm(args, option.paramTypes ?? []);
|
|
600
730
|
}
|
|
601
|
-
result = await callback(...args);
|
|
731
|
+
result = await (0, aop_1.runWithMethodInvocationContext)(invocationCtx, () => callback(...args));
|
|
602
732
|
}
|
|
603
733
|
else {
|
|
604
734
|
result = reqCtx.data;
|
|
605
735
|
}
|
|
606
|
-
|
|
736
|
+
let serialized = Json_1.ObjectMapper.writeValue(result);
|
|
737
|
+
serialized = await (0, interceptors_1.runHandlerPostHandle)(req, response, handler, serialized);
|
|
738
|
+
if (response.headersSent) {
|
|
739
|
+
result = serialized;
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
607
742
|
const resCtx = await (0, interceptors_1.runResponseInterceptors)({
|
|
608
743
|
req,
|
|
609
744
|
res: response,
|
|
@@ -628,6 +763,7 @@ class Application {
|
|
|
628
763
|
await (0, Exception_1.handleException)(req, response, e);
|
|
629
764
|
}
|
|
630
765
|
finally {
|
|
766
|
+
await (0, interceptors_1.runHandlerAfterCompletion)(req, response, handler, error);
|
|
631
767
|
this.scheduleOperationLog(req, option, {
|
|
632
768
|
result: error ? undefined : result,
|
|
633
769
|
error,
|
|
@@ -663,6 +799,9 @@ Application.redisRegistered = false;
|
|
|
663
799
|
Application.ormRegistered = false;
|
|
664
800
|
/** 已注册过的 Controller,防止重复挂路由 */
|
|
665
801
|
Application.registeredControllers = new WeakSet();
|
|
802
|
+
/** 已注册过的 Filter / Interceptor 类 */
|
|
803
|
+
Application.registeredFilters = new WeakSet();
|
|
804
|
+
Application.registeredInterceptors = new WeakSet();
|
|
666
805
|
/** 已 require 过的模块文件 */
|
|
667
806
|
Application.loadedFiles = new Set();
|
|
668
807
|
/**
|
|
@@ -671,6 +810,26 @@ Application.loadedFiles = new Set();
|
|
|
671
810
|
*/
|
|
672
811
|
Application.scanRoots = [];
|
|
673
812
|
exports.default = Application;
|
|
813
|
+
var interceptors_2 = require("./interceptors");
|
|
814
|
+
Object.defineProperty(exports, "Interceptor", { enumerable: true, get: function () { return interceptors_2.Interceptor; } });
|
|
815
|
+
var filters_2 = require("./filters");
|
|
816
|
+
Object.defineProperty(exports, "WebFilter", { enumerable: true, get: function () { return filters_2.WebFilter; } });
|
|
817
|
+
var aop_2 = require("./aop");
|
|
818
|
+
Object.defineProperty(exports, "Around", { enumerable: true, get: function () { return aop_2.Around; } });
|
|
819
|
+
Object.defineProperty(exports, "Before", { enumerable: true, get: function () { return aop_2.Before; } });
|
|
820
|
+
Object.defineProperty(exports, "After", { enumerable: true, get: function () { return aop_2.After; } });
|
|
821
|
+
Object.defineProperty(exports, "AfterReturning", { enumerable: true, get: function () { return aop_2.AfterReturning; } });
|
|
822
|
+
Object.defineProperty(exports, "AfterThrowing", { enumerable: true, get: function () { return aop_2.AfterThrowing; } });
|
|
823
|
+
Object.defineProperty(exports, "createAroundDecorator", { enumerable: true, get: function () { return aop_2.createAroundDecorator; } });
|
|
824
|
+
Object.defineProperty(exports, "createBeforeDecorator", { enumerable: true, get: function () { return aop_2.createBeforeDecorator; } });
|
|
825
|
+
Object.defineProperty(exports, "createAfterDecorator", { enumerable: true, get: function () { return aop_2.createAfterDecorator; } });
|
|
826
|
+
Object.defineProperty(exports, "createAfterReturningDecorator", { enumerable: true, get: function () { return aop_2.createAfterReturningDecorator; } });
|
|
827
|
+
Object.defineProperty(exports, "createAfterThrowingDecorator", { enumerable: true, get: function () { return aop_2.createAfterThrowingDecorator; } });
|
|
828
|
+
Object.defineProperty(exports, "markAdvice", { enumerable: true, get: function () { return aop_2.markAdvice; } });
|
|
829
|
+
Object.defineProperty(exports, "registerAroundAdvice", { enumerable: true, get: function () { return aop_2.registerAroundAdvice; } });
|
|
830
|
+
Object.defineProperty(exports, "createMarkDecorator", { enumerable: true, get: function () { return aop_2.createMarkDecorator; } });
|
|
831
|
+
Object.defineProperty(exports, "getMethodInvocationContext", { enumerable: true, get: function () { return aop_2.getMethodInvocationContext; } });
|
|
832
|
+
Object.defineProperty(exports, "getMethodAdvices", { enumerable: true, get: function () { return aop_2.getMethodAdvices; } });
|
|
674
833
|
var lifecycle_2 = require("./lifecycle");
|
|
675
834
|
Object.defineProperty(exports, "runApplicationInits", { enumerable: true, get: function () { return lifecycle_2.runApplicationInits; } });
|
|
676
835
|
Object.defineProperty(exports, "runApplicationDestroys", { enumerable: true, get: function () { return lifecycle_2.runApplicationDestroys; } });
|
|
@@ -694,6 +853,7 @@ Object.defineProperty(exports, "RequestQuery", { enumerable: true, get: function
|
|
|
694
853
|
Object.defineProperty(exports, "RequestPath", { enumerable: true, get: function () { return decorators_1.RequestPath; } });
|
|
695
854
|
Object.defineProperty(exports, "RequestHeader", { enumerable: true, get: function () { return decorators_1.RequestHeader; } });
|
|
696
855
|
Object.defineProperty(exports, "RequestCookie", { enumerable: true, get: function () { return decorators_1.RequestCookie; } });
|
|
856
|
+
Object.defineProperty(exports, "RequestForm", { enumerable: true, get: function () { return decorators_1.RequestForm; } });
|
|
697
857
|
Object.defineProperty(exports, "Value", { enumerable: true, get: function () { return decorators_1.Value; } });
|
|
698
858
|
var container_1 = require("./container");
|
|
699
859
|
Object.defineProperty(exports, "Container", { enumerable: true, get: function () { return container_1.Container; } });
|