diff --git a/package-lock.json b/package-lock.json index 13e81d752a3..fc03be58ee0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@netlify/local-functions-proxy": "1.1.1", "@netlify/zip-it-and-ship-it": "9.5.0", "@octokit/rest": "19.0.8", + "@skn0tt/lambda-local": "^2.0.3", "ansi-escapes": "6.2.0", "ansi-styles": "6.2.1", "ansi-to-html": "0.7.2", @@ -68,11 +69,11 @@ "inquirer": "6.5.2", "inquirer-autocomplete-prompt": "1.4.0", "is-docker": "3.0.0", + "is-stream": "^3.0.0", "is-wsl": "2.2.0", "isexe": "2.0.0", "jsonwebtoken": "9.0.0", "jwt-decode": "3.1.2", - "lambda-local": "2.0.3", "listr": "0.14.3", "locate-path": "7.2.0", "lodash": "4.17.21", @@ -2401,17 +2402,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@netlify/build/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@netlify/build/node_modules/lowercase-keys": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", @@ -2865,17 +2855,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@netlify/config/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@netlify/config/node_modules/map-obj": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.2.tgz", @@ -3104,17 +3083,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@netlify/edge-bundler/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@netlify/edge-bundler/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -3614,18 +3582,6 @@ "node": ">=12.20.0" } }, - "node_modules/@netlify/eslint-config-node/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@netlify/eslint-config-node/node_modules/npm-run-path": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", @@ -3881,17 +3837,6 @@ "node": ">=12.20.0" } }, - "node_modules/@netlify/git-utils/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@netlify/git-utils/node_modules/map-obj": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.2.tgz", @@ -4203,17 +4148,6 @@ "node": ">=12.20.0" } }, - "node_modules/@netlify/run-utils/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@netlify/run-utils/node_modules/npm-run-path": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", @@ -4393,17 +4327,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@netlify/zip-it-and-ship-it/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@netlify/zip-it-and-ship-it/node_modules/minimatch": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", @@ -4867,6 +4790,30 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, + "node_modules/@skn0tt/lambda-local": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@skn0tt/lambda-local/-/lambda-local-2.0.3.tgz", + "integrity": "sha512-7WZuCWSHeWC9Fh2FTT7lAT6yL5vDZUPxCZ51gIDdCc631CXmEJL/r7t2WMubP2CPuuRA+EnDSJrzKckwY4cz8g==", + "dependencies": { + "commander": "^9.4.0", + "dotenv": "^16.0.2", + "winston": "^3.8.2" + }, + "bin": { + "lambda-local": "build/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@skn0tt/lambda-local/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -11096,6 +11043,17 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/execa/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==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/exit-on-epipe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", @@ -12902,6 +12860,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/hasha/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==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/hasha/node_modules/type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -13956,11 +13925,11 @@ } }, "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==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -14536,30 +14505,6 @@ "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, - "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==", - "dependencies": { - "commander": "^9.4.0", - "dotenv": "^16.0.2", - "winston": "^3.8.2" - }, - "bin": { - "lambda-local": "build/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lambda-local/node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "engines": { - "node": "^12.20.0 || >=14" - } - }, "node_modules/latest-version": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", @@ -20631,17 +20576,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tempy/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/tempy/node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -22368,6 +22302,17 @@ "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==", + "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", @@ -24155,11 +24100,6 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==" }, - "is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==" - }, "lowercase-keys": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", @@ -24485,11 +24425,6 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==" }, - "is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==" - }, "map-obj": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.2.tgz", @@ -24630,11 +24565,6 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==" }, - "is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==" - }, "json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -24895,12 +24825,6 @@ "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==", "dev": true }, - "is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true - }, "npm-run-path": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", @@ -25074,11 +24998,6 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==" }, - "is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==" - }, "map-obj": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.2.tgz", @@ -25242,11 +25161,6 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==" }, - "is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==" - }, "npm-run-path": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", @@ -25373,11 +25287,6 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==" }, - "is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==" - }, "minimatch": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", @@ -25730,6 +25639,23 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, + "@skn0tt/lambda-local": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@skn0tt/lambda-local/-/lambda-local-2.0.3.tgz", + "integrity": "sha512-7WZuCWSHeWC9Fh2FTT7lAT6yL5vDZUPxCZ51gIDdCc631CXmEJL/r7t2WMubP2CPuuRA+EnDSJrzKckwY4cz8g==", + "requires": { + "commander": "^9.4.0", + "dotenv": "^16.0.2", + "winston": "^3.8.2" + }, + "dependencies": { + "commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==" + } + } + }, "@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -30334,6 +30260,13 @@ "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.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==" + } } }, "exit-on-epipe": { @@ -31707,6 +31640,11 @@ "type-fest": "^0.8.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==" + }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -32424,9 +32362,9 @@ } }, "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==" }, "is-string": { "version": "1.0.7", @@ -32857,23 +32795,6 @@ "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, - "lambda-local": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/lambda-local/-/lambda-local-2.0.3.tgz", - "integrity": "sha512-Vs55gujwdjhPL2VpXEXAWWwxiOYdnVPDsMgwOr9BqC0O1EoSXs1S8TKBmD/ySEnPVRiQfFlABcQgcykF1mkE8Q==", - "requires": { - "commander": "^9.4.0", - "dotenv": "^16.0.2", - "winston": "^3.8.2" - }, - "dependencies": { - "commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==" - } - } - }, "latest-version": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", @@ -37355,11 +37276,6 @@ } } }, - "is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==" - }, "type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -38618,6 +38534,13 @@ "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==" + } } }, "winston-transport": { diff --git a/package.json b/package.json index 41655c523fe..09c102b84f5 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "@netlify/local-functions-proxy": "1.1.1", "@netlify/zip-it-and-ship-it": "9.5.0", "@octokit/rest": "19.0.8", + "@skn0tt/lambda-local": "^2.0.3", "ansi-escapes": "6.2.0", "ansi-styles": "6.2.1", "ansi-to-html": "0.7.2", @@ -134,11 +135,11 @@ "inquirer": "6.5.2", "inquirer-autocomplete-prompt": "1.4.0", "is-docker": "3.0.0", + "is-stream": "^3.0.0", "is-wsl": "2.2.0", "isexe": "2.0.0", "jsonwebtoken": "9.0.0", "jwt-decode": "3.1.2", - "lambda-local": "2.0.3", "listr": "0.14.3", "locate-path": "7.2.0", "lodash": "4.17.21", diff --git a/src/lib/functions/runtimes/js/index.mjs b/src/lib/functions/runtimes/js/index.mjs index 0af80c7c836..f8e6f6b166a 100644 --- a/src/lib/functions/runtimes/js/index.mjs +++ b/src/lib/functions/runtimes/js/index.mjs @@ -1,6 +1,6 @@ import { dirname } from 'path' -import lambdaLocal from 'lambda-local' +import lambdaLocal from '@skn0tt/lambda-local' import winston from 'winston' import detectNetlifyLambdaBuilder from './builders/netlify-lambda.mjs' diff --git a/src/lib/functions/synchronous.mjs b/src/lib/functions/synchronous.mjs index 1543442621c..e2d9740af1c 100644 --- a/src/lib/functions/synchronous.mjs +++ b/src/lib/functions/synchronous.mjs @@ -1,6 +1,8 @@ // @ts-check import { Buffer } from 'buffer' +import { isStream } from 'is-stream' + import { chalk, log, NETLIFYDEVERR } from '../../utils/command-helpers.mjs' import renderErrorTemplate from '../render-error-template.mjs' @@ -47,6 +49,12 @@ export const handleSynchronousFunction = function ({ } if (result.body) { + if (isStream(result.body)) { + result.body.pipe(response) + + return + } + response.write(result.isBase64Encoded ? Buffer.from(result.body, 'base64') : result.body) } response.end() @@ -97,8 +105,8 @@ const validateLambdaResponse = (lambdaResponse) => { error: `Your function response must have a numerical statusCode. You gave: $ ${lambdaResponse.statusCode}`, } } - if (lambdaResponse.body && typeof lambdaResponse.body !== 'string') { - return { error: `Your function response must have a string body. You gave: ${lambdaResponse.body}` } + if (lambdaResponse.body && typeof lambdaResponse.body !== 'string' && !isStream(lambdaResponse.body)) { + return { error: `Your function response must have a string or a stream body. You gave: ${lambdaResponse.body}` } } return {} diff --git a/tests/integration/400.command.dev.test.cjs b/tests/integration/400.command.dev.test.cjs index aeb01aa62c5..f97e5eaf674 100644 --- a/tests/integration/400.command.dev.test.cjs +++ b/tests/integration/400.command.dev.test.cjs @@ -8,6 +8,7 @@ const FormData = require('form-data') const { withDevServer } = require('./utils/dev-server.cjs') const got = require('./utils/got.cjs') +const { pause } = require('./utils/pause.cjs') const { withSiteBuilder } = require('./utils/site-builder.cjs') const test = isCI ? avaTest.serial.bind(avaTest) : avaTest @@ -412,3 +413,76 @@ test('should handle multipart form data when redirecting', async (t) => { }) }) }) + +test('should support functions with streaming responses', async (t) => { + await withSiteBuilder('site-with-streaming-function', async (builder) => { + builder + .withPackageJson({ packageJson: { dependencies: { '@netlify/functions': 'latest' } } }) + .withCommand({ command: ['npm', 'install'] }) + .withContentFile({ + content: ` + const { stream } = require("@netlify/functions"); + + class TimerSource { + #input; + #interval; + + constructor(input) { + this.#input = input; + } + + start(controller) { + this.#interval = setInterval(() => { + const string = this.#input.shift(); + + if (string === undefined) { + controller.close(); + + clearInterval(this.#interval); + + return; + } + + controller.enqueue(string); + }, 50); + } + + cancel() { + clearInterval(this.#interval); + } + } + + exports.handler = stream(async (event) => ({ + body: new ReadableStream(new TimerSource(["one", "two", "three"])), + headers: { + "x-custom-header-1": "value 1" + }, + statusCode: 200, + })); + `, + path: 'netlify/functions/streamer.js', + }) + + await builder.buildAsync() + + await withDevServer({ cwd: builder.directory }, async (server) => { + const chunks = [] + const response = got.stream(`${server.url}/.netlify/functions/streamer`) + + let lastTimestamp = 0 + + response.on('data', (chunk) => { + const now = Date.now() + + t.true(now > lastTimestamp) + + lastTimestamp = now + chunks.push(chunk.toString()) + }) + + await pause(500) + + t.deepEqual(chunks, ['one', 'two', 'three']) + }) + }) +}) diff --git a/tests/integration/utils/site-builder.cjs b/tests/integration/utils/site-builder.cjs index 21723fffbe2..4d759979d67 100644 --- a/tests/integration/utils/site-builder.cjs +++ b/tests/integration/utils/site-builder.cjs @@ -206,6 +206,16 @@ class SiteBuilder { return this } + withCommand({ command }) { + this.tasks.push(async () => { + const [mainCommand, ...args] = command + + await execa(mainCommand, args, { cwd: this.directory }) + }) + + return this + } + async build() { // eslint-disable-next-line fp/no-loops for (const task of this.tasks) {