@modern-js/bff-core 1.0.1-beta.0 → 1.0.1-beta.3
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/js/modern/api.js +0 -11
- package/dist/js/modern/client/generate-client.js +2 -3
- package/dist/js/modern/operators/http.js +16 -13
- package/dist/js/modern/router/index.js +86 -82
- package/dist/js/modern/router/utils.js +10 -0
- package/dist/js/modern/types.js +8 -3
- package/dist/js/modern/utils.js +3 -1
- package/dist/js/node/api.js +0 -11
- package/dist/js/node/client/generate-client.js +2 -3
- package/dist/js/node/operators/http.js +14 -12
- package/dist/js/node/router/index.js +89 -84
- package/dist/js/node/router/utils.js +15 -2
- package/dist/js/node/types.js +10 -4
- package/dist/js/node/utils.js +7 -3
- package/dist/types/operators/http.d.ts +5 -1
- package/dist/types/router/index.d.ts +9 -9
- package/dist/types/router/utils.d.ts +3 -1
- package/dist/types/types.d.ts +5 -3
- package/dist/types/utils.d.ts +2 -1
- package/package.json +6 -1
package/dist/js/modern/api.js
CHANGED
|
@@ -25,17 +25,6 @@ export function Api(...args) {
|
|
|
25
25
|
const validateHandlers = operators.filter(operator => operator.validate).map(operator => operator.validate);
|
|
26
26
|
|
|
27
27
|
async function runner(inputs) {
|
|
28
|
-
// 错误组合传给用户哪些信息?
|
|
29
|
-
// 取出来所有的 schema,然后做校验
|
|
30
|
-
// 包裹中间件,怎么根据不同框架去包裹?
|
|
31
|
-
// 需要满足的需求,可以关闭某一样 schema 的校验
|
|
32
|
-
// 可以关闭某一个字段的校验
|
|
33
|
-
// 可以设置校验函数以替换 zod ?类型怎么搞?
|
|
34
|
-
// 全局可配置校验函数
|
|
35
|
-
// middleware 多框架实现要支持在路由上配,但这样 middleware 就要在校验之前先执行了
|
|
36
|
-
// 简易模式适配怎么处理?
|
|
37
|
-
// 不同框架适配,响应怎么处理?都传入 co ntext 给这个函数?
|
|
38
|
-
// 如何不依赖 zod 库?支持用户自定义 schema 库? Query,Data 实现可以统一代码,类型好像无解,除非这些函数是创建出来的,保证只有 http 中依赖 zod 吧
|
|
39
28
|
const executeHelper = {
|
|
40
29
|
result: null,
|
|
41
30
|
|
|
@@ -29,13 +29,12 @@ export const generateClient = async ({
|
|
|
29
29
|
|
|
30
30
|
const apiRouter = new ApiRouter({
|
|
31
31
|
apiDir,
|
|
32
|
-
prefix
|
|
33
|
-
lambdaDir: apiDir
|
|
32
|
+
prefix
|
|
34
33
|
});
|
|
35
34
|
const handlerInfos = apiRouter.getSingleModuleHandlers(resourcePath);
|
|
36
35
|
|
|
37
36
|
if (!handlerInfos) {
|
|
38
|
-
return Err(`Cannot require module ${resourcePath}`);
|
|
37
|
+
return Err(`generate client error: Cannot require module ${resourcePath}`);
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
let handlersCode = '';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { HttpMetadata, OperatorType, HttpMethod, TriggerType } from "../types";
|
|
2
|
+
import { HttpMetadata, OperatorType, HttpMethod, TriggerType, ResponseMetaType } from "../types";
|
|
3
3
|
import { ValidationError } from "../errors/http";
|
|
4
4
|
|
|
5
5
|
const validateInput = async (schema, input) => {
|
|
@@ -133,14 +133,21 @@ export const Headers = schema => {
|
|
|
133
133
|
|
|
134
134
|
};
|
|
135
135
|
};
|
|
136
|
+
|
|
137
|
+
const setResponseMeta = (helper, type, value) => {
|
|
138
|
+
const responseMetaData = helper.getMetadata(HttpMetadata.Response) || [];
|
|
139
|
+
helper.setMetadata(HttpMetadata.Response, [...responseMetaData, {
|
|
140
|
+
type,
|
|
141
|
+
value
|
|
142
|
+
}]);
|
|
143
|
+
};
|
|
144
|
+
|
|
136
145
|
export const HttpCode = statusCode => {
|
|
137
146
|
return {
|
|
138
147
|
name: 'HttpCode',
|
|
139
148
|
|
|
140
|
-
metadata({
|
|
141
|
-
|
|
142
|
-
}) {
|
|
143
|
-
setMetadata(HttpMetadata.StatusCode, statusCode);
|
|
149
|
+
metadata(helper) {
|
|
150
|
+
setResponseMeta(helper, ResponseMetaType.StatusCode, statusCode);
|
|
144
151
|
}
|
|
145
152
|
|
|
146
153
|
};
|
|
@@ -149,10 +156,8 @@ export const SetHeaders = headers => {
|
|
|
149
156
|
return {
|
|
150
157
|
name: 'SetHeaders',
|
|
151
158
|
|
|
152
|
-
metadata({
|
|
153
|
-
|
|
154
|
-
}) {
|
|
155
|
-
setMetadata(HttpMetadata.ResponseHeaders, headers);
|
|
159
|
+
metadata(helper) {
|
|
160
|
+
setResponseMeta(helper, ResponseMetaType.Headers, headers);
|
|
156
161
|
}
|
|
157
162
|
|
|
158
163
|
};
|
|
@@ -161,10 +166,8 @@ export const Redirect = url => {
|
|
|
161
166
|
return {
|
|
162
167
|
name: 'Redirect',
|
|
163
168
|
|
|
164
|
-
metadata({
|
|
165
|
-
|
|
166
|
-
}) {
|
|
167
|
-
setMetadata(HttpMetadata.Redirect, url);
|
|
169
|
+
metadata(helper) {
|
|
170
|
+
setResponseMeta(helper, ResponseMetaType.Redirect, url);
|
|
168
171
|
}
|
|
169
172
|
|
|
170
173
|
};
|
|
@@ -5,8 +5,9 @@ import { fs, logger } from '@modern-js/utils';
|
|
|
5
5
|
import 'reflect-metadata';
|
|
6
6
|
import 'esbuild-register';
|
|
7
7
|
import { HttpMethod, httpMethods, OperatorType, TriggerType } from "../types";
|
|
8
|
+
import { debug } from "../utils";
|
|
8
9
|
import { APIMode, FRAMEWORK_MODE_LAMBDA_DIR, API_FILE_RULES } from "./constants";
|
|
9
|
-
import { getFiles, getPathFromFilename, requireHandlerModule } from "./utils";
|
|
10
|
+
import { getFiles, getPathFromFilename, requireHandlerModule, sortRoutes } from "./utils";
|
|
10
11
|
export * from "./types";
|
|
11
12
|
export * from "./constants";
|
|
12
13
|
export class ApiRouter {
|
|
@@ -59,86 +60,6 @@ export class ApiRouter {
|
|
|
59
60
|
this.apiDir = _apiDir;
|
|
60
61
|
this.lambdaDir = _lambdaDir || this.getLambdaDir(this.apiDir);
|
|
61
62
|
}
|
|
62
|
-
/**
|
|
63
|
-
* 如果用户未传入或传入空串,默认为 /api
|
|
64
|
-
* 如果传入 /,则 prefix 为 /
|
|
65
|
-
*/
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
initPrefix(prefix) {
|
|
69
|
-
if (prefix === '/') {
|
|
70
|
-
return '';
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return prefix || '/api';
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
validateAbsolute(filename, paramsName) {
|
|
77
|
-
if (!path.isAbsolute(filename)) {
|
|
78
|
-
throw new Error(`The ${paramsName} ${filename} is not a abolute path`);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
getModuleInfos(filenames) {
|
|
83
|
-
return filenames.map(filename => this.getModuleInfo(filename)).filter(moduleInfo => Boolean(moduleInfo));
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
getModuleInfo(filename) {
|
|
87
|
-
try {
|
|
88
|
-
const module = requireHandlerModule(filename);
|
|
89
|
-
return {
|
|
90
|
-
filename,
|
|
91
|
-
module
|
|
92
|
-
};
|
|
93
|
-
} catch (err) {
|
|
94
|
-
if (process.env.NODE_ENV === 'production') {
|
|
95
|
-
throw err;
|
|
96
|
-
} else {
|
|
97
|
-
console.error(err);
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
getHandlerInfos(moduleInfos) {
|
|
104
|
-
let apiHandlers = [];
|
|
105
|
-
moduleInfos.forEach(moduleInfo => {
|
|
106
|
-
const handlerInfos = this.getModuleHandlerInfos(moduleInfo);
|
|
107
|
-
|
|
108
|
-
if (handlerInfos) {
|
|
109
|
-
apiHandlers = apiHandlers.concat(handlerInfos);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
return apiHandlers;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
getModuleHandlerInfos(moduleInfo) {
|
|
116
|
-
const {
|
|
117
|
-
module,
|
|
118
|
-
filename
|
|
119
|
-
} = moduleInfo;
|
|
120
|
-
return Object.entries(module).filter(([, handler]) => typeof handler === 'function').map(([key]) => {
|
|
121
|
-
const handler = module[key];
|
|
122
|
-
const handlerInfo = this.getHandlerInfo(filename, key, handler);
|
|
123
|
-
return handlerInfo;
|
|
124
|
-
}).filter(handlerInfo => Boolean(handlerInfo));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
validateValidApifile(filename) {
|
|
128
|
-
if (!this.apiFiles.includes(filename)) {
|
|
129
|
-
throw new Error(`The ${filename} is not a valid api file.`);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
getRoutePath(prefix, routeName) {
|
|
134
|
-
const finalRouteName = routeName === '/' ? '' : routeName;
|
|
135
|
-
|
|
136
|
-
if (prefix === '' && finalRouteName === '') {
|
|
137
|
-
return '/';
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return `${prefix}${finalRouteName}`;
|
|
141
|
-
}
|
|
142
63
|
|
|
143
64
|
isApiFile(filename) {
|
|
144
65
|
if (!this.apiFiles.includes(filename)) {
|
|
@@ -265,7 +186,90 @@ export class ApiRouter {
|
|
|
265
186
|
getApiHandlers() {
|
|
266
187
|
const filenames = this.getApiFiles();
|
|
267
188
|
const moduleInfos = this.getModuleInfos(filenames);
|
|
268
|
-
|
|
189
|
+
const apiHandlers = this.getHandlerInfos(moduleInfos);
|
|
190
|
+
debug('apiHandlers', apiHandlers);
|
|
191
|
+
return apiHandlers;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* 如果用户未传入或传入空串,默认为 /api
|
|
195
|
+
* 如果传入 /,则 prefix 为 /
|
|
196
|
+
*/
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
initPrefix(prefix) {
|
|
200
|
+
if (prefix === '/') {
|
|
201
|
+
return '';
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return prefix || '/api';
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
validateAbsolute(filename, paramsName) {
|
|
208
|
+
if (!path.isAbsolute(filename)) {
|
|
209
|
+
throw new Error(`The ${paramsName} ${filename} is not a abolute path`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
getModuleInfos(filenames) {
|
|
214
|
+
return filenames.map(filename => this.getModuleInfo(filename)).filter(moduleInfo => Boolean(moduleInfo));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
getModuleInfo(filename) {
|
|
218
|
+
try {
|
|
219
|
+
const module = requireHandlerModule(filename);
|
|
220
|
+
return {
|
|
221
|
+
filename,
|
|
222
|
+
module
|
|
223
|
+
};
|
|
224
|
+
} catch (err) {
|
|
225
|
+
if (process.env.NODE_ENV === 'production') {
|
|
226
|
+
throw err;
|
|
227
|
+
} else {
|
|
228
|
+
console.error(err);
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
getHandlerInfos(moduleInfos) {
|
|
235
|
+
let apiHandlers = [];
|
|
236
|
+
moduleInfos.forEach(moduleInfo => {
|
|
237
|
+
const handlerInfos = this.getModuleHandlerInfos(moduleInfo);
|
|
238
|
+
|
|
239
|
+
if (handlerInfos) {
|
|
240
|
+
apiHandlers = apiHandlers.concat(handlerInfos);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
const sortedHandlers = sortRoutes(apiHandlers);
|
|
244
|
+
return sortedHandlers;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
getModuleHandlerInfos(moduleInfo) {
|
|
248
|
+
const {
|
|
249
|
+
module,
|
|
250
|
+
filename
|
|
251
|
+
} = moduleInfo;
|
|
252
|
+
return Object.entries(module).filter(([, handler]) => typeof handler === 'function').map(([key]) => {
|
|
253
|
+
const handler = module[key];
|
|
254
|
+
const handlerInfo = this.getHandlerInfo(filename, key, handler);
|
|
255
|
+
return handlerInfo;
|
|
256
|
+
}).filter(handlerInfo => Boolean(handlerInfo));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
validateValidApifile(filename) {
|
|
260
|
+
if (!this.apiFiles.includes(filename)) {
|
|
261
|
+
throw new Error(`The ${filename} is not a valid api file.`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
getRoutePath(prefix, routeName) {
|
|
266
|
+
const finalRouteName = routeName === '/' ? '' : routeName;
|
|
267
|
+
|
|
268
|
+
if (prefix === '' && finalRouteName === '') {
|
|
269
|
+
return '/';
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return `${prefix}${finalRouteName}`;
|
|
269
273
|
}
|
|
270
274
|
|
|
271
275
|
}
|
|
@@ -50,4 +50,14 @@ export const requireHandlerModule = modulePath => {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
return module;
|
|
53
|
+
};
|
|
54
|
+
export const sortRoutes = apiHandlers => {
|
|
55
|
+
const sortedHandlers = apiHandlers.slice();
|
|
56
|
+
sortedHandlers.forEach((apiHandler, handlerIndex) => {
|
|
57
|
+
if (apiHandler.routeName.includes(':')) {
|
|
58
|
+
sortedHandlers.splice(handlerIndex, 1);
|
|
59
|
+
sortedHandlers.push(apiHandler);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return sortedHandlers;
|
|
53
63
|
};
|
package/dist/js/modern/types.js
CHANGED
|
@@ -20,11 +20,16 @@ export let HttpMetadata;
|
|
|
20
20
|
HttpMetadata["Params"] = "PARAMS";
|
|
21
21
|
HttpMetadata["Headers"] = "HEADERS";
|
|
22
22
|
HttpMetadata["Response"] = "RESPONSE";
|
|
23
|
-
HttpMetadata["StatusCode"] = "STATUS_CODE";
|
|
24
|
-
HttpMetadata["Redirect"] = "REDIRECT";
|
|
25
|
-
HttpMetadata["ResponseHeaders"] = "RESPONSE_HEADERS";
|
|
26
23
|
})(HttpMetadata || (HttpMetadata = {}));
|
|
27
24
|
|
|
25
|
+
export let ResponseMetaType;
|
|
26
|
+
|
|
27
|
+
(function (ResponseMetaType) {
|
|
28
|
+
ResponseMetaType[ResponseMetaType["StatusCode"] = 0] = "StatusCode";
|
|
29
|
+
ResponseMetaType[ResponseMetaType["Redirect"] = 1] = "Redirect";
|
|
30
|
+
ResponseMetaType[ResponseMetaType["Headers"] = 2] = "Headers";
|
|
31
|
+
})(ResponseMetaType || (ResponseMetaType = {}));
|
|
32
|
+
|
|
28
33
|
export let HttpMethod;
|
|
29
34
|
|
|
30
35
|
(function (HttpMethod) {
|
package/dist/js/modern/utils.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import util from 'util';
|
|
2
|
-
|
|
2
|
+
import { createDebugger } from '@modern-js/utils';
|
|
3
|
+
export const HANDLER_WITH_META = 'HANDLER_WITH_META';
|
|
4
|
+
export const debug = createDebugger('bff'); // export const pick = <T extends Record<string, unknown>, K extends keyof T>(
|
|
3
5
|
// obj: T,
|
|
4
6
|
// keys: readonly K[],
|
|
5
7
|
// ) => {
|
package/dist/js/node/api.js
CHANGED
|
@@ -37,17 +37,6 @@ function Api(...args) {
|
|
|
37
37
|
const validateHandlers = operators.filter(operator => operator.validate).map(operator => operator.validate);
|
|
38
38
|
|
|
39
39
|
async function runner(inputs) {
|
|
40
|
-
// 错误组合传给用户哪些信息?
|
|
41
|
-
// 取出来所有的 schema,然后做校验
|
|
42
|
-
// 包裹中间件,怎么根据不同框架去包裹?
|
|
43
|
-
// 需要满足的需求,可以关闭某一样 schema 的校验
|
|
44
|
-
// 可以关闭某一个字段的校验
|
|
45
|
-
// 可以设置校验函数以替换 zod ?类型怎么搞?
|
|
46
|
-
// 全局可配置校验函数
|
|
47
|
-
// middleware 多框架实现要支持在路由上配,但这样 middleware 就要在校验之前先执行了
|
|
48
|
-
// 简易模式适配怎么处理?
|
|
49
|
-
// 不同框架适配,响应怎么处理?都传入 co ntext 给这个函数?
|
|
50
|
-
// 如何不依赖 zod 库?支持用户自定义 schema 库? Query,Data 实现可以统一代码,类型好像无解,除非这些函数是创建出来的,保证只有 http 中依赖 zod 吧
|
|
51
40
|
const executeHelper = {
|
|
52
41
|
result: null,
|
|
53
42
|
|
|
@@ -45,13 +45,12 @@ const generateClient = async ({
|
|
|
45
45
|
|
|
46
46
|
const apiRouter = new _router.ApiRouter({
|
|
47
47
|
apiDir,
|
|
48
|
-
prefix
|
|
49
|
-
lambdaDir: apiDir
|
|
48
|
+
prefix
|
|
50
49
|
});
|
|
51
50
|
const handlerInfos = apiRouter.getSingleModuleHandlers(resourcePath);
|
|
52
51
|
|
|
53
52
|
if (!handlerInfos) {
|
|
54
|
-
return (0, _result.Err)(`Cannot require module ${resourcePath}`);
|
|
53
|
+
return (0, _result.Err)(`generate client error: Cannot require module ${resourcePath}`);
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
let handlersCode = '';
|
|
@@ -166,14 +166,20 @@ const Headers = schema => {
|
|
|
166
166
|
|
|
167
167
|
exports.Headers = Headers;
|
|
168
168
|
|
|
169
|
+
const setResponseMeta = (helper, type, value) => {
|
|
170
|
+
const responseMetaData = helper.getMetadata(_types.HttpMetadata.Response) || [];
|
|
171
|
+
helper.setMetadata(_types.HttpMetadata.Response, [...responseMetaData, {
|
|
172
|
+
type,
|
|
173
|
+
value
|
|
174
|
+
}]);
|
|
175
|
+
};
|
|
176
|
+
|
|
169
177
|
const HttpCode = statusCode => {
|
|
170
178
|
return {
|
|
171
179
|
name: 'HttpCode',
|
|
172
180
|
|
|
173
|
-
metadata({
|
|
174
|
-
|
|
175
|
-
}) {
|
|
176
|
-
setMetadata(_types.HttpMetadata.StatusCode, statusCode);
|
|
181
|
+
metadata(helper) {
|
|
182
|
+
setResponseMeta(helper, _types.ResponseMetaType.StatusCode, statusCode);
|
|
177
183
|
}
|
|
178
184
|
|
|
179
185
|
};
|
|
@@ -185,10 +191,8 @@ const SetHeaders = headers => {
|
|
|
185
191
|
return {
|
|
186
192
|
name: 'SetHeaders',
|
|
187
193
|
|
|
188
|
-
metadata({
|
|
189
|
-
|
|
190
|
-
}) {
|
|
191
|
-
setMetadata(_types.HttpMetadata.ResponseHeaders, headers);
|
|
194
|
+
metadata(helper) {
|
|
195
|
+
setResponseMeta(helper, _types.ResponseMetaType.Headers, headers);
|
|
192
196
|
}
|
|
193
197
|
|
|
194
198
|
};
|
|
@@ -200,10 +204,8 @@ const Redirect = url => {
|
|
|
200
204
|
return {
|
|
201
205
|
name: 'Redirect',
|
|
202
206
|
|
|
203
|
-
metadata({
|
|
204
|
-
|
|
205
|
-
}) {
|
|
206
|
-
setMetadata(_types.HttpMetadata.Redirect, url);
|
|
207
|
+
metadata(helper) {
|
|
208
|
+
setResponseMeta(helper, _types.ResponseMetaType.Redirect, url);
|
|
207
209
|
}
|
|
208
210
|
|
|
209
211
|
};
|
|
@@ -18,6 +18,8 @@ require("esbuild-register");
|
|
|
18
18
|
|
|
19
19
|
var _types = require("../types");
|
|
20
20
|
|
|
21
|
+
var _utils2 = require("../utils");
|
|
22
|
+
|
|
21
23
|
var _constants = require("./constants");
|
|
22
24
|
|
|
23
25
|
Object.keys(_constants).forEach(function (key) {
|
|
@@ -32,7 +34,7 @@ Object.keys(_constants).forEach(function (key) {
|
|
|
32
34
|
});
|
|
33
35
|
});
|
|
34
36
|
|
|
35
|
-
var
|
|
37
|
+
var _utils3 = require("./utils");
|
|
36
38
|
|
|
37
39
|
var _types2 = require("./types");
|
|
38
40
|
|
|
@@ -102,86 +104,6 @@ class ApiRouter {
|
|
|
102
104
|
this.apiDir = _apiDir;
|
|
103
105
|
this.lambdaDir = _lambdaDir || this.getLambdaDir(this.apiDir);
|
|
104
106
|
}
|
|
105
|
-
/**
|
|
106
|
-
* 如果用户未传入或传入空串,默认为 /api
|
|
107
|
-
* 如果传入 /,则 prefix 为 /
|
|
108
|
-
*/
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
initPrefix(prefix) {
|
|
112
|
-
if (prefix === '/') {
|
|
113
|
-
return '';
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return prefix || '/api';
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
validateAbsolute(filename, paramsName) {
|
|
120
|
-
if (!_path.default.isAbsolute(filename)) {
|
|
121
|
-
throw new Error(`The ${paramsName} ${filename} is not a abolute path`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
getModuleInfos(filenames) {
|
|
126
|
-
return filenames.map(filename => this.getModuleInfo(filename)).filter(moduleInfo => Boolean(moduleInfo));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
getModuleInfo(filename) {
|
|
130
|
-
try {
|
|
131
|
-
const module = (0, _utils2.requireHandlerModule)(filename);
|
|
132
|
-
return {
|
|
133
|
-
filename,
|
|
134
|
-
module
|
|
135
|
-
};
|
|
136
|
-
} catch (err) {
|
|
137
|
-
if (process.env.NODE_ENV === 'production') {
|
|
138
|
-
throw err;
|
|
139
|
-
} else {
|
|
140
|
-
console.error(err);
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
getHandlerInfos(moduleInfos) {
|
|
147
|
-
let apiHandlers = [];
|
|
148
|
-
moduleInfos.forEach(moduleInfo => {
|
|
149
|
-
const handlerInfos = this.getModuleHandlerInfos(moduleInfo);
|
|
150
|
-
|
|
151
|
-
if (handlerInfos) {
|
|
152
|
-
apiHandlers = apiHandlers.concat(handlerInfos);
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
return apiHandlers;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
getModuleHandlerInfos(moduleInfo) {
|
|
159
|
-
const {
|
|
160
|
-
module,
|
|
161
|
-
filename
|
|
162
|
-
} = moduleInfo;
|
|
163
|
-
return Object.entries(module).filter(([, handler]) => typeof handler === 'function').map(([key]) => {
|
|
164
|
-
const handler = module[key];
|
|
165
|
-
const handlerInfo = this.getHandlerInfo(filename, key, handler);
|
|
166
|
-
return handlerInfo;
|
|
167
|
-
}).filter(handlerInfo => Boolean(handlerInfo));
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
validateValidApifile(filename) {
|
|
171
|
-
if (!this.apiFiles.includes(filename)) {
|
|
172
|
-
throw new Error(`The ${filename} is not a valid api file.`);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
getRoutePath(prefix, routeName) {
|
|
177
|
-
const finalRouteName = routeName === '/' ? '' : routeName;
|
|
178
|
-
|
|
179
|
-
if (prefix === '' && finalRouteName === '') {
|
|
180
|
-
return '/';
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return `${prefix}${finalRouteName}`;
|
|
184
|
-
}
|
|
185
107
|
|
|
186
108
|
isApiFile(filename) {
|
|
187
109
|
if (!this.apiFiles.includes(filename)) {
|
|
@@ -239,7 +161,7 @@ class ApiRouter {
|
|
|
239
161
|
}
|
|
240
162
|
}
|
|
241
163
|
|
|
242
|
-
const routePath = (0,
|
|
164
|
+
const routePath = (0, _utils3.getPathFromFilename)(this.lambdaDir, filename);
|
|
243
165
|
return routePath;
|
|
244
166
|
}
|
|
245
167
|
|
|
@@ -294,7 +216,7 @@ class ApiRouter {
|
|
|
294
216
|
|
|
295
217
|
loadApiFiles() {
|
|
296
218
|
// eslint-disable-next-line no-multi-assign
|
|
297
|
-
const apiFiles = this.apiFiles = (0,
|
|
219
|
+
const apiFiles = this.apiFiles = (0, _utils3.getFiles)(this.lambdaDir, _constants.API_FILE_RULES);
|
|
298
220
|
return apiFiles;
|
|
299
221
|
}
|
|
300
222
|
|
|
@@ -309,7 +231,90 @@ class ApiRouter {
|
|
|
309
231
|
getApiHandlers() {
|
|
310
232
|
const filenames = this.getApiFiles();
|
|
311
233
|
const moduleInfos = this.getModuleInfos(filenames);
|
|
312
|
-
|
|
234
|
+
const apiHandlers = this.getHandlerInfos(moduleInfos);
|
|
235
|
+
(0, _utils2.debug)('apiHandlers', apiHandlers);
|
|
236
|
+
return apiHandlers;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* 如果用户未传入或传入空串,默认为 /api
|
|
240
|
+
* 如果传入 /,则 prefix 为 /
|
|
241
|
+
*/
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
initPrefix(prefix) {
|
|
245
|
+
if (prefix === '/') {
|
|
246
|
+
return '';
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return prefix || '/api';
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
validateAbsolute(filename, paramsName) {
|
|
253
|
+
if (!_path.default.isAbsolute(filename)) {
|
|
254
|
+
throw new Error(`The ${paramsName} ${filename} is not a abolute path`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
getModuleInfos(filenames) {
|
|
259
|
+
return filenames.map(filename => this.getModuleInfo(filename)).filter(moduleInfo => Boolean(moduleInfo));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
getModuleInfo(filename) {
|
|
263
|
+
try {
|
|
264
|
+
const module = (0, _utils3.requireHandlerModule)(filename);
|
|
265
|
+
return {
|
|
266
|
+
filename,
|
|
267
|
+
module
|
|
268
|
+
};
|
|
269
|
+
} catch (err) {
|
|
270
|
+
if (process.env.NODE_ENV === 'production') {
|
|
271
|
+
throw err;
|
|
272
|
+
} else {
|
|
273
|
+
console.error(err);
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
getHandlerInfos(moduleInfos) {
|
|
280
|
+
let apiHandlers = [];
|
|
281
|
+
moduleInfos.forEach(moduleInfo => {
|
|
282
|
+
const handlerInfos = this.getModuleHandlerInfos(moduleInfo);
|
|
283
|
+
|
|
284
|
+
if (handlerInfos) {
|
|
285
|
+
apiHandlers = apiHandlers.concat(handlerInfos);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
const sortedHandlers = (0, _utils3.sortRoutes)(apiHandlers);
|
|
289
|
+
return sortedHandlers;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
getModuleHandlerInfos(moduleInfo) {
|
|
293
|
+
const {
|
|
294
|
+
module,
|
|
295
|
+
filename
|
|
296
|
+
} = moduleInfo;
|
|
297
|
+
return Object.entries(module).filter(([, handler]) => typeof handler === 'function').map(([key]) => {
|
|
298
|
+
const handler = module[key];
|
|
299
|
+
const handlerInfo = this.getHandlerInfo(filename, key, handler);
|
|
300
|
+
return handlerInfo;
|
|
301
|
+
}).filter(handlerInfo => Boolean(handlerInfo));
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
validateValidApifile(filename) {
|
|
305
|
+
if (!this.apiFiles.includes(filename)) {
|
|
306
|
+
throw new Error(`The ${filename} is not a valid api file.`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
getRoutePath(prefix, routeName) {
|
|
311
|
+
const finalRouteName = routeName === '/' ? '' : routeName;
|
|
312
|
+
|
|
313
|
+
if (prefix === '' && finalRouteName === '') {
|
|
314
|
+
return '/';
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return `${prefix}${finalRouteName}`;
|
|
313
318
|
}
|
|
314
319
|
|
|
315
320
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.requireHandlerModule = exports.isHandler = exports.getPathFromFilename = exports.getFiles = void 0;
|
|
6
|
+
exports.sortRoutes = exports.requireHandlerModule = exports.isHandler = exports.getPathFromFilename = exports.getFiles = void 0;
|
|
7
7
|
|
|
8
8
|
var _path = _interopRequireDefault(require("path"));
|
|
9
9
|
|
|
@@ -71,4 +71,17 @@ const requireHandlerModule = modulePath => {
|
|
|
71
71
|
return module;
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
-
exports.requireHandlerModule = requireHandlerModule;
|
|
74
|
+
exports.requireHandlerModule = requireHandlerModule;
|
|
75
|
+
|
|
76
|
+
const sortRoutes = apiHandlers => {
|
|
77
|
+
const sortedHandlers = apiHandlers.slice();
|
|
78
|
+
sortedHandlers.forEach((apiHandler, handlerIndex) => {
|
|
79
|
+
if (apiHandler.routeName.includes(':')) {
|
|
80
|
+
sortedHandlers.splice(handlerIndex, 1);
|
|
81
|
+
sortedHandlers.push(apiHandler);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
return sortedHandlers;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
exports.sortRoutes = sortRoutes;
|
package/dist/js/node/types.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.httpMethods = exports.TriggerType = exports.OperatorType = exports.HttpMethod = exports.HttpMetadata = void 0;
|
|
6
|
+
exports.httpMethods = exports.TriggerType = exports.ResponseMetaType = exports.OperatorType = exports.HttpMethod = exports.HttpMetadata = void 0;
|
|
7
7
|
let OperatorType;
|
|
8
8
|
exports.OperatorType = OperatorType;
|
|
9
9
|
|
|
@@ -29,11 +29,17 @@ exports.HttpMetadata = HttpMetadata;
|
|
|
29
29
|
HttpMetadata["Params"] = "PARAMS";
|
|
30
30
|
HttpMetadata["Headers"] = "HEADERS";
|
|
31
31
|
HttpMetadata["Response"] = "RESPONSE";
|
|
32
|
-
HttpMetadata["StatusCode"] = "STATUS_CODE";
|
|
33
|
-
HttpMetadata["Redirect"] = "REDIRECT";
|
|
34
|
-
HttpMetadata["ResponseHeaders"] = "RESPONSE_HEADERS";
|
|
35
32
|
})(HttpMetadata || (exports.HttpMetadata = HttpMetadata = {}));
|
|
36
33
|
|
|
34
|
+
let ResponseMetaType;
|
|
35
|
+
exports.ResponseMetaType = ResponseMetaType;
|
|
36
|
+
|
|
37
|
+
(function (ResponseMetaType) {
|
|
38
|
+
ResponseMetaType[ResponseMetaType["StatusCode"] = 0] = "StatusCode";
|
|
39
|
+
ResponseMetaType[ResponseMetaType["Redirect"] = 1] = "Redirect";
|
|
40
|
+
ResponseMetaType[ResponseMetaType["Headers"] = 2] = "Headers";
|
|
41
|
+
})(ResponseMetaType || (exports.ResponseMetaType = ResponseMetaType = {}));
|
|
42
|
+
|
|
37
43
|
let HttpMethod;
|
|
38
44
|
exports.HttpMethod = HttpMethod;
|
|
39
45
|
|
package/dist/js/node/utils.js
CHANGED
|
@@ -3,13 +3,17 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.validateFunction = exports.isWithMetaHandler = exports.getTypeErrorMessage = exports.HANDLER_WITH_META = exports.ERR_INVALID_ARG_TYPE = void 0;
|
|
6
|
+
exports.validateFunction = exports.isWithMetaHandler = exports.getTypeErrorMessage = exports.debug = exports.HANDLER_WITH_META = exports.ERR_INVALID_ARG_TYPE = void 0;
|
|
7
7
|
|
|
8
8
|
var _util = _interopRequireDefault(require("util"));
|
|
9
9
|
|
|
10
|
+
var _utils = require("@modern-js/utils");
|
|
11
|
+
|
|
10
12
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
13
|
|
|
12
|
-
const HANDLER_WITH_META = '
|
|
14
|
+
const HANDLER_WITH_META = 'HANDLER_WITH_META';
|
|
15
|
+
exports.HANDLER_WITH_META = HANDLER_WITH_META;
|
|
16
|
+
const debug = (0, _utils.createDebugger)('bff'); // export const pick = <T extends Record<string, unknown>, K extends keyof T>(
|
|
13
17
|
// obj: T,
|
|
14
18
|
// keys: readonly K[],
|
|
15
19
|
// ) => {
|
|
@@ -19,7 +23,7 @@ const HANDLER_WITH_META = 'HANDLER_WITH_SCHEMA'; // export const pick = <T exten
|
|
|
19
23
|
// };
|
|
20
24
|
// fork from https://github.com/nodejs/node/blob/master/lib/internal/errors.js
|
|
21
25
|
|
|
22
|
-
exports.
|
|
26
|
+
exports.debug = debug;
|
|
23
27
|
|
|
24
28
|
const getTypeErrorMessage = actual => {
|
|
25
29
|
let msg = '';
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { Operator, HttpMethod, ApiMiddleware } from '../types';
|
|
2
|
+
import { Operator, HttpMethod, ApiMiddleware, ResponseMetaType } from '../types';
|
|
3
|
+
export interface ResponseMeta {
|
|
4
|
+
type: ResponseMetaType;
|
|
5
|
+
value: unknown;
|
|
6
|
+
}
|
|
3
7
|
export declare const createHttpOperator: (method: HttpMethod) => (urlPath: string) => Operator<void>;
|
|
4
8
|
export declare const Get: (urlPath: string) => Operator<void>;
|
|
5
9
|
export declare const Post: (urlPath: string) => Operator<void>;
|
|
@@ -18,6 +18,15 @@ export declare class ApiRouter {
|
|
|
18
18
|
lambdaDir?: string;
|
|
19
19
|
prefix?: string;
|
|
20
20
|
});
|
|
21
|
+
isApiFile(filename: string): boolean;
|
|
22
|
+
getSingleModuleHandlers(filename: string): APIHandlerInfo[] | null;
|
|
23
|
+
getHandlerInfo(filename: string, originFuncName: string, handler: ApiHandler): APIHandlerInfo | null;
|
|
24
|
+
getSafeRoutePath(filename: string, handler?: ApiHandler): string;
|
|
25
|
+
getRouteName(filename: string, handler?: ApiHandler): string;
|
|
26
|
+
getHttpMethod(originHandlerName: string, handler?: ApiHandler): HttpMethod | null;
|
|
27
|
+
loadApiFiles(): string[];
|
|
28
|
+
getApiFiles(): string[];
|
|
29
|
+
getApiHandlers(): APIHandlerInfo[];
|
|
21
30
|
/**
|
|
22
31
|
* 如果用户未传入或传入空串,默认为 /api
|
|
23
32
|
* 如果传入 /,则 prefix 为 /
|
|
@@ -34,13 +43,4 @@ export declare class ApiRouter {
|
|
|
34
43
|
private getModuleHandlerInfos;
|
|
35
44
|
private validateValidApifile;
|
|
36
45
|
private getRoutePath;
|
|
37
|
-
isApiFile(filename: string): boolean;
|
|
38
|
-
getSingleModuleHandlers(filename: string): APIHandlerInfo[] | null;
|
|
39
|
-
getHandlerInfo(filename: string, originFuncName: string, handler: ApiHandler): APIHandlerInfo | null;
|
|
40
|
-
getSafeRoutePath(filename: string, handler?: ApiHandler): string;
|
|
41
|
-
getRouteName(filename: string, handler?: ApiHandler): string;
|
|
42
|
-
getHttpMethod(originHandlerName: string, handler?: ApiHandler): HttpMethod | null;
|
|
43
|
-
loadApiFiles(): string[];
|
|
44
|
-
getApiFiles(): string[];
|
|
45
|
-
getApiHandlers(): APIHandlerInfo[];
|
|
46
46
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { MaybeAsync } from '@modern-js/bff-runtime';
|
|
2
|
+
import { APIHandlerInfo } from './types';
|
|
2
3
|
export declare type NormalHandler = (...args: any[]) => any;
|
|
3
4
|
export declare type Handler<I, O> = (input: I) => MaybeAsync<O>;
|
|
4
5
|
export declare const getFiles: (lambdaDir: string, rules: string | string[]) => string[];
|
|
5
6
|
export declare const getPathFromFilename: (baseDir: string, filename: string) => string;
|
|
6
7
|
export declare const isHandler: (input: any) => input is Handler<any, any>;
|
|
7
|
-
export declare const requireHandlerModule: (modulePath: string) => any;
|
|
8
|
+
export declare const requireHandlerModule: (modulePath: string) => any;
|
|
9
|
+
export declare const sortRoutes: (apiHandlers: APIHandlerInfo[]) => APIHandlerInfo[];
|
package/dist/types/types.d.ts
CHANGED
|
@@ -13,9 +13,11 @@ export declare enum HttpMetadata {
|
|
|
13
13
|
Params = "PARAMS",
|
|
14
14
|
Headers = "HEADERS",
|
|
15
15
|
Response = "RESPONSE",
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
}
|
|
17
|
+
export declare enum ResponseMetaType {
|
|
18
|
+
StatusCode = 0,
|
|
19
|
+
Redirect = 1,
|
|
20
|
+
Headers = 2,
|
|
19
21
|
}
|
|
20
22
|
export declare enum HttpMethod {
|
|
21
23
|
Get = "GET",
|
package/dist/types/utils.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export declare const HANDLER_WITH_META = "
|
|
1
|
+
export declare const HANDLER_WITH_META = "HANDLER_WITH_META";
|
|
2
|
+
export declare const debug: import("@modern-js/utils/compiled/debug").Debugger;
|
|
2
3
|
export declare const getTypeErrorMessage: (actual: unknown) => string;
|
|
3
4
|
export declare class ERR_INVALID_ARG_TYPE extends Error {
|
|
4
5
|
constructor(funcName: string, expectedType: string, actual: unknown);
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"modern",
|
|
12
12
|
"modern.js"
|
|
13
13
|
],
|
|
14
|
-
"version": "1.0.1-beta.
|
|
14
|
+
"version": "1.0.1-beta.3",
|
|
15
15
|
"jsnext:source": "./src/index.ts",
|
|
16
16
|
"types": "./dist/types/index.d.ts",
|
|
17
17
|
"main": "./dist/js/node/index.js",
|
|
@@ -47,6 +47,11 @@
|
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"zod": "^3.17.3"
|
|
49
49
|
},
|
|
50
|
+
"peerDependenciesMeta": {
|
|
51
|
+
"zod": {
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
50
55
|
"modernConfig": {
|
|
51
56
|
"output": {
|
|
52
57
|
"packageMode": "node-js"
|