UNPKG

@scloud/lambda-local

Version:

Run typical Lambda handlers locally.

92 lines 13.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.webApiLocal = webApiLocal; const express_1 = __importDefault(require("express")); function webApiLocal(lambdaHandler, debug = false) { const port = +(process.env.port || '3000'); const app = (0, express_1.default)(); // https://stackoverflow.com/questions/12345166/how-to-force-parse-request-body-as-plain-text-instead-of-json-in-express app.use(express_1.default.text({ type: '*/*' })); app.use(async (req, res) => { // const url = new URL(req.originalUrl, 'https://example.com'); // Headers - NB it seems that in Lambda multiValueHeaders always contains the values from headers const headers = {}; const multiValueHeaders = {}; Object.keys(req.headers).forEach((header) => { if (req.headers[header] === undefined) { headers[header] = undefined; multiValueHeaders[header] = undefined; } else if (typeof req.headers[header] === 'string') { headers[header] = req.headers[header]; multiValueHeaders[header] = (multiValueHeaders[header] || []).concat([req.headers[header]]); } else if (Array.isArray(req.headers[header])) { multiValueHeaders[header] = (multiValueHeaders[header] || []).concat(req.headers[header]); } }); // Query string - basic translation const queryStringParameters = {}; const multiValueQueryStringParameters = {}; for (const name of Object.keys(req.query)) { const value = req.query[name]; if (typeof value === 'string') queryStringParameters[name] = value; } const event = { body: typeof req.body === 'string' ? req.body : JSON.stringify(req.body), headers, multiValueHeaders, httpMethod: req.method, path: req.path, queryStringParameters, multiValueQueryStringParameters, requestContext: { httpMethod: req.method, path: req.path, protocol: req.protocol, }, }; // Print out the event that will be sent to the handler if (debug) { console.log('Event:'); console.log(event.httpMethod, event.path); console.log(JSON.stringify(event, null, 2)); } try { // Invoke the function handler: const result = await lambdaHandler(event, {}); // Print out the result if (debug) { console.log('Result:'); console.log(event.httpMethod, event.path, result.statusCode); console.log(JSON.stringify(result.body, null, 2)); } // Headers res.status(result.statusCode); for (const key of Object.keys(result.multiValueHeaders || [])) { res.set(key, result.multiValueHeaders[key].map((value) => `${value}`)); } ; for (const key of Object.keys(result.headers || [])) { res.set(key, `${result.headers[key]}`); } ; // Body res.send(result.body); } catch (e) { // Log the error and send a 500 response console.log(e); console.log(e.stack); res.status(500).send(`${e}`); } }); app.listen(port, () => { console.log(`Lambda handler can be invoked at http://localhost:${port}`); }); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViQXBpTG9jYWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd2ViQXBpTG9jYWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFHQSxrQ0EwRkM7QUE3RkQsc0RBQXFEO0FBR3JELFNBQWdCLFdBQVcsQ0FBQyxhQUFnRyxFQUFFLEtBQUssR0FBRyxLQUFLO0lBQ3pJLE1BQU0sSUFBSSxHQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxNQUFNLENBQUMsQ0FBQztJQUMzQyxNQUFNLEdBQUcsR0FBRyxJQUFBLGlCQUFPLEdBQUUsQ0FBQztJQUV0Qix3SEFBd0g7SUFDeEgsR0FBRyxDQUFDLEdBQUcsQ0FBQyxpQkFBTyxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFFdkMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsR0FBWSxFQUFFLEdBQWEsRUFBRSxFQUFFO1FBQzVDLCtEQUErRDtRQUMvRCxpR0FBaUc7UUFDakcsTUFBTSxPQUFPLEdBQXVDLEVBQUUsQ0FBQztRQUN2RCxNQUFNLGlCQUFpQixHQUF5QyxFQUFFLENBQUM7UUFDbkUsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUU7WUFDMUMsSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUN0QyxPQUFPLENBQUMsTUFBTSxDQUFDLEdBQUcsU0FBUyxDQUFDO2dCQUM1QixpQkFBaUIsQ0FBQyxNQUFNLENBQUMsR0FBRyxTQUFTLENBQUM7WUFDeEMsQ0FBQztpQkFBTSxJQUFJLE9BQU8sR0FBRyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDbkQsT0FBTyxDQUFDLE1BQU0sQ0FBQyxHQUFH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IFJlcXVlc3QsIFJlc3BvbnNlIH0gZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgeyBBUElHYXRld2F5UHJveHlFdmVudCwgQVBJR2F0ZXdheVByb3h5UmVzdWx0LCBDb250ZXh0IH0gZnJvbSAnYXdzLWxhbWJkYSc7XG5cbmV4cG9ydCBmdW5jdGlvbiB3ZWJBcGlMb2NhbChsYW1iZGFIYW5kbGVyOiAoZXZlbnQ6IEFQSUdhdGV3YXlQcm94eUV2ZW50LCBjb250ZXh0OiBDb250ZXh0KSA9PiBQcm9taXNlPEFQSUdhdGV3YXlQcm94eVJlc3VsdD4sIGRlYnVnID0gZmFsc2UpIHtcbiAgY29uc3QgcG9ydCA9ICsocHJvY2Vzcy5lbnYucG9ydCB8fCAnMzAwMCcpO1xuICBjb25zdCBhcHAgPSBleHByZXNzKCk7XG5cbiAgLy8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTIzNDUxNjYvaG93LXRvLWZvcmNlLXBhcnNlLXJlcXVlc3QtYm9keS1hcy1wbGFpbi10ZXh0LWluc3RlYWQtb2YtanNvbi1pbi1leHByZXNzXG4gIGFwcC51c2UoZXhwcmVzcy50ZXh0KHsgdHlwZTogJyovKicgfSkpO1xuXG4gIGFwcC51c2UoYXN5bmMgKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSkgPT4ge1xuICAgIC8vIGNvbnN0IHVybCA9IG5ldyBVUkwocmVxLm9yaWdpbmFsVXJsLCAnaHR0cHM6Ly9leGFtcGxlLmNvbScpO1xuICAgIC8vIEhlYWRlcnMgLSBOQiBpdCBzZWVtcyB0aGF0IGluIExhbWJkYSBtdWx0aVZhbHVlSGVhZGVycyBhbHdheXMgY29udGFpbnMgdGhlIHZhbHVlcyBmcm9tIGhlYWRlcnNcbiAgICBjb25zdCBoZWFkZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCB1bmRlZmluZWQ+ID0ge307XG4gICAgY29uc3QgbXVsdGlWYWx1ZUhlYWRlcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZ1tdIHwgdW5kZWZpbmVkPiA9IHt9O1xuICAgIE9iamVjdC5rZXlzKHJlcS5oZWFkZXJzKS5mb3JFYWNoKChoZWFkZXIpID0+IHtcbiAgICAgIGlmIChyZXEuaGVhZGVyc1toZWFkZXJdID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgaGVhZGVyc1toZWFkZXJdID0gdW5kZWZpbmVkO1xuICAgICAgICBtdWx0aVZhbHVlSGVhZGVyc1toZWFkZXJdID0gdW5kZWZpbmVkO1xuICAgICAgfSBlbHNlIGlmICh0eXBlb2YgcmVxLmhlYWRlcnNbaGVhZGVyXSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgaGVhZGVyc1toZWFkZXJdID0gcmVxLmhlYWRlcnNbaGVhZGVyXTtcbiAgICAgICAgbXVsdGlWYWx1ZUhlYWRlcnNbaGVhZGVyXSA9IChtdWx0aVZhbHVlSGVhZGVyc1toZWFkZXJdIHx8IFtdKS5jb25jYXQoW3JlcS5oZWFkZXJzW2hlYWRlcl1dKTtcbiAgICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShyZXEuaGVhZGVyc1toZWFkZXJdKSkge1xuICAgICAgICBtdWx0aVZhbHVlSGVhZGVyc1toZWFkZXJdID0gKG11bHRpVmFsdWVIZWFkZXJzW2hlYWRlcl0gfHwgW10pLmNvbmNhdChyZXEuaGVhZGVyc1toZWFkZXJdKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIFF1ZXJ5IHN0cmluZyAtIGJhc2ljIHRyYW5zbGF0aW9uXG4gICAgY29uc3QgcXVlcnlTdHJpbmdQYXJhbWV0ZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCB1bmRlZmluZWQ+ID0ge307XG4gICAgY29uc3QgbXVsdGlWYWx1ZVF1ZXJ5U3RyaW5nUGFyYW1ldGVyczogUmVjb3JkPHN0cmluZywgc3RyaW5nW10gfCB1bmRlZmluZWQ+ID0ge307XG4gICAgZm9yIChjb25zdCBuYW1lIG9mIE9iamVjdC5rZXlzKHJlcS5xdWVyeSkpIHtcbiAgICAgIGNvbnN0IHZhbHVlID0gcmVxLnF1ZXJ5W25hbWVdO1xuICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHF1ZXJ5U3RyaW5nUGFyYW1ldGVyc1tuYW1lXSA9IHZhbHVlO1xuICAgIH1cblxuICAgIGNvbnN0IGV2ZW50OiBBUElHYXRld2F5UHJveHlFdmVudCA9IHtcbiAgICAgIGJvZHk6IHR5cGVvZiByZXEuYm9keSA9PT0gJ3N0cmluZycgPyByZXEuYm9keSA6IEpTT04uc3RyaW5naWZ5KHJlcS5ib2R5KSxcbiAgICAgIGhlYWRlcnMsXG4gICAgICBtdWx0aVZhbHVlSGVhZGVycyxcbiAgICAgIGh0dHBNZXRob2Q6IHJlcS5tZXRob2QsXG4gICAgICBwYXRoOiByZXEucGF0aCxcbiAgICAgIHF1ZXJ5U3RyaW5nUGFyYW1ldGVycyxcbiAgICAgIG11bHRpVmFsdWVRdWVyeVN0cmluZ1BhcmFtZXRlcnMsXG4gICAgICByZXF1ZXN0Q29udGV4dDoge1xuICAgICAgICBodHRwTWV0aG9kOiByZXEubWV0aG9kLFxuICAgICAgICBwYXRoOiByZXEucGF0aCxcbiAgICAgICAgcHJvdG9jb2w6IHJlcS5wcm90b2NvbCxcbiAgICAgIH0gYXMgdW5rbm93biBhcyBBUElHYXRld2F5UHJveHlFdmVudFsncmVxdWVzdENvbnRleHQnXSxcbiAgICB9IGFzIHVua25vd24gYXMgQVBJR2F0ZXdheVByb3h5RXZlbnQ7XG5cbiAgICAvLyBQcmludCBvdXQgdGhlIGV2ZW50IHRoYXQgd2lsbCBiZSBzZW50IHRvIHRoZSBoYW5kbGVyXG4gICAgaWYgKGRlYnVnKSB7XG4gICAgICBjb25zb2xlLmxvZygnRXZlbnQ6Jyk7XG4gICAgICBjb25zb2xlLmxvZyhldmVudC5odHRwTWV0aG9kLCBldmVudC5wYXRoKTtcbiAgICAgIGNvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KGV2ZW50LCBudWxsLCAyKSk7XG4gICAgfVxuXG4gICAgdHJ5IHtcblxuICAgICAgLy8gSW52b2tlIHRoZSBmdW5jdGlvbiBoYW5kbGVyOlxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgbGFtYmRhSGFuZGxlcihldmVudCwge30gYXMgQ29udGV4dCk7XG5cbiAgICAgIC8vIFByaW50IG91dCB0aGUgcmVzdWx0XG4gICAgICBpZiAoZGVidWcpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ1Jlc3VsdDonKTtcbiAgICAgICAgY29uc29sZS5sb2coZXZlbnQuaHR0cE1ldGhvZCwgZXZlbnQucGF0aCwgcmVzdWx0LnN0YXR1c0NvZGUpO1xuICAgICAgICBjb25zb2xlLmxvZyhKU09OLnN0cmluZ2lmeShyZXN1bHQuYm9keSwgbnVsbCwgMikpO1xuICAgICAgfVxuXG4gICAgICAvLyBIZWFkZXJzXG4gICAgICByZXMuc3RhdHVzKHJlc3VsdC5zdGF0dXNDb2RlKTtcbiAgICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHJlc3VsdC5tdWx0aVZhbHVlSGVhZGVycyB8fCBbXSkpIHtcbiAgICAgICAgcmVzLnNldChrZXksIHJlc3VsdC5tdWx0aVZhbHVlSGVhZGVycyFba2V5XS5tYXAoKHZhbHVlKSA9PiBgJHt2YWx1ZX1gKSk7XG4gICAgICB9O1xuXG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhyZXN1bHQuaGVhZGVycyB8fCBbXSkpIHtcbiAgICAgICAgcmVzLnNldChrZXksIGAke3Jlc3VsdC5oZWFkZXJzIVtrZXldfWApO1xuICAgICAgfTtcblxuICAgICAgLy8gQm9keVxuICAgICAgcmVzLnNlbmQocmVzdWx0LmJvZHkpO1xuXG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgLy8gTG9nIHRoZSBlcnJvciBhbmQgc2VuZCBhIDUwMCByZXNwb25zZVxuICAgICAgY29uc29sZS5sb2coZSk7XG4gICAgICBjb25zb2xlLmxvZygoZSBhcyBFcnJvcikuc3RhY2spO1xuICAgICAgcmVzLnN0YXR1cyg1MDApLnNlbmQoYCR7ZX1gKTtcbiAgICB9XG4gIH0pO1xuXG4gIGFwcC5saXN0ZW4ocG9ydCwgKCkgPT4ge1xuICAgIGNvbnNvbGUubG9nKGBMYW1iZGEgaGFuZGxlciBjYW4gYmUgaW52b2tlZCBhdCBodHRwOi8vbG9jYWxob3N0OiR7cG9ydH1gKTtcbiAgfSk7XG59XG4iXX0=