1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | const express_1 = __importDefault(require("express"));
|
7 | const body_parser_1 = __importDefault(require("body-parser"));
|
8 | const cookie_parser_1 = __importDefault(require("cookie-parser"));
|
9 | const lodash_1 = require("lodash");
|
10 | const APIConfig_1 = require("./lib/APIConfig");
|
11 | exports.APIConfig = APIConfig_1.APIConfig;
|
12 | const path_1 = __importDefault(require("path"));
|
13 | const APIUtils_1 = require("./lib/APIUtils");
|
14 | exports.APIUtils = APIUtils_1.APIUtils;
|
15 | require("reflect-metadata");
|
16 | const APIResponse_1 = require("./lib/APIResponse");
|
17 | exports.APIResponse = APIResponse_1.APIResponse;
|
18 | const APIError_1 = require("./lib/APIError");
|
19 | exports.APIError = APIError_1.APIError;
|
20 | const KVService_1 = require("./lib/Services/KeyValue/KVService");
|
21 | exports.APIKVService = KVService_1.KVService;
|
22 | const FileService_1 = require("./lib/Services/File/FileService");
|
23 | exports.APIFileService = FileService_1.FileService;
|
24 | const Config_1 = require("./lib/Services/Config");
|
25 | exports.EnvVarSync = Config_1.EnvVarSync;
|
26 | const APIAuthUtils_1 = require("./lib/APIAuthUtils");
|
27 | exports.APIAuthUtils = APIAuthUtils_1.APIAuthUtils;
|
28 | function _createHandlerWrapperFunction(handlerData, thisObject) {
|
29 | return (req, res, next) => {
|
30 | let apiResponse = new APIResponse_1.APIResponse(req, res, next);
|
31 |
|
32 | if (handlerData.options.requireAuthentication) {
|
33 | if (!req.auth || !req.auth.isAuthenticated || req.auth.isExpired) {
|
34 | apiResponse.withError(APIError_1.APIError.create401UnauthorizedError());
|
35 | return;
|
36 | }
|
37 | }
|
38 | let handlerArgs = [];
|
39 | let validationErrors = [];
|
40 |
|
41 | for (let index = 0; index < handlerData.handlerParameterNames.length; index++) {
|
42 | let paramData = handlerData.handlerParameterData[index];
|
43 | let paramOptions = lodash_1.get(paramData, "paramOptions", {});
|
44 | let paramName = APIUtils_1.APIUtils.coalesce(paramOptions.rawName, handlerData.handlerParameterNames[index]);
|
45 |
|
46 | if ((index === handlerData.handlerParameterNames.length - 1 || index === handlerData.handlerParameterNames.length - 2) && ["req", "request", "res", "response"].indexOf(paramName.toLowerCase()) >= 0) {
|
47 | continue;
|
48 | }
|
49 | let paramSources = lodash_1.castArray(lodash_1.get(paramOptions, "sources", ["params", "query", "body", "cookie", "headers"]));
|
50 | let paramValue;
|
51 | if (req.auth && paramData.paramType === "APIAuthUser") {
|
52 | paramValue = APIAuthUtils_1.APIAuthUtils.getAPIAuthUserFromAuthCredentials(req.auth);
|
53 | }
|
54 | else {
|
55 | for (let paramSource of paramSources) {
|
56 | let paramValues = lodash_1.get(req, paramSource);
|
57 | if (lodash_1.isNil(paramValues)) {
|
58 | continue;
|
59 | }
|
60 | if (paramOptions.includeFullSource ||
|
61 | (/[\.\[\]]/g).test(paramSource)
|
62 | ) {
|
63 | paramValue = paramValues;
|
64 | break;
|
65 | }
|
66 | else {
|
67 | if (lodash_1.has(paramValues, paramName)) {
|
68 | paramValue = paramValues[paramName];
|
69 | if (paramSource === "query") {
|
70 | paramValue = decodeURIComponent(paramValue);
|
71 | }
|
72 | break;
|
73 | }
|
74 | }
|
75 | }
|
76 | }
|
77 | let argValue = APIUtils_1.APIUtils.coalesce(paramValue, paramOptions.defaultValue);
|
78 | if (paramOptions.processor) {
|
79 | try {
|
80 | argValue = paramOptions.processor(argValue, req);
|
81 | }
|
82 | catch (error) {
|
83 | validationErrors.push({
|
84 | parameter: paramName,
|
85 | message: error.message || error.toString()
|
86 | });
|
87 | continue;
|
88 | }
|
89 | }
|
90 | if (lodash_1.isNil(argValue)) {
|
91 |
|
92 | if (!lodash_1.get(paramOptions, "optional", false)) {
|
93 | validationErrors.push({
|
94 | parameter: paramName,
|
95 | message: "missing"
|
96 | });
|
97 | }
|
98 | handlerArgs.push(undefined);
|
99 | continue;
|
100 | }
|
101 | argValue = APIUtils_1.APIUtils.convertToType(argValue, paramData.paramRawType);
|
102 | if (lodash_1.isNil(argValue) || lodash_1.isNaN(argValue)) {
|
103 | validationErrors.push({
|
104 | parameter: paramName,
|
105 | message: "invalid"
|
106 | });
|
107 | continue;
|
108 | }
|
109 | handlerArgs.push(argValue);
|
110 | }
|
111 | if (validationErrors.length > 0) {
|
112 | apiResponse.withError(APIError_1.APIError.createValidationError(validationErrors));
|
113 | return;
|
114 | }
|
115 | apiResponse.processHandlerFunction(thisObject, handlerData.handlerFunction, handlerArgs, handlerData.options.disableFriendlyResponse, handlerData.options.successResponse);
|
116 | };
|
117 | }
|
118 | function _loadAPI(apiRouter, apiDefinition) {
|
119 | let apiModule;
|
120 | try {
|
121 | apiModule = require(path_1.default.resolve(process.cwd(), apiDefinition.require));
|
122 | }
|
123 | catch (e) {
|
124 | console.error(e);
|
125 | return null;
|
126 | }
|
127 | if (lodash_1.isNil(apiModule)) {
|
128 | return null;
|
129 | }
|
130 | let moduleName = APIUtils_1.APIUtils.coalesce(apiDefinition.moduleName, path_1.default.basename(apiDefinition.require));
|
131 | let apiClass = APIUtils_1.APIUtils.coalesce(apiModule[moduleName], apiModule.default, apiModule);
|
132 | let apiInstance;
|
133 | lodash_1.each(lodash_1.get(apiClass, "__handlerData", {}), (handlerData, name) => {
|
134 |
|
135 | if (handlerData.isInstance && lodash_1.isNil(apiInstance)) {
|
136 | apiInstance = new apiClass();
|
137 | }
|
138 | let options = handlerData.options;
|
139 | let argsArray = [options.path];
|
140 | if (options.middleware) {
|
141 | argsArray = argsArray.concat(lodash_1.castArray(options.middleware));
|
142 | }
|
143 | let handlerWrapper = _createHandlerWrapperFunction(handlerData, handlerData.isInstance ? apiInstance : apiClass);
|
144 | argsArray.push(handlerWrapper);
|
145 | apiRouter[options.method.toLowerCase()].apply(apiRouter, argsArray);
|
146 | });
|
147 | }
|
148 | class APILove {
|
149 | static start(options) {
|
150 | if (options.loadStandardMiddleware !== false) {
|
151 | this.app.use(cookie_parser_1.default());
|
152 | this.app.use(body_parser_1.default.json({ limit: "50mb" }));
|
153 | this.app.use(body_parser_1.default.urlencoded({ limit: "50mb", extended: false, parameterLimit: 50000 }));
|
154 | this.app.use(body_parser_1.default.text({ limit: "50mb" }));
|
155 | this.app.use((req, res, next) => {
|
156 | req.auth = APIAuthUtils_1.APIAuthUtils.getAuthCredentialsFromRequest(req, true);
|
157 | next();
|
158 | });
|
159 | }
|
160 | for (let mw of lodash_1.get(options, "middleware", [])) {
|
161 | this.app.use(mw);
|
162 | }
|
163 |
|
164 | for (let api of lodash_1.get(options, "apis", [])) {
|
165 | if (lodash_1.isNil(api.apiPath)) {
|
166 | api.apiPath = "";
|
167 | }
|
168 | if (APIConfig_1.APIConfig.LAZY_LOAD_APIS) {
|
169 | let apiRouter;
|
170 | this.app.use(api.apiPath, (req, res, next) => {
|
171 |
|
172 | if (!apiRouter) {
|
173 | apiRouter = express_1.default.Router();
|
174 | _loadAPI(apiRouter, api);
|
175 | }
|
176 | apiRouter(req, res, next);
|
177 | });
|
178 | }
|
179 | else {
|
180 | let apiRouter = express_1.default.Router();
|
181 | _loadAPI(apiRouter, api);
|
182 | this.app.use(api.apiPath, apiRouter);
|
183 | }
|
184 | }
|
185 | if (!lodash_1.isNil(options.defaultRouteHandler)) {
|
186 | this.app.use(options.defaultRouteHandler);
|
187 | }
|
188 |
|
189 | if (!lodash_1.isNil(options.defaultErrorHandler)) {
|
190 | this.app.use(options.defaultErrorHandler);
|
191 | }
|
192 | else {
|
193 | this.app.use((error, req, res, next) => {
|
194 | if (error instanceof APIError_1.APIError) {
|
195 | let apiError = error;
|
196 | res.status(apiError.statusCode).send(APIConfig_1.APIConfig.OUTPUT_HAPI_RESULTS ? apiError.hapiOut() : apiError.out());
|
197 | }
|
198 | else {
|
199 | let apiResponse = new APIResponse_1.APIResponse(res, res);
|
200 | apiResponse.withError(error);
|
201 | }
|
202 | });
|
203 | }
|
204 | if (APIConfig_1.APIConfig.RUN_AS_SERVER) {
|
205 | this.app.listen(APIConfig_1.APIConfig.WEB_PORT, () => console.log(`API listening on port ${APIConfig_1.APIConfig.WEB_PORT}`));
|
206 | return this.app;
|
207 | }
|
208 | else {
|
209 | let serverless = require("serverless-http");
|
210 | return serverless(this.app, { callbackWaitsForEmptyEventLoop: !!options.callbackWaitsForEmptyEventLoop });
|
211 | }
|
212 | }
|
213 | }
|
214 | exports.APILove = APILove;
|
215 | APILove.app = express_1.default();
|
216 | function APIParameter(options) {
|
217 | return function (target, key, parameterIndex) {
|
218 | let isInstance = lodash_1.isNil(target.prototype);
|
219 | let theClass = isInstance ? target.constructor : target.prototype.constructor;
|
220 | let handlerData = lodash_1.get(theClass, `__handlerData.${key}`, {});
|
221 | lodash_1.set(handlerData, `handlerParameterData.${parameterIndex}.paramOptions`, options);
|
222 | lodash_1.set(theClass, `__handlerData.${key}`, handlerData);
|
223 | };
|
224 | }
|
225 | exports.APIParameter = APIParameter;
|
226 | function APIEndpoint(options) {
|
227 | return function (target, key, descriptor) {
|
228 | let isInstance = lodash_1.isNil(target.prototype);
|
229 | let theClass = isInstance ? target.constructor : target.prototype.constructor;
|
230 | let handlerData = lodash_1.get(theClass, `__handlerData.${key}`, {});
|
231 | options = lodash_1.defaultsDeep({}, options, {
|
232 | method: "get",
|
233 | path: "/"
|
234 | });
|
235 | let parameterMetadata = Reflect.getMetadata("design:paramtypes", target, key);
|
236 | let parameterNames = APIUtils_1.APIUtils.getFunctionParamNames(descriptor.value);
|
237 | handlerData.isInstance = isInstance;
|
238 | handlerData.handlerFunction = descriptor.value;
|
239 | handlerData.options = options;
|
240 | handlerData.handlerParameterNames = parameterNames;
|
241 | for (let parameterIndex = 0; parameterIndex < parameterNames.length; parameterIndex++) {
|
242 | lodash_1.set(handlerData, `handlerParameterData.${parameterIndex}.paramRawType`, APIUtils_1.APIUtils.getRawTypeName(parameterMetadata[parameterIndex].prototype));
|
243 | lodash_1.set(handlerData, `handlerParameterData.${parameterIndex}.paramType`, parameterMetadata[parameterIndex].name);
|
244 | lodash_1.set(handlerData, `handlerParameterData.${parameterIndex}.paramName`, parameterNames[parameterIndex]);
|
245 | }
|
246 | lodash_1.set(theClass, `__handlerData.${key}`, handlerData);
|
247 | };
|
248 | }
|
249 | exports.APIEndpoint = APIEndpoint;
|
250 |
|
\ | No newline at end of file |