lambda-local
Advanced tools
Comparing version 2.0.3 to 2.1.0
@@ -31,2 +31,3 @@ #!/usr/bin/env node | ||
.option('-h, --handler <handler name>', '(optional) Lambda function handler name. Default is \'handler\'.') | ||
.option('--esm', '(optional) Load lambda function as ECMAScript module.') | ||
.option('-t, --timeout <timeout seconds>', '(optional) Seconds until lambda function timeout. Default is 3 seconds.') | ||
@@ -46,3 +47,3 @@ .option('-r, --region <aws region>', '(optional) default set to us-east-1') | ||
.parse(process.argv); | ||
var eventPath = program.eventPath, lambdaPath = program.lambdaPath, lambdaHandler = program.handler, profilePath = program.profilePath, profileName = program.profile, region = program.region, environment = program.environment, envdestroy = program.envdestroy, envfile = program.envfile, callbackWaitsForEmptyEventLoop = program.waitEmptyEventLoop, verboseLevel = program.verboselevel; | ||
var eventPath = program.eventPath, lambdaPath = program.lambdaPath, lambdaHandler = program.handler, esm = program.esm, profilePath = program.profilePath, profileName = program.profile, region = program.region, environment = program.environment, envdestroy = program.envdestroy, envfile = program.envfile, callbackWaitsForEmptyEventLoop = program.waitEmptyEventLoop, verboseLevel = program.verboselevel; | ||
var port; | ||
@@ -122,2 +123,12 @@ if (program.watch) { | ||
} | ||
if (esm) { | ||
if (utils.get_node_major_version() < 12) { | ||
console.log("Loading ESCMAScript modules not available on NodeJS < 12.0.0."); | ||
process.exit(1); | ||
} | ||
if (program.watch) { | ||
console.log("Watch mode not supported for ECMAScript lambda modules."); | ||
process.exit(1); | ||
} | ||
} | ||
var event = function () { | ||
@@ -135,2 +146,3 @@ if (program.watch) | ||
lambdaHandler: lambdaHandler, | ||
esm: esm, | ||
profilePath: profilePath, | ||
@@ -137,0 +149,0 @@ profileName: profileName, |
@@ -1,2 +0,2 @@ | ||
export declare const version = "2.0.0"; | ||
export declare const version = "2.1.0"; | ||
export declare function setLogger(_logger: any): void; | ||
@@ -3,0 +3,0 @@ export declare function getLogger(): any; |
@@ -28,3 +28,3 @@ 'use strict'; | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
while (g && (g = 0, op[0] && (_ = 0)), _) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
@@ -64,6 +64,7 @@ if (y = 0, t) op = [op[0] & 2, t.value]; | ||
var Context = require("./lib/context.js"); | ||
require("./lib/streaming.js"); | ||
/* | ||
* Lambda local version | ||
*/ | ||
exports.version = "2.0.0"; | ||
exports.version = "2.1.0"; | ||
var logger = utils.getWinstonConsole(); | ||
@@ -119,4 +120,2 @@ function setLogger(_logger) { | ||
try { | ||
if (req.headers['content-type'] !== 'application/json') | ||
throw 'Invalid header Content-Type (Expected application/json)'; | ||
_getRequestPayload(req, function (error, result) { return __awaiter(_this, void 0, void 0, function () { | ||
@@ -130,6 +129,6 @@ var data, ans, error_1; | ||
throw error; | ||
return [4 /*yield*/, execute(__assign(__assign({}, opts), { event: function () { return result; } }))]; | ||
return [4 /*yield*/, execute(__assign(__assign({}, opts), { event: result }))]; | ||
case 1: | ||
data = _a.sent(); | ||
ans = JSON.stringify({ data: data }); | ||
ans = _formatResponsePayload(res, data); | ||
logger.log('info', log_msg + " -> OK (".concat(ans.length * 2, " bytes)")); | ||
@@ -158,2 +157,5 @@ return [2 /*return*/, res.end(ans)]; | ||
function _getRequestPayload(req, callback) { | ||
/* | ||
* Handle HTTP server functions. | ||
*/ | ||
var body = ''; | ||
@@ -164,9 +166,62 @@ req.on('data', function (chunk) { | ||
req.on('end', function () { | ||
var payload = JSON.parse(body); | ||
if (!payload.event) { | ||
callback('Invalid body (Expected "event" property)'); | ||
var payload; | ||
try { | ||
payload = JSON.parse(body || '{}'); | ||
} | ||
callback(null, payload.event); | ||
catch (err) { | ||
callback(err); | ||
return; | ||
} | ||
// Format: https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.proxy-format | ||
var url = new URL(req.url, "http://".concat(req.headers.host)); | ||
var event = { | ||
version: "2.0", | ||
routeKey: "$default", | ||
rawPath: url.pathname, | ||
rawQueryString: url.search, | ||
cookies: utils.parseCookies(req), | ||
headers: req.headers, | ||
queryStringParameters: Object.fromEntries(url.searchParams), | ||
requestContext: { | ||
accountId: "123456789012", | ||
apiId: "api-id", | ||
authentication: {}, | ||
authorizer: {}, | ||
http: { | ||
method: req.method, | ||
path: url.pathname, | ||
protocol: "HTTP/" + req.httpVersion, | ||
sourceIp: req.socket.localAddress, | ||
userAgent: req.headers['user-agent'], | ||
}, | ||
requestId: "id", | ||
routeKey: "$default", | ||
stage: "$default", | ||
time: new Date().toISOString(), | ||
timeEpoch: new Date().getTime(), | ||
}, | ||
body: payload, | ||
isBase64Encoded: req.headers['content-type'] !== 'application/json', | ||
}; | ||
callback(null, event); | ||
}); | ||
} | ||
function _formatResponsePayload(res, data) { | ||
/* | ||
* Handle HTTP server function output. | ||
*/ | ||
// https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.response | ||
if (!data.statusCode) { | ||
data = { | ||
isBase64Encoded: false, | ||
statusCode: 200, | ||
body: data, | ||
headers: { | ||
"content-type": "application/json", | ||
} | ||
}; | ||
} | ||
res.writeHead(data.statusCode, data.headers); | ||
return JSON.stringify(data.body); | ||
} | ||
function updateEnv(env) { | ||
@@ -183,3 +238,3 @@ /* | ||
function _executeSync(opts) { | ||
var event = opts.event, lambdaFunc = opts.lambdaFunc, lambdaPath = opts.lambdaPath, lambdaHandler = opts.lambdaHandler || 'handler', profilePath = opts.profilePath, profileName = opts.profileName || process.env['AWS_PROFILE'] || process.env['AWS_DEFAULT_PROFILE'], region = opts.region, environment = opts.environment, envdestroy = opts.envdestroy, envfile = opts.envfile, callbackWaitsForEmptyEventLoop = opts.callbackWaitsForEmptyEventLoop || false, timeoutMs = opts.timeoutMs || 3000, verboseLevel = opts.verboseLevel, callback = opts.callback, clientContext = null; | ||
var event = opts.event, lambdaFunc = opts.lambdaFunc, lambdaPath = opts.lambdaPath, lambdaHandler = opts.lambdaHandler || 'handler', esm = opts.esm, profilePath = opts.profilePath, profileName = opts.profileName || process.env['AWS_PROFILE'] || process.env['AWS_DEFAULT_PROFILE'], region = opts.region, environment = opts.environment, envdestroy = opts.envdestroy, envfile = opts.envfile, callbackWaitsForEmptyEventLoop = opts.callbackWaitsForEmptyEventLoop || false, timeoutMs = opts.timeoutMs || 3000, verboseLevel = opts.verboseLevel, callback = opts.callback, clientContext = null; | ||
if (opts.clientContext) { | ||
@@ -288,25 +343,38 @@ if (typeof opts.clientContext === "string") { | ||
var ctx = context.generate_context(); | ||
var executeLambdaFunc = function (lambdaFunc) { | ||
try { | ||
//load event | ||
if (event instanceof Function) { | ||
event = event(); | ||
} | ||
//start timeout | ||
context._init_timeout(); | ||
// execute lambda function | ||
var result = lambdaFunc[lambdaHandler](event, ctx, ctx.done); | ||
if (result) { | ||
if (result.then) { | ||
result.then(ctx.succeed, ctx.fail); | ||
} | ||
else { | ||
ctx.succeed(null); | ||
} | ||
} | ||
} | ||
catch (err) { | ||
ctx.fail(err); | ||
} | ||
}; | ||
try { | ||
// load lambda function | ||
if (!(lambdaFunc)) { | ||
if (lambdaFunc) { | ||
executeLambdaFunc(lambdaFunc); | ||
} | ||
else if (esm) { | ||
// use eval to avoid typescript transpilation of dynamic import () | ||
eval("import(lambdaPath)").then(executeLambdaFunc, function (err) { return ctx.fail(err); }); | ||
} | ||
else { | ||
// delete this function from the require.cache to ensure every dependency is refreshed | ||
delete require.cache[require.resolve(lambdaPath)]; | ||
lambdaFunc = require(lambdaPath); | ||
executeLambdaFunc(require(lambdaPath)); | ||
} | ||
//load event | ||
if (event instanceof Function) { | ||
event = event(); | ||
} | ||
//start timeout | ||
context._init_timeout(); | ||
// execute lambda function | ||
var result = lambdaFunc[lambdaHandler](event, ctx, ctx.done); | ||
if (result) { | ||
if (result.then) { | ||
result.then(ctx.succeed, ctx.fail); | ||
} | ||
else { | ||
ctx.succeed(null); | ||
} | ||
} | ||
} | ||
@@ -313,0 +381,0 @@ catch (err) { |
@@ -9,2 +9,3 @@ /** | ||
export declare function processJSON(json: any): any; | ||
export declare function parseCookies(request: any): {}; | ||
export declare class TimeoutError extends Error { | ||
@@ -11,0 +12,0 @@ constructor(m: string); |
@@ -18,3 +18,3 @@ 'use strict'; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.waitForNodeJS = exports.loadAWSCredentials = exports.TimeoutError = exports.processJSON = exports.getAbsolutePath = exports.getWinstonConsole = exports.generateRandomHex = exports.get_node_major_version = void 0; | ||
exports.waitForNodeJS = exports.loadAWSCredentials = exports.TimeoutError = exports.parseCookies = exports.processJSON = exports.getAbsolutePath = exports.getWinstonConsole = exports.generateRandomHex = exports.get_node_major_version = void 0; | ||
/** | ||
@@ -114,2 +114,21 @@ * Requires | ||
; | ||
function parseCookies(request) { | ||
var _a; | ||
var list = {}; | ||
var cookieHeader = (_a = request.headers) === null || _a === void 0 ? void 0 : _a.cookie; | ||
if (!cookieHeader) | ||
return list; | ||
cookieHeader.split(";").forEach(function (cookie) { | ||
var _a = cookie.split("="), name = _a[0], rest = _a.slice(1); | ||
name = name === null || name === void 0 ? void 0 : name.trim(); | ||
if (!name) | ||
return; | ||
var value = rest.join("=").trim(); | ||
if (!value) | ||
return; | ||
list[name] = decodeURIComponent(value); | ||
}); | ||
return list; | ||
} | ||
exports.parseCookies = parseCookies; | ||
var TimeoutError = /** @class */ (function (_super) { | ||
@@ -116,0 +135,0 @@ __extends(TimeoutError, _super); |
{ | ||
"name": "lambda-local", | ||
"version": "2.0.3", | ||
"version": "2.1.0", | ||
"description": "Commandline tool to run Lambda functions on your local machine.", | ||
@@ -39,12 +39,12 @@ "main": "build/lambdalocal.js", | ||
"dependencies": { | ||
"commander": "^9.4.0", | ||
"dotenv": "^16.0.2", | ||
"winston": "^3.8.2" | ||
"commander": "^11.0.0", | ||
"dotenv": "^16.3.1", | ||
"winston": "^3.10.0" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^18.7.16", | ||
"chai": "^4.3.6", | ||
"mocha": "^10.0.0", | ||
"sinon": "^14.0.0", | ||
"typescript": "^4.8.3" | ||
"@types/node": "^20.4.2", | ||
"chai": "^4.3.7", | ||
"mocha": "^10.2.0", | ||
"sinon": "^15.2.0", | ||
"typescript": "^5.1.6" | ||
}, | ||
@@ -51,0 +51,0 @@ "preferGlobal": true, |
@@ -67,2 +67,3 @@ # Lambda-local | ||
| `timeoutMs`|optional, timeout, default to 3000 ms| | ||
| `esm`|boolean, marks that the script is an ECMAScript module (use import), default false| | ||
| `environment`|optional, extra environment variables for the lambda| | ||
@@ -141,2 +142,3 @@ | `envfile`|optional, load an environment file before booting| | ||
* `-t, --timeout <timeout>` (optional) Seconds until lambda function timeout. Default is 3 seconds. | ||
* `--esm` (optional) Load lambda function as ECMAScript module. | ||
* `-r, --region <aws region>` (optional) Sets the AWS region, defaults to us-east-1. | ||
@@ -163,7 +165,9 @@ * `-P, --profile-path <aws profile name>` (optional) Read the specified AWS credentials file. | ||
#### Running lambda functions as a HTTP Server | ||
A simple way you can run lambda functions locally, without the need to create any special template files (like Serverless plugin and SAM requires), just adding the parameter `--watch`. It will raise a http server listening to the specified port (default is 8008), then you can pass the event payload to the handler via request body. | ||
#### Running lambda functions as a HTTP Server (Amazon API Gateway payload format version 2.0.) | ||
A simple way you can run lambda functions locally, without the need to create any special template files (like Serverless plugin and SAM requires), just adding the parameter `--watch`. It will raise a http server listening to the specified port (default is 8008). You can then call the lambda as mentionned here: | ||
https://docs.aws.amazon.com/lambda/latest/dg/urls-invocation.html | ||
```bash | ||
lambda-local -l examples/handler_helloworld.js -h handler --watch 8008 | ||
lambda-local -l examples/handler_gateway2.js -h handler --watch 8008 | ||
@@ -174,8 +178,7 @@ curl --request POST \ | ||
--data '{ | ||
"event": { | ||
"key1": "value1", | ||
"key2": "value2", | ||
"key3": "value3" | ||
} | ||
"key1": "value1", | ||
"key2": "value2", | ||
"key3": "value3" | ||
}' | ||
{"message":"This is a response"} | ||
``` | ||
@@ -192,3 +195,3 @@ | ||
module.exports = { | ||
foo: "bar" | ||
foo: "bar" | ||
}; | ||
@@ -195,0 +198,0 @@ ``` |
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
69792
32
1550
217
2
+ Addedcommander@11.1.0(transitive)
- Removedcommander@9.5.0(transitive)
Updatedcommander@^11.0.0
Updateddotenv@^16.3.1
Updatedwinston@^3.10.0