diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index bf654865286..b15972ee284 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -72,7 +72,7 @@ "isexe": "^2.0.0", "jsonwebtoken": "^8.5.1", "jwt-decode": "^3.0.0", - "lambda-local": "^2.0.1", + "lambda-local": "^2.0.2", "listr": "^0.14.3", "locate-path": "^6.0.0", "lodash": "^4.17.20", @@ -15320,13 +15320,13 @@ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, "node_modules/lambda-local": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/lambda-local/-/lambda-local-2.0.1.tgz", - "integrity": "sha512-21AoIJYuGRPNMCEtxAOa/BP2j0fNY10IVYMQ1pRqDyhSJi5xt4r4IZUqWF40+aYU6TJ1SdB7t5s1BmSq391ILQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lambda-local/-/lambda-local-2.0.2.tgz", + "integrity": "sha512-sCE0U645QdmQOx5y028kZnmvbfho4NkdAjmJuA8KdwPQS8tz9sByz281WHyEAfcBfXci/9eQxNURuL996Q8ybw==", "dependencies": { - "commander": "^8.3.0", - "dotenv": "^10.0.0", - "winston": "^3.3.3" + "commander": "^9.0.0", + "dotenv": "^16.0.0", + "winston": "^3.6.0" }, "bin": { "lambda-local": "build/cli.js" @@ -15335,22 +15335,6 @@ "node": ">=6" } }, - "node_modules/lambda-local/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/lambda-local/node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "engines": { - "node": ">=10" - } - }, "node_modules/latest-version": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", @@ -35617,25 +35601,13 @@ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, "lambda-local": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/lambda-local/-/lambda-local-2.0.1.tgz", - "integrity": "sha512-21AoIJYuGRPNMCEtxAOa/BP2j0fNY10IVYMQ1pRqDyhSJi5xt4r4IZUqWF40+aYU6TJ1SdB7t5s1BmSq391ILQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lambda-local/-/lambda-local-2.0.2.tgz", + "integrity": "sha512-sCE0U645QdmQOx5y028kZnmvbfho4NkdAjmJuA8KdwPQS8tz9sByz281WHyEAfcBfXci/9eQxNURuL996Q8ybw==", "requires": { - "commander": "^8.3.0", - "dotenv": "^10.0.0", - "winston": "^3.3.3" - }, - "dependencies": { - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" - }, - "dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" - } + "commander": "^9.0.0", + "dotenv": "^16.0.0", + "winston": "^3.6.0" } }, "latest-version": { diff --git a/package.json b/package.json index f32bdaefd51..be28f61de9d 100644 --- a/package.json +++ b/package.json @@ -110,6 +110,7 @@ "Sergii Zinkevych", "Shawn Erquhart ", "Shawn Makinson (http://smakinson.github.io)", + "Simon Knott (https://twitter.com/skn0tt)", "Souma Suzuki ", "Sébastien Chopin (https://twitter.com/Atinux)", "Takumi Hirunuma (https://twitter.com/mg111_)", diff --git a/src/lib/functions/synchronous.js b/src/lib/functions/synchronous.js index f170befc61d..e203fbf3a2c 100644 --- a/src/lib/functions/synchronous.js +++ b/src/lib/functions/synchronous.js @@ -79,6 +79,11 @@ const validateLambdaResponse = (lambdaResponse) => { if (lambdaResponse === undefined) { return { error: 'lambda response was undefined. check your function code again' } } + if (lambdaResponse === null) { + return { + error: 'no lambda response. check your function code again. make sure to return a promise or use the callback.', + } + } if (!Number(lambdaResponse.statusCode)) { return { error: `Your function response must have a numerical statusCode. You gave: $ ${lambdaResponse.statusCode}`, diff --git a/tests/integration/20.command.functions.test.js b/tests/integration/20.command.functions.test.js index d492aada239..d43cc85da59 100644 --- a/tests/integration/20.command.functions.test.js +++ b/tests/integration/20.command.functions.test.js @@ -625,7 +625,7 @@ test('should serve helpful tips and tricks', async (t) => { content: ` const { schedule } = require('@netlify/functions') - module.exports.handler = schedule('@daily', () => { + module.exports.handler = schedule('@daily', async () => { return { statusCode: 200, body: "hello world" @@ -684,7 +684,7 @@ test('should emulate next_run for scheduled functions', async (t) => { path: 'functions/hello-world.js', content: ` const { schedule } = require('@netlify/functions') - module.exports.handler = schedule("@daily", (event) => { + module.exports.handler = schedule("@daily", async (event) => { const { next_run } = JSON.parse(event.body) return { statusCode: !!next_run ? 200 : 400, @@ -748,7 +748,7 @@ test('should detect file changes to scheduled function', async (t) => { .withContentFile({ path: 'functions/hello-world.js', content: ` - module.exports.handler = () => { + module.exports.handler = async () => { return { statusCode: 200 } @@ -772,7 +772,7 @@ test('should detect file changes to scheduled function', async (t) => { content: ` const { schedule } = require('@netlify/functions') - module.exports.handler = schedule("@daily", () => { + module.exports.handler = schedule("@daily", async () => { return { statusCode: 200, body: "test" diff --git a/tests/integration/330.serving-functions.test.js b/tests/integration/330.serving-functions.test.js index 8431317fd0b..68b922bb364 100644 --- a/tests/integration/330.serving-functions.test.js +++ b/tests/integration/330.serving-functions.test.js @@ -510,7 +510,7 @@ testMatrix.forEach(({ args }) => { path: 'functions/hello/index.js', content: ` const response = require("./dist") -exports.handler = () => ({ +exports.handler = async () => ({ statusCode: 200, body: response })`, diff --git a/tests/integration/400.command.dev.test.js b/tests/integration/400.command.dev.test.js index 5063ecba97d..1cad70f44b1 100644 --- a/tests/integration/400.command.dev.test.js +++ b/tests/integration/400.command.dev.test.js @@ -137,6 +137,26 @@ testMatrix.forEach(({ args }) => { }) }) + test(testName('should replicate Lambda behaviour for synchronous return values', args), async (t) => { + await withSiteBuilder('site-replicate-aws-sync-behaviour', async (builder) => { + builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ + path: 'env.js', + handler: () => ({ + statusCode: 200, + }), + }) + + await builder.buildAsync() + + await withDevServer({ cwd: builder.directory, args }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/env`, { + throwHttpErrors: false, + }) + t.true(response.body.startsWith('no lambda response.')) + }) + }) + }) + test(testName('should redirect using a wildcard when set in netlify.toml', args), async (t) => { await withSiteBuilder('site-with-redirect-function', async (builder) => { builder diff --git a/tests/unit/lib/functions/server.test.js b/tests/unit/lib/functions/server.test.js index e4f7aa338e0..38c044814c1 100644 --- a/tests/unit/lib/functions/server.test.js +++ b/tests/unit/lib/functions/server.test.js @@ -18,7 +18,7 @@ test.before(async () => { mkdirSync(functionsDirectory) const mainFile = join(functionsDirectory, 'hello.js') - writeFileSync(mainFile, `exports.handler = (event) => ({ statusCode: 200, body: event.rawUrl })`) + writeFileSync(mainFile, `exports.handler = async (event) => ({ statusCode: 200, body: event.rawUrl })`) const functionsRegistry = new FunctionsRegistry({ projectRoot,