@modern-js/bff-core 1.21.2-beta.1 → 1.21.2-beta.2
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 +54 -0
- package/dist/js/modern/client/generate-client.js +63 -0
- package/dist/js/modern/client/index.js +1 -0
- package/dist/js/modern/client/result.js +20 -0
- package/dist/js/modern/errors/http.js +22 -0
- package/dist/js/modern/index.js +7 -0
- package/dist/js/modern/operators/http.js +187 -0
- package/dist/js/modern/router/constants.js +14 -0
- package/dist/js/modern/router/index.js +299 -0
- package/dist/js/modern/router/types.js +1 -0
- package/dist/js/modern/router/utils.js +99 -0
- package/dist/js/modern/types.js +47 -0
- package/dist/js/modern/utils/alias.js +91 -0
- package/dist/js/modern/utils/debug.js +2 -0
- package/dist/js/modern/utils/index.js +5 -0
- package/dist/js/modern/utils/meta.js +4 -0
- package/dist/js/modern/utils/storage.js +48 -0
- package/dist/js/modern/utils/validate.js +49 -0
- package/dist/js/node/api.js +66 -0
- package/dist/js/node/client/generate-client.js +81 -0
- package/dist/js/node/client/index.js +18 -0
- package/dist/js/node/client/result.js +32 -0
- package/dist/js/node/errors/http.js +34 -0
- package/dist/js/node/index.js +125 -0
- package/dist/js/node/operators/http.js +226 -0
- package/dist/js/node/router/constants.js +29 -0
- package/dist/js/node/router/index.js +345 -0
- package/dist/js/node/router/types.js +5 -0
- package/dist/js/node/router/utils.js +121 -0
- package/dist/js/node/types.js +59 -0
- package/dist/js/node/utils/alias.js +115 -0
- package/dist/js/node/utils/debug.js +11 -0
- package/dist/js/node/utils/index.js +72 -0
- package/dist/js/node/utils/meta.js +14 -0
- package/dist/js/node/utils/storage.js +59 -0
- package/dist/js/node/utils/validate.js +68 -0
- package/dist/types/api.d.ts +3 -0
- package/dist/types/client/generate-client.d.ts +24 -0
- package/dist/types/client/index.d.ts +1 -0
- package/dist/types/client/result.d.ts +15 -0
- package/dist/types/errors/http.d.ts +8 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/operators/http.d.ts +39 -0
- package/dist/types/router/constants.d.ts +17 -0
- package/dist/types/router/index.d.ts +51 -0
- package/dist/types/router/types.d.ts +17 -0
- package/dist/types/router/utils.d.ts +10 -0
- package/dist/types/types.d.ts +58 -0
- package/dist/types/utils/alias.d.ts +7 -0
- package/dist/types/utils/debug.d.ts +1 -0
- package/dist/types/utils/index.d.ts +5 -0
- package/dist/types/utils/meta.d.ts +2 -0
- package/dist/types/utils/storage.d.ts +5 -0
- package/dist/types/utils/validate.d.ts +5 -0
- package/package.json +2 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import compose from 'koa-compose';
|
|
3
|
+
import { validateFunction, HANDLER_WITH_META } from "./utils";
|
|
4
|
+
export function Api(...args) {
|
|
5
|
+
const handler = args.pop();
|
|
6
|
+
validateFunction(handler, 'Apihandler');
|
|
7
|
+
const operators = args;
|
|
8
|
+
const metadataHelper = {
|
|
9
|
+
getMetadata(key) {
|
|
10
|
+
return Reflect.getMetadata(key, runner);
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
setMetadata(key, value) {
|
|
14
|
+
return Reflect.defineMetadata(key, value, runner);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
for (const operator of operators) {
|
|
20
|
+
if (operator.metadata) {
|
|
21
|
+
operator.metadata(metadataHelper);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const validateHandlers = operators.filter(operator => operator.validate).map(operator => operator.validate);
|
|
26
|
+
const pipeHandlers = operators.filter(operator => operator.execute).map(operator => operator.execute);
|
|
27
|
+
|
|
28
|
+
async function runner(inputs) {
|
|
29
|
+
const executeHelper = {
|
|
30
|
+
result: null,
|
|
31
|
+
|
|
32
|
+
get inputs() {
|
|
33
|
+
return inputs;
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
set inputs(val) {
|
|
37
|
+
// eslint-disable-next-line no-param-reassign
|
|
38
|
+
inputs = val;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
};
|
|
42
|
+
const stack = [...validateHandlers, ...pipeHandlers];
|
|
43
|
+
stack.push(async (helper, next) => {
|
|
44
|
+
const res = await handler(helper.inputs);
|
|
45
|
+
helper.result = res;
|
|
46
|
+
return next();
|
|
47
|
+
});
|
|
48
|
+
await compose(stack)(executeHelper);
|
|
49
|
+
return executeHelper.result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
runner[HANDLER_WITH_META] = true;
|
|
53
|
+
return runner;
|
|
54
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import { ApiRouter } from "../router";
|
|
3
|
+
import { Ok, Err } from "./result";
|
|
4
|
+
export const DEFAULT_CLIENT_REQUEST_CREATOR = '@modern-js/create-request';
|
|
5
|
+
export const generateClient = async ({
|
|
6
|
+
resourcePath,
|
|
7
|
+
apiDir,
|
|
8
|
+
prefix,
|
|
9
|
+
port,
|
|
10
|
+
target,
|
|
11
|
+
requestCreator,
|
|
12
|
+
fetcher,
|
|
13
|
+
requireResolve: _requireResolve = require.resolve
|
|
14
|
+
}) => {
|
|
15
|
+
if (!requestCreator) {
|
|
16
|
+
// eslint-disable-next-line no-param-reassign
|
|
17
|
+
requestCreator = _requireResolve(`${DEFAULT_CLIENT_REQUEST_CREATOR}${target ? `/${target}` : ''}`).replace(/\\/g, '/');
|
|
18
|
+
} else {
|
|
19
|
+
// 这里约束传入的 requestCreator 包也必须有两个导出 client 和 server,因为目前的机制 client 和 server 要导出不同的 configure 函数;该 api 不对使用者暴露,后续可优化
|
|
20
|
+
let resolvedPath = requestCreator;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
resolvedPath = path.dirname(_requireResolve(requestCreator));
|
|
24
|
+
} catch (error) {} // eslint-disable-next-line no-param-reassign
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
requestCreator = `${resolvedPath}${target ? `/${target}` : ''}`.replace(/\\/g, '/');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const apiRouter = new ApiRouter({
|
|
31
|
+
apiDir,
|
|
32
|
+
prefix
|
|
33
|
+
});
|
|
34
|
+
const handlerInfos = apiRouter.getSingleModuleHandlers(resourcePath);
|
|
35
|
+
|
|
36
|
+
if (!handlerInfos) {
|
|
37
|
+
return Err(`generate client error: Cannot require module ${resourcePath}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let handlersCode = '';
|
|
41
|
+
|
|
42
|
+
for (const handlerInfo of handlerInfos) {
|
|
43
|
+
const {
|
|
44
|
+
name,
|
|
45
|
+
httpMethod,
|
|
46
|
+
routePath
|
|
47
|
+
} = handlerInfo;
|
|
48
|
+
let exportStatement = `const ${name} =`;
|
|
49
|
+
|
|
50
|
+
if (name.toLowerCase() === 'default') {
|
|
51
|
+
exportStatement = 'default';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const upperHttpMethod = httpMethod.toUpperCase();
|
|
55
|
+
const routeName = routePath;
|
|
56
|
+
handlersCode += `export ${exportStatement} createRequest('${routeName}', '${upperHttpMethod}', process.env.PORT || ${String(port)}${fetcher ? `, fetch` : ''});
|
|
57
|
+
`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const importCode = `import { createRequest } from '${requestCreator}';
|
|
61
|
+
${fetcher ? `import { fetch } from '${fetcher}';\n` : ''}`;
|
|
62
|
+
return Ok(`${importCode}\n${handlersCode}`);
|
|
63
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./generate-client";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
2
|
+
export const Err = value => {
|
|
3
|
+
const err = {
|
|
4
|
+
kind: 'Err',
|
|
5
|
+
value,
|
|
6
|
+
isErr: true,
|
|
7
|
+
isOk: false
|
|
8
|
+
};
|
|
9
|
+
return err;
|
|
10
|
+
}; // eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
11
|
+
|
|
12
|
+
export const Ok = value => {
|
|
13
|
+
const ok = {
|
|
14
|
+
kind: 'Ok',
|
|
15
|
+
value,
|
|
16
|
+
isErr: false,
|
|
17
|
+
isOk: true
|
|
18
|
+
};
|
|
19
|
+
return ok;
|
|
20
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
2
|
+
|
|
3
|
+
export class HttpError extends Error {
|
|
4
|
+
constructor(status, message) {
|
|
5
|
+
super(message);
|
|
6
|
+
|
|
7
|
+
_defineProperty(this, "status", void 0);
|
|
8
|
+
|
|
9
|
+
this.status = status;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
}
|
|
13
|
+
export class ValidationError extends HttpError {
|
|
14
|
+
constructor(status, message) {
|
|
15
|
+
super(status, message);
|
|
16
|
+
|
|
17
|
+
_defineProperty(this, "code", void 0);
|
|
18
|
+
|
|
19
|
+
this.code = 'VALIDATION_ERROR';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Api } from "./api";
|
|
2
|
+
export { HttpError, ValidationError } from "./errors/http";
|
|
3
|
+
export * from "./router";
|
|
4
|
+
export * from "./types";
|
|
5
|
+
export * from "./client";
|
|
6
|
+
export * from "./operators/http";
|
|
7
|
+
export { getRelativeRuntimePath, HANDLER_WITH_META, isWithMetaHandler, createStorage, registerPaths } from "./utils";
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
2
|
+
|
|
3
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
4
|
+
|
|
5
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
6
|
+
|
|
7
|
+
import { HttpMetadata, OperatorType, HttpMethod, TriggerType, ResponseMetaType } from "../types";
|
|
8
|
+
import { ValidationError } from "../errors/http";
|
|
9
|
+
|
|
10
|
+
const validateInput = async (schema, input) => {
|
|
11
|
+
try {
|
|
12
|
+
return await schema.parseAsync(input);
|
|
13
|
+
} catch (error) {
|
|
14
|
+
const {
|
|
15
|
+
z: zod
|
|
16
|
+
} = require('zod');
|
|
17
|
+
|
|
18
|
+
if (error instanceof zod.ZodError) {
|
|
19
|
+
throw new ValidationError(400, error.message);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const createHttpOperator = method => {
|
|
27
|
+
return urlPath => {
|
|
28
|
+
return {
|
|
29
|
+
name: method,
|
|
30
|
+
|
|
31
|
+
metadata({
|
|
32
|
+
setMetadata
|
|
33
|
+
}) {
|
|
34
|
+
setMetadata(OperatorType.Trigger, {
|
|
35
|
+
type: TriggerType.Http,
|
|
36
|
+
path: urlPath,
|
|
37
|
+
method
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export const Get = createHttpOperator(HttpMethod.Get);
|
|
45
|
+
export const Post = createHttpOperator(HttpMethod.Post);
|
|
46
|
+
export const Put = createHttpOperator(HttpMethod.Put);
|
|
47
|
+
export const Delete = createHttpOperator(HttpMethod.Delete);
|
|
48
|
+
export const Connect = createHttpOperator(HttpMethod.Connect);
|
|
49
|
+
export const Trace = createHttpOperator(HttpMethod.Trace);
|
|
50
|
+
export const Patch = createHttpOperator(HttpMethod.Patch);
|
|
51
|
+
export const Option = createHttpOperator(HttpMethod.Option);
|
|
52
|
+
export const Head = createHttpOperator(HttpMethod.Head);
|
|
53
|
+
export const Data = schema => {
|
|
54
|
+
return {
|
|
55
|
+
name: HttpMetadata.Data,
|
|
56
|
+
|
|
57
|
+
metadata({
|
|
58
|
+
setMetadata
|
|
59
|
+
}) {
|
|
60
|
+
setMetadata(HttpMetadata.Data, schema);
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
async validate(helper, next) {
|
|
64
|
+
const {
|
|
65
|
+
inputs: {
|
|
66
|
+
data
|
|
67
|
+
}
|
|
68
|
+
} = helper;
|
|
69
|
+
helper.inputs = _objectSpread(_objectSpread({}, helper.inputs), {}, {
|
|
70
|
+
data: await validateInput(schema, data)
|
|
71
|
+
});
|
|
72
|
+
return next();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
export const Query = schema => {
|
|
78
|
+
return {
|
|
79
|
+
name: HttpMetadata.Query,
|
|
80
|
+
|
|
81
|
+
metadata({
|
|
82
|
+
setMetadata
|
|
83
|
+
}) {
|
|
84
|
+
setMetadata(HttpMetadata.Query, schema);
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
async validate(helper, next) {
|
|
88
|
+
const {
|
|
89
|
+
inputs: {
|
|
90
|
+
query
|
|
91
|
+
}
|
|
92
|
+
} = helper;
|
|
93
|
+
helper.inputs = _objectSpread(_objectSpread({}, helper.inputs), {}, {
|
|
94
|
+
query: await validateInput(schema, query)
|
|
95
|
+
});
|
|
96
|
+
return next();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
export const Params = schema => {
|
|
102
|
+
return {
|
|
103
|
+
name: HttpMetadata.Params,
|
|
104
|
+
|
|
105
|
+
metadata({
|
|
106
|
+
setMetadata
|
|
107
|
+
}) {
|
|
108
|
+
setMetadata(HttpMetadata.Params, schema);
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
async validate(helper, next) {
|
|
112
|
+
const {
|
|
113
|
+
inputs: {
|
|
114
|
+
params
|
|
115
|
+
}
|
|
116
|
+
} = helper;
|
|
117
|
+
helper.inputs = _objectSpread(_objectSpread({}, helper.inputs), {}, {
|
|
118
|
+
params: await validateInput(schema, params)
|
|
119
|
+
});
|
|
120
|
+
return next();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
export const Headers = schema => {
|
|
126
|
+
return {
|
|
127
|
+
name: HttpMetadata.Headers,
|
|
128
|
+
|
|
129
|
+
metadata({
|
|
130
|
+
setMetadata
|
|
131
|
+
}) {
|
|
132
|
+
setMetadata(HttpMetadata.Headers, schema);
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
async validate(helper, next) {
|
|
136
|
+
const {
|
|
137
|
+
inputs: {
|
|
138
|
+
headers
|
|
139
|
+
}
|
|
140
|
+
} = helper;
|
|
141
|
+
helper.inputs = _objectSpread(_objectSpread({}, helper.inputs), {}, {
|
|
142
|
+
headers: await validateInput(schema, headers)
|
|
143
|
+
});
|
|
144
|
+
return next();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const setResponseMeta = (helper, type, value) => {
|
|
151
|
+
const responseMetaData = helper.getMetadata(HttpMetadata.Response) || [];
|
|
152
|
+
helper.setMetadata(HttpMetadata.Response, [...responseMetaData, {
|
|
153
|
+
type,
|
|
154
|
+
value
|
|
155
|
+
}]);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export const HttpCode = statusCode => {
|
|
159
|
+
return {
|
|
160
|
+
name: 'HttpCode',
|
|
161
|
+
|
|
162
|
+
metadata(helper) {
|
|
163
|
+
setResponseMeta(helper, ResponseMetaType.StatusCode, statusCode);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
export const SetHeaders = headers => {
|
|
169
|
+
return {
|
|
170
|
+
name: 'SetHeaders',
|
|
171
|
+
|
|
172
|
+
metadata(helper) {
|
|
173
|
+
setResponseMeta(helper, ResponseMetaType.Headers, headers);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
export const Redirect = url => {
|
|
179
|
+
return {
|
|
180
|
+
name: 'Redirect',
|
|
181
|
+
|
|
182
|
+
metadata(helper) {
|
|
183
|
+
setResponseMeta(helper, ResponseMetaType.Redirect, url);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
};
|
|
187
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { HttpMethod } from "../types";
|
|
2
|
+
export const AllHttpMethods = Object.values(HttpMethod);
|
|
3
|
+
export let APIMode;
|
|
4
|
+
|
|
5
|
+
(function (APIMode) {
|
|
6
|
+
APIMode["FARMEWORK"] = "framework";
|
|
7
|
+
APIMode["FUNCTION"] = "function";
|
|
8
|
+
})(APIMode || (APIMode = {}));
|
|
9
|
+
|
|
10
|
+
export const FRAMEWORK_MODE_LAMBDA_DIR = 'lambda';
|
|
11
|
+
export const FRAMEWORK_MODE_APP_DIR = 'app';
|
|
12
|
+
export const INDEX_SUFFIX = 'index';
|
|
13
|
+
export const API_DIR = 'api';
|
|
14
|
+
export const API_FILE_RULES = ['**/*.[tj]s', '!**/_*', '!**/_*/**/*.[tj]s', '!**/*.test.js', '!**/*.test.ts', '!**/*.d.ts', '!__test__/*.ts', '!__tests__/*.ts', '!node_modules/**', '!bootstrap.js'];
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
2
|
+
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fs, logger } from '@modern-js/utils';
|
|
5
|
+
import 'reflect-metadata';
|
|
6
|
+
import { HttpMethod, httpMethods, OperatorType, TriggerType } from "../types";
|
|
7
|
+
import { debug } from "../utils";
|
|
8
|
+
import { APIMode, FRAMEWORK_MODE_LAMBDA_DIR, API_FILE_RULES, FRAMEWORK_MODE_APP_DIR } from "./constants";
|
|
9
|
+
import { getFiles, getPathFromFilename, requireHandlerModule, sortRoutes } from "./utils";
|
|
10
|
+
export * from "./types";
|
|
11
|
+
export * from "./constants";
|
|
12
|
+
export class ApiRouter {
|
|
13
|
+
// lambdaDir is the dir which equal to the apiDir in function mode, and equal to the api/lambda dir in framework mode
|
|
14
|
+
constructor({
|
|
15
|
+
apiDir: _apiDir,
|
|
16
|
+
lambdaDir: _lambdaDir,
|
|
17
|
+
prefix
|
|
18
|
+
}) {
|
|
19
|
+
_defineProperty(this, "apiMode", void 0);
|
|
20
|
+
|
|
21
|
+
_defineProperty(this, "apiDir", void 0);
|
|
22
|
+
|
|
23
|
+
_defineProperty(this, "existLambdaDir", void 0);
|
|
24
|
+
|
|
25
|
+
_defineProperty(this, "lambdaDir", void 0);
|
|
26
|
+
|
|
27
|
+
_defineProperty(this, "prefix", void 0);
|
|
28
|
+
|
|
29
|
+
_defineProperty(this, "apiFiles", []);
|
|
30
|
+
|
|
31
|
+
_defineProperty(this, "getExactApiMode", apiDir => {
|
|
32
|
+
const exist = this.createExistChecker(apiDir);
|
|
33
|
+
const existLambdaDir = exist(FRAMEWORK_MODE_LAMBDA_DIR);
|
|
34
|
+
const existAppDir = exist(FRAMEWORK_MODE_APP_DIR);
|
|
35
|
+
const existAppFile = exist('app.ts') || exist('app.js');
|
|
36
|
+
|
|
37
|
+
if (existLambdaDir || existAppDir || existAppFile) {
|
|
38
|
+
return APIMode.FARMEWORK;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return APIMode.FUNCTION;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
_defineProperty(this, "createExistChecker", base => target => fs.pathExistsSync(path.resolve(base, target)));
|
|
45
|
+
|
|
46
|
+
_defineProperty(this, "getExactLambdaDir", apiDir => {
|
|
47
|
+
if (this.lambdaDir) {
|
|
48
|
+
return this.lambdaDir;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const lambdaDir = this.apiMode === APIMode.FARMEWORK ? path.join(apiDir, FRAMEWORK_MODE_LAMBDA_DIR) : apiDir;
|
|
52
|
+
return lambdaDir;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
this.validateAbsolute(_apiDir, 'apiDir');
|
|
56
|
+
this.validateAbsolute(_lambdaDir, 'lambdaDir');
|
|
57
|
+
this.prefix = this.initPrefix(prefix);
|
|
58
|
+
this.apiDir = _apiDir;
|
|
59
|
+
this.apiMode = this.getExactApiMode(_apiDir);
|
|
60
|
+
this.lambdaDir = _lambdaDir || this.getExactLambdaDir(this.apiDir);
|
|
61
|
+
this.existLambdaDir = fs.existsSync(this.lambdaDir);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
isExistLambda() {
|
|
65
|
+
return this.existLambdaDir;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
getApiMode() {
|
|
69
|
+
return this.apiMode;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
getLambdaDir() {
|
|
73
|
+
return this.lambdaDir;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
isApiFile(filename) {
|
|
77
|
+
if (this.existLambdaDir) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!this.apiFiles.includes(filename)) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
getSingleModuleHandlers(filename) {
|
|
89
|
+
const moduleInfo = this.getModuleInfo(filename);
|
|
90
|
+
|
|
91
|
+
if (moduleInfo) {
|
|
92
|
+
return this.getModuleHandlerInfos(moduleInfo);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
getHandlerInfo(filename, originFuncName, handler) {
|
|
99
|
+
const httpMethod = this.getHttpMethod(originFuncName, handler);
|
|
100
|
+
const routeName = this.getRouteName(filename, handler);
|
|
101
|
+
|
|
102
|
+
if (httpMethod && routeName) {
|
|
103
|
+
return {
|
|
104
|
+
handler,
|
|
105
|
+
name: originFuncName,
|
|
106
|
+
httpMethod,
|
|
107
|
+
routeName,
|
|
108
|
+
filename,
|
|
109
|
+
routePath: this.getRoutePath(this.prefix, routeName)
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return null;
|
|
114
|
+
} // TODO: 性能提升,开发环境,判断下 lambda 目录修改时间
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
getSafeRoutePath(filename, handler) {
|
|
118
|
+
this.loadApiFiles();
|
|
119
|
+
this.validateValidApifile(filename);
|
|
120
|
+
return this.getRouteName(filename, handler);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
getRouteName(filename, handler) {
|
|
124
|
+
if (handler) {
|
|
125
|
+
const trigger = Reflect.getMetadata(OperatorType.Trigger, handler);
|
|
126
|
+
|
|
127
|
+
if (trigger && trigger.type === TriggerType.Http) {
|
|
128
|
+
if (!trigger.path) {
|
|
129
|
+
throw new Error(`The http trigger ${trigger.name} needs to specify a path`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return trigger.path;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const routePath = getPathFromFilename(this.lambdaDir, filename);
|
|
137
|
+
return routePath;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
getHttpMethod(originHandlerName, handler) {
|
|
141
|
+
if (handler) {
|
|
142
|
+
const trigger = Reflect.getMetadata(OperatorType.Trigger, handler);
|
|
143
|
+
|
|
144
|
+
if (trigger && httpMethods.includes(trigger.method)) {
|
|
145
|
+
return trigger.method;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const upperName = originHandlerName.toUpperCase();
|
|
150
|
+
|
|
151
|
+
switch (upperName) {
|
|
152
|
+
case 'GET':
|
|
153
|
+
return HttpMethod.Get;
|
|
154
|
+
|
|
155
|
+
case 'POST':
|
|
156
|
+
return HttpMethod.Post;
|
|
157
|
+
|
|
158
|
+
case 'PUT':
|
|
159
|
+
return HttpMethod.Put;
|
|
160
|
+
|
|
161
|
+
case 'DELETE':
|
|
162
|
+
case 'DEL':
|
|
163
|
+
return HttpMethod.Delete;
|
|
164
|
+
|
|
165
|
+
case 'CONNECT':
|
|
166
|
+
return HttpMethod.Connect;
|
|
167
|
+
|
|
168
|
+
case 'TRACE':
|
|
169
|
+
return HttpMethod.Trace;
|
|
170
|
+
|
|
171
|
+
case 'PATCH':
|
|
172
|
+
return HttpMethod.Patch;
|
|
173
|
+
|
|
174
|
+
case 'OPTION':
|
|
175
|
+
return HttpMethod.Option;
|
|
176
|
+
|
|
177
|
+
case 'DEFAULT':
|
|
178
|
+
{
|
|
179
|
+
return HttpMethod.Get;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
default:
|
|
183
|
+
logger.warn(`Only api handlers are allowd to be exported, please remove the function ${originHandlerName} from exports`);
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
loadApiFiles() {
|
|
189
|
+
if (!this.existLambdaDir) {
|
|
190
|
+
return [];
|
|
191
|
+
} // eslint-disable-next-line no-multi-assign
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
const apiFiles = this.apiFiles = getFiles(this.lambdaDir, API_FILE_RULES);
|
|
195
|
+
return apiFiles;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
getApiFiles() {
|
|
199
|
+
if (!this.existLambdaDir) {
|
|
200
|
+
return [];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (this.apiFiles.length > 0) {
|
|
204
|
+
return this.apiFiles;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return this.loadApiFiles();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
getApiHandlers() {
|
|
211
|
+
const filenames = this.getApiFiles();
|
|
212
|
+
const moduleInfos = this.getModuleInfos(filenames);
|
|
213
|
+
const apiHandlers = this.getHandlerInfos(moduleInfos);
|
|
214
|
+
debug('apiHandlers', apiHandlers.length, apiHandlers);
|
|
215
|
+
return apiHandlers;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* 如果用户未传入或传入空串,默认为 /api
|
|
219
|
+
* 如果传入 /,则 prefix 为 /
|
|
220
|
+
*/
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
initPrefix(prefix) {
|
|
224
|
+
if (prefix === '/') {
|
|
225
|
+
return '';
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return prefix || '/api';
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
validateAbsolute(filename, paramsName) {
|
|
232
|
+
if (typeof filename === 'string' && !path.isAbsolute(filename)) {
|
|
233
|
+
throw new Error(`The ${paramsName} ${filename} is not a abolute path`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
getModuleInfos(filenames) {
|
|
238
|
+
return filenames.map(filename => this.getModuleInfo(filename)).filter(moduleInfo => Boolean(moduleInfo));
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
getModuleInfo(filename) {
|
|
242
|
+
try {
|
|
243
|
+
const module = requireHandlerModule(filename);
|
|
244
|
+
return {
|
|
245
|
+
filename,
|
|
246
|
+
module
|
|
247
|
+
};
|
|
248
|
+
} catch (err) {
|
|
249
|
+
if (process.env.NODE_ENV === 'production') {
|
|
250
|
+
throw err;
|
|
251
|
+
} else {
|
|
252
|
+
console.error(err);
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
getHandlerInfos(moduleInfos) {
|
|
259
|
+
let apiHandlers = [];
|
|
260
|
+
moduleInfos.forEach(moduleInfo => {
|
|
261
|
+
const handlerInfos = this.getModuleHandlerInfos(moduleInfo);
|
|
262
|
+
|
|
263
|
+
if (handlerInfos) {
|
|
264
|
+
apiHandlers = apiHandlers.concat(handlerInfos);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
const sortedHandlers = sortRoutes(apiHandlers);
|
|
268
|
+
return sortedHandlers;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
getModuleHandlerInfos(moduleInfo) {
|
|
272
|
+
const {
|
|
273
|
+
module,
|
|
274
|
+
filename
|
|
275
|
+
} = moduleInfo;
|
|
276
|
+
return Object.entries(module).filter(([, handler]) => typeof handler === 'function').map(([key]) => {
|
|
277
|
+
const handler = module[key];
|
|
278
|
+
const handlerInfo = this.getHandlerInfo(filename, key, handler);
|
|
279
|
+
return handlerInfo;
|
|
280
|
+
}).filter(handlerInfo => Boolean(handlerInfo));
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
validateValidApifile(filename) {
|
|
284
|
+
if (!this.apiFiles.includes(filename)) {
|
|
285
|
+
throw new Error(`The ${filename} is not a valid api file.`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
getRoutePath(prefix, routeName) {
|
|
290
|
+
const finalRouteName = routeName === '/' ? '' : routeName;
|
|
291
|
+
|
|
292
|
+
if (prefix === '' && finalRouteName === '') {
|
|
293
|
+
return '/';
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return `${prefix}${finalRouteName}`;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|