import {APIGatewayProxyEvent, APIGatewayProxyResult} from "aws-lambda"; import {Response} from './response'; import {match} from 'path-to-regexp'; import {MultipartBody} from "request"; export type C4CApiHandler = (req: C4CApiRequest, res: C4CApiResponse, next: () => void, options?: Record) => Promise; export type AddRoutes = (sr: Router) => {}; export type ContinueFlag = { result?: any, next: boolean }; export {Simulator} from "./simulator"; export * as bodyParser from './middlewares/body.parser'; export * as staticHandler from './middlewares/static.handler'; export * as cookieParser from './middlewares/cookie.parser'; export * as protocolMiddleware from './middlewares/protocol.middleware'; export interface C4CApiRequest extends APIGatewayProxyEvent { params?: Record; _body?: MultipartBody; cookies?: Record; sd?: Record; } export interface C4CApiResponse extends Response { multiValueHeaders?: Record; } export interface C4CScfContext extends Record { } export class Router { private readonly _handlers: any[]; private readonly _request: C4CApiRequest; private readonly options: Record; public _response: Response; constructor(request: C4CApiRequest, options?: Record) { this._handlers = []; this._request = request; this.options = options || {}; this._response = new Response(this._request, this.options); } add(paths: C4CApiHandler | string | string[], handler?: C4CApiHandler, method?: string) { let fixedPaths: string[]; const pathPrefix = this.options.pathPrefix || ''; if (typeof paths === 'function') { handler = paths; if (!pathPrefix) { this._handlers.push({func: handler}); return; } else { paths = ['']; fixedPaths = [pathPrefix || '']; } } if (method === 'ALL' || method === this._request.httpMethod) { if (!(paths instanceof Array)) { paths = [paths]; } fixedPaths = paths.map((path) => { return `${pathPrefix}${path}`; }); for (const path of fixedPaths) { const regTester = match(path, {decode: decodeURIComponent}); const testResult = regTester(this._request.path); if (testResult) { this._handlers.push({ func: handler, params: testResult.params, path }); } } } } extends(prefix: string | AddRoutes, addRoute?: AddRoutes | string) { let sr; if (typeof prefix === 'function') { sr = new Router(this._request); addRoute = prefix; } else { sr = new Router(this._request, {pathPrefix: prefix}); } (addRoute as AddRoutes)(sr); for (const handler of sr._handlers) { this._handlers.push(handler); } } put(paths: string | C4CApiHandler, handler?: C4CApiHandler) { this.add(paths, handler, 'PUT'); } get(paths: string | C4CApiHandler, handler?: C4CApiHandler) { this.add(paths, handler, 'GET'); } post(paths: string | C4CApiHandler, handler?: C4CApiHandler) { this.add(paths, handler, 'POST'); } del(paths: string | C4CApiHandler, handler?: C4CApiHandler) { this.add(paths, handler, 'DELETE'); } use(paths: string | C4CApiHandler, handler?: C4CApiHandler) { this.add(paths, handler, 'ALL'); } executeHandler(handler: { func: C4CApiHandler, params: Record }, flags: ContinueFlag): Promise<{ continue: boolean, result?: any }> { return new Promise(async (resolve, reject) => { try { this._response.finally(() => { if (flags.next) { console.error('the next() was executed, so there is no result'); } else { flags.result = true; resolve({ continue: false, result: this._response.result }); } }); this._request.params = handler.params; await handler.func( this._request, this._response, () => { if (flags.result) { console.error('the response has been responded'); } else { flags.next = true; resolve({ continue: true }); } }, this.options ); } catch (e) { reject(e); } }); } /** * start the route server */ async serve() { for (const handler of this._handlers) { const flags = { next: false, result: false }; const out = await this.executeHandler(handler, flags); if (!out.continue) { return out.result; } } } }