From 93d203c94c090729e379af96b27674a367256b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Bou=C3=A7as?= Date: Mon, 24 Apr 2023 09:10:23 +0100 Subject: [PATCH] feat: add private support for v2 API (#1395) * feat: add support for v2 API * chore: bump @netlify/serverless-functions-api * chore: conditionally run test --- .eslintrc.cjs | 1 + package-lock.json | 433 ++++++++++++++++++ package.json | 2 + src/feature_flags.ts | 7 +- src/runtimes/node/bundlers/esbuild/bundler.ts | 1 - .../bundlers/esbuild/plugin_native_modules.ts | 1 - src/runtimes/node/utils/entry_file.ts | 13 +- src/runtimes/node/utils/zip.ts | 21 +- src/zip.ts | 1 - tests/fixtures/v2-api/function.js | 5 + tests/helpers/lambda.ts | 31 ++ tests/main.test.ts | 21 + 12 files changed, 528 insertions(+), 9 deletions(-) create mode 100644 tests/fixtures/v2-api/function.js create mode 100644 tests/helpers/lambda.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 163595856..76734c9f8 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -34,6 +34,7 @@ module.exports = { 'import/no-namespace': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/2483 'max-lines': 'off', + 'max-statements': 'off', 'no-shadow': 'off', '@typescript-eslint/no-shadow': 'error', }, diff --git a/package-lock.json b/package-lock.json index 139a7c4a8..5caea8ad9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@babel/parser": "7.16.8", "@netlify/binary-info": "^1.0.0", "@netlify/esbuild": "0.14.39", + "@netlify/serverless-functions-api": "^1.2.0", "@vercel/nft": "^0.22.0", "archiver": "^5.3.0", "common-path-prefix": "^3.0.0", @@ -62,6 +63,7 @@ "deepmerge": "^4.2.2", "get-stream": "^6.0.0", "husky": "^8.0.0", + "lambda-local": "^2.0.3", "npm-run-all": "^4.1.5", "sort-on": "^5.0.0", "source-map-support": "^0.5.21", @@ -463,6 +465,15 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/@commitlint/cli": { "version": "17.5.1", "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-17.5.1.tgz", @@ -1234,6 +1245,17 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dev": true, + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@dependents/detective-less": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@dependents/detective-less/-/detective-less-3.0.1.tgz", @@ -2260,6 +2282,14 @@ "node": ">=16.0.0" } }, + "node_modules/@netlify/serverless-functions-api": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@netlify/serverless-functions-api/-/serverless-functions-api-1.2.0.tgz", + "integrity": "sha512-TenW9rP3J49FyYLw+IUT01RnGMNxyGb2NNZjTzvQ1zn0swhPmJrHTPju6VQPOQcyQCJZhSBYIZgdeItbCnYTfQ==", + "engines": { + "node": "^14.18.0 || >=16.0.0" + } + }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -2484,6 +2514,12 @@ "integrity": "sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA==", "dev": true }, + "node_modules/@types/triple-beam": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.2.tgz", + "integrity": "sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g==", + "dev": true + }, "node_modules/@types/unist": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", @@ -3740,6 +3776,16 @@ "node": ">=12" } }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -3755,6 +3801,16 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -3763,6 +3819,16 @@ "color-support": "bin.js" } }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dev": true, + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, "node_modules/commander": { "version": "9.5.0", "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", @@ -4532,6 +4598,15 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.356", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.356.tgz", @@ -4543,6 +4618,12 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "dev": true + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -6036,6 +6117,12 @@ "reusify": "^1.0.4" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "dev": true + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -6109,6 +6196,12 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "dev": true + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -7453,6 +7546,29 @@ "node": ">=0.10.0" } }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "dev": true + }, + "node_modules/lambda-local": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lambda-local/-/lambda-local-2.0.3.tgz", + "integrity": "sha512-Vs55gujwdjhPL2VpXEXAWWwxiOYdnVPDsMgwOr9BqC0O1EoSXs1S8TKBmD/ySEnPVRiQfFlABcQgcykF1mkE8Q==", + "dev": true, + "dependencies": { + "commander": "^9.4.0", + "dotenv": "^16.0.2", + "winston": "^3.8.2" + }, + "bin": { + "lambda-local": "build/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/lazystream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", @@ -7661,6 +7777,20 @@ "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", "dev": true }, + "node_modules/logform": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz", + "integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==", + "dev": true, + "dependencies": { + "@colors/colors": "1.5.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -8417,6 +8547,15 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dev": true, + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/onetime": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", @@ -9537,6 +9676,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/semver": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", @@ -9625,6 +9773,21 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + }, "node_modules/slash": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", @@ -9746,6 +9909,15 @@ "readable-stream": "^3.0.0" } }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -10085,6 +10257,12 @@ "node": ">=0.10" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "dev": true + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -10213,6 +10391,12 @@ "node": ">=8" } }, + "node_modules/triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==", + "dev": true + }, "node_modules/ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -10764,6 +10948,54 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, + "node_modules/winston": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", + "dev": true, + "dependencies": { + "@colors/colors": "1.5.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "dev": true, + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -11195,6 +11427,12 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true + }, "@commitlint/cli": { "version": "17.5.1", "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-17.5.1.tgz", @@ -11760,6 +11998,17 @@ } } }, + "@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dev": true, + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "@dependents/detective-less": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@dependents/detective-less/-/detective-less-3.0.1.tgz", @@ -12327,6 +12576,11 @@ "statuses": "^2.0.1" } }, + "@netlify/serverless-functions-api": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@netlify/serverless-functions-api/-/serverless-functions-api-1.2.0.tgz", + "integrity": "sha512-TenW9rP3J49FyYLw+IUT01RnGMNxyGb2NNZjTzvQ1zn0swhPmJrHTPju6VQPOQcyQCJZhSBYIZgdeItbCnYTfQ==" + }, "@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -12533,6 +12787,12 @@ "integrity": "sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA==", "dev": true }, + "@types/triple-beam": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.2.tgz", + "integrity": "sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g==", + "dev": true + }, "@types/unist": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", @@ -13408,6 +13668,16 @@ "wrap-ansi": "^7.0.0" } }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dev": true, + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -13423,11 +13693,31 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dev": true, + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, "commander": { "version": "9.5.0", "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", @@ -13967,6 +14257,12 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "dev": true + }, "electron-to-chromium": { "version": "1.4.356", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.356.tgz", @@ -13978,6 +14274,12 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "dev": true + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -15075,6 +15377,12 @@ "reusify": "^1.0.4" } }, + "fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "dev": true + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -15127,6 +15435,12 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "dev": true + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -16061,6 +16375,23 @@ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "dev": true + }, + "lambda-local": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lambda-local/-/lambda-local-2.0.3.tgz", + "integrity": "sha512-Vs55gujwdjhPL2VpXEXAWWwxiOYdnVPDsMgwOr9BqC0O1EoSXs1S8TKBmD/ySEnPVRiQfFlABcQgcykF1mkE8Q==", + "dev": true, + "requires": { + "commander": "^9.4.0", + "dotenv": "^16.0.2", + "winston": "^3.8.2" + } + }, "lazystream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", @@ -16249,6 +16580,20 @@ "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", "dev": true }, + "logform": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz", + "integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==", + "dev": true, + "requires": { + "@colors/colors": "1.5.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -16790,6 +17135,15 @@ "wrappy": "1" } }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dev": true, + "requires": { + "fn.name": "1.x.x" + } + }, "onetime": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", @@ -17558,6 +17912,12 @@ "is-regex": "^1.1.4" } }, + "safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "dev": true + }, "semver": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", @@ -17627,6 +17987,23 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dev": true, + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + } + } + }, "slash": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", @@ -17720,6 +18097,12 @@ "readable-stream": "^3.0.0" } }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "dev": true + }, "stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -17973,6 +18356,12 @@ "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", "dev": true }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "dev": true + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -18080,6 +18469,12 @@ "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==", + "dev": true + }, "ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -18431,6 +18826,44 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, + "winston": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", + "dev": true, + "requires": { + "@colors/colors": "1.5.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "dependencies": { + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + } + } + }, + "winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "dev": true, + "requires": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", diff --git a/package.json b/package.json index fc24a4455..c059c7d7f 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "@babel/parser": "7.16.8", "@netlify/binary-info": "^1.0.0", "@netlify/esbuild": "0.14.39", + "@netlify/serverless-functions-api": "^1.2.0", "@vercel/nft": "^0.22.0", "archiver": "^5.3.0", "common-path-prefix": "^3.0.0", @@ -104,6 +105,7 @@ "deepmerge": "^4.2.2", "get-stream": "^6.0.0", "husky": "^8.0.0", + "lambda-local": "^2.0.3", "npm-run-all": "^4.1.5", "sort-on": "^5.0.0", "source-map-support": "^0.5.21", diff --git a/src/feature_flags.ts b/src/feature_flags.ts index 5a6931be1..2a3a1d5e4 100644 --- a/src/feature_flags.ts +++ b/src/feature_flags.ts @@ -18,11 +18,14 @@ export const defaultFlags: Record = { // `.mjs` extension. zisi_pure_esm_mjs: false, - // Output CJS file extension + // Output CJS file extension. zisi_output_cjs_extension: false, - // Do not allow ___netlify-entry-point as function or file name + // Do not allow ___netlify-entry-point as function or file name. zisi_disallow_new_entry_name: false, + + // Inject the compatibility layer required for the v2 runtime API to work. + zisi_functions_api_v2: false, } export type FeatureFlag = keyof typeof defaultFlags diff --git a/src/runtimes/node/bundlers/esbuild/bundler.ts b/src/runtimes/node/bundlers/esbuild/bundler.ts index 16d12f763..05a1c391a 100644 --- a/src/runtimes/node/bundlers/esbuild/bundler.ts +++ b/src/runtimes/node/bundlers/esbuild/bundler.ts @@ -25,7 +25,6 @@ export const ESBUILD_LOG_LIMIT = 10 // the extensions that esbuild will look for, in this order. const RESOLVE_EXTENSIONS = ['.js', '.jsx', '.mjs', '.cjs', '.ts', '.tsx', '.mts', '.cts', '.json'] -// eslint-disable-next-line max-statements export const bundleJsFile = async function ({ additionalModulePaths, basePath, diff --git a/src/runtimes/node/bundlers/esbuild/plugin_native_modules.ts b/src/runtimes/node/bundlers/esbuild/plugin_native_modules.ts index e2fce8817..c3371b36e 100644 --- a/src/runtimes/node/bundlers/esbuild/plugin_native_modules.ts +++ b/src/runtimes/node/bundlers/esbuild/plugin_native_modules.ts @@ -32,7 +32,6 @@ export const getNativeModulesPlugin = (externalizedModules: NativeNodeModules): setup(build) { const cache: NativeModuleCache = {} - // eslint-disable-next-line max-statements build.onResolve({ filter: packageFilter }, async (args) => { const pkg = packageName.exec(args.path) diff --git a/src/runtimes/node/utils/entry_file.ts b/src/runtimes/node/utils/entry_file.ts index 1d2727c8e..1581cc4ac 100644 --- a/src/runtimes/node/utils/entry_file.ts +++ b/src/runtimes/node/utils/entry_file.ts @@ -14,15 +14,24 @@ import { import { normalizeFilePath } from './normalize_path.js' export const ENTRY_FILE_NAME = '___netlify-entry-point' +export const BOOTSTRAP_FILE_NAME = '___netlify-bootstrap.js' export interface EntryFile { contents: string filename: string } -const getEntryFileContents = (mainPath: string, moduleFormat: string) => { +const getEntryFileContents = (mainPath: string, moduleFormat: string, featureFlags: FeatureFlags) => { const importPath = `.${mainPath.startsWith('/') ? mainPath : `/${mainPath}`}` + if (featureFlags.zisi_functions_api_v2) { + return [ + `import func from '${importPath}'`, + `import { getLambdaHandler } from './${BOOTSTRAP_FILE_NAME}'`, + `export const handler = getLambdaHandler(func)`, + ].join(';\n') + } + if (moduleFormat === MODULE_FORMAT.COMMONJS) { return `module.exports = require('${importPath}')` } @@ -117,7 +126,7 @@ export const getEntryFile = ({ const mainPath = normalizeFilePath({ commonPrefix, path: mainFile, userNamespace }) const extension = getFileExtensionForFormat(moduleFormat, featureFlags) const entryFilename = getEntryFileName({ extension, filename }) - const contents = getEntryFileContents(mainPath, moduleFormat) + const contents = getEntryFileContents(mainPath, moduleFormat, featureFlags) return { contents, diff --git a/src/runtimes/node/utils/zip.ts b/src/runtimes/node/utils/zip.ts index 770b4835a..a5a7bd414 100644 --- a/src/runtimes/node/utils/zip.ts +++ b/src/runtimes/node/utils/zip.ts @@ -3,6 +3,7 @@ import { Stats, promises as fs } from 'fs' import os from 'os' import { basename, join } from 'path' +import { getPath as getV2APIPath } from '@netlify/serverless-functions-api' import { copyFile } from 'cp-file' import { deleteAsync as deleteFiles } from 'del' import pMap from 'p-map' @@ -20,7 +21,13 @@ import type { FeatureFlags } from '../../../feature_flags.js' import type { RuntimeCache } from '../../../utils/cache.js' import { cachedLstat, mkdirAndWriteFile } from '../../../utils/fs.js' -import { conflictsWithEntryFile, EntryFile, getEntryFile, isNamedLikeEntryFile } from './entry_file.js' +import { + BOOTSTRAP_FILE_NAME, + conflictsWithEntryFile, + EntryFile, + getEntryFile, + isNamedLikeEntryFile, +} from './entry_file.js' import { ModuleFormat } from './module_format.js' import { normalizeFilePath } from './normalize_path.js' @@ -99,7 +106,7 @@ const createDirectory = async function ({ } const createZipArchive = async function ({ - aliases, + aliases = new Map(), basePath, cache, destFolder, @@ -146,6 +153,16 @@ const createZipArchive = async function ({ addEntryFileToZip(archive, entryFile) } + if (featureFlags.zisi_functions_api_v2) { + // This is the path to the file that contains all the code for the v2 + // functions API. We add it to the list of source files and create an + // alias so that it's written as `BOOTSTRAP_FILE_NAME` in the ZIP. + const v2APIPath = getV2APIPath() + + srcFiles.push(v2APIPath) + aliases.set(v2APIPath, BOOTSTRAP_FILE_NAME) + } + const srcFilesInfos = await Promise.all(srcFiles.map((file) => addStat(cache, file))) // We ensure this is not async, so that the archive's checksum is diff --git a/src/zip.ts b/src/zip.ts index da4e4c58d..eb23b9741 100644 --- a/src/zip.ts +++ b/src/zip.ts @@ -142,7 +142,6 @@ export const zipFunctions = async function ( return formattedResults } -// eslint-disable-next-line max-statements export const zipFunction = async function ( relativeSrcPath: string, destFolder: string, diff --git a/tests/fixtures/v2-api/function.js b/tests/fixtures/v2-api/function.js new file mode 100644 index 000000000..5a1d92c5a --- /dev/null +++ b/tests/fixtures/v2-api/function.js @@ -0,0 +1,5 @@ +export default async () => new Response("

Hello world

", { + headers: { + "content-type": "text/html" + } +}) diff --git a/tests/helpers/lambda.ts b/tests/helpers/lambda.ts new file mode 100644 index 000000000..ec2db0867 --- /dev/null +++ b/tests/helpers/lambda.ts @@ -0,0 +1,31 @@ +import { execute } from 'lambda-local' + +interface LambdaResponse { + statusCode: number + headers?: { + [header: string]: boolean | number | string + } + multiValueHeaders?: { + [header: string]: ReadonlyArray + } + body?: string + isBase64Encoded?: boolean +} + +export const invokeLambda = async (func, { method = 'GET', ...options }: RequestInit = {}) => { + const event = { + ...options, + body: options.body ?? '', + headers: { + ...options.headers, + }, + httpMethod: method, + rawUrl: 'https://example.netlify', + } + const result = (await execute({ + event, + lambdaFunc: func, + })) as LambdaResponse + + return result +} diff --git a/tests/main.test.ts b/tests/main.test.ts index aaa8ac822..2296db903 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -20,6 +20,7 @@ import { detectEsModule } from '../src/runtimes/node/utils/detect_es_module.js' import { MODULE_FORMAT } from '../src/runtimes/node/utils/module_format.js' import { shellUtils } from '../src/utils/shell.js' +import { invokeLambda } from './helpers/lambda.js' import { getRequires, zipNode, @@ -2698,4 +2699,24 @@ describe('zip-it-and-ship-it', () => { ).rejects.toThrowError(/is a reserved word and cannot be used as a file or directory name\.$/) }, ) + + if (semver.gte(nodeVersion, '18.13.0')) { + testMany( + 'Handles a JavaScript function using the V2 API', + ['bundler_default', 'todo:bundler_esbuild', 'todo:bundler_esbuild_zisi', 'bundler_default_nft', 'bundler_nft'], + async (options) => { + const { files, tmpDir } = await zipFixture('v2-api', { + opts: merge(options, { featureFlags: { zisi_functions_api_v2: true } }), + }) + await unzipFiles(files) + + const func = await importFunctionFile(`${tmpDir}/function.js`) + const { body, headers = {}, statusCode } = await invokeLambda(func) + + expect(body).toBe('

Hello world

') + expect(headers['content-type']).toBe('text/html') + expect(statusCode).toBe(200) + }, + ) + } })