diff --git a/package-lock.json b/package-lock.json index 82d5fb20..e8f0ed10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3358,10 +3358,11 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", - "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", + "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "tslib": "^2.4.0" @@ -5220,6 +5221,17 @@ "node": ">=6.9.0" } }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@img/sharp-darwin-arm64": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", @@ -5328,6 +5340,23 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.3.tgz", + "integrity": "sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-libvips-linux-s390x": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", @@ -5436,6 +5465,29 @@ "@img/sharp-libvips-linux-arm64": "1.0.4" } }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.4.tgz", + "integrity": "sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.3" + } + }, "node_modules/@img/sharp-linux-s390x": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", @@ -5543,6 +5595,26 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.4.tgz", + "integrity": "sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-win32-ia32": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", @@ -6290,156 +6362,6 @@ "node": ">= 0.4" } }, - "node_modules/@next/env": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.4.tgz", - "integrity": "sha512-irQnbMLbUNQpP1wcE5NstJtbuA/69kRfzBrpAD7Gsn8zm/CY6YQYc3HQBz8QPxwISG26tIm5afvvVbu508oBeQ==", - "dev": true - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.4.tgz", - "integrity": "sha512-mF05E/5uPthWzyYDyptcwHptucf/jj09i2SXBPwNzbgBNc+XnwzrL0U6BmPjQeOL+FiB+iG1gwBeq7mlDjSRPg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.4.tgz", - "integrity": "sha512-IZQ3C7Bx0k2rYtrZZxKKiusMTM9WWcK5ajyhOZkYYTCc8xytmwSzR1skU7qLgVT/EY9xtXDG0WhY6fyujnI3rw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.4.tgz", - "integrity": "sha512-VwwZKrBQo/MGb1VOrxJ6LrKvbpo7UbROuyMRvQKTFKhNaXjUmKTu7wxVkIuCARAfiI8JpaWAnKR+D6tzpCcM4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.4.tgz", - "integrity": "sha512-8QftwPEW37XxXoAwsn+nXlodKWHfpMaSvt81W43Wh8dv0gkheD+30ezWMcFGHLI71KiWmHK5PSQbTQGUiidvLQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.4.tgz", - "integrity": "sha512-/s/Pme3VKfZAfISlYVq2hzFS8AcAIOTnoKupc/j4WlvF6GQ0VouS2Q2KEgPuO1eMBwakWPB1aYFIA4VNVh667A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.4.tgz", - "integrity": "sha512-m8z/6Fyal4L9Bnlxde5g2Mfa1Z7dasMQyhEhskDATpqr+Y0mjOBZcXQ7G5U+vgL22cI4T7MfvgtrM2jdopqWaw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.4.tgz", - "integrity": "sha512-7Wv4PRiWIAWbm5XrGz3D8HUkCVDMMz9igffZG4NB1p4u1KoItwx9qjATHz88kwCEal/HXmbShucaslXCQXUM5w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.4.tgz", - "integrity": "sha512-zLeNEAPULsl0phfGb4kdzF/cAVIfaC7hY+kt0/d+y9mzcZHsMS3hAS829WbJ31DkSlVKQeHEjZHIdhN+Pg7Gyg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.4.tgz", - "integrity": "sha512-yEh2+R8qDlDCjxVpzOTEpBLQTEFAcP2A8fUFLaWNap9GitYKkKv1//y2S6XY6zsR4rCOPRpU7plYDR+az2n30A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@ngtools/webpack": { "version": "17.1.2", "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-17.1.2.tgz", @@ -9269,15 +9191,6 @@ "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", "dev": true }, - "node_modules/@swc/helpers": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", - "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", - "dev": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -13211,10 +13124,11 @@ } }, "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=8" } @@ -18493,53 +18407,6 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "node_modules/next": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/next/-/next-14.0.4.tgz", - "integrity": "sha512-qbwypnM7327SadwFtxXnQdGiKpkuhaRLE2uq62/nRul9cj9KhQ5LhHmlziTNqUidZotw/Q1I9OjirBROdUJNgA==", - "dev": true, - "dependencies": { - "@next/env": "14.0.4", - "@swc/helpers": "0.5.2", - "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", - "graceful-fs": "^4.2.11", - "postcss": "8.4.31", - "styled-jsx": "5.1.1", - "watchpack": "2.4.0" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": ">=18.17.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "14.0.4", - "@next/swc-darwin-x64": "14.0.4", - "@next/swc-linux-arm64-gnu": "14.0.4", - "@next/swc-linux-arm64-musl": "14.0.4", - "@next/swc-linux-x64-gnu": "14.0.4", - "@next/swc-linux-x64-musl": "14.0.4", - "@next/swc-win32-arm64-msvc": "14.0.4", - "@next/swc-win32-ia32-msvc": "14.0.4", - "@next/swc-win32-x64-msvc": "14.0.4" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, "node_modules/nice-napi": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", @@ -23173,29 +23040,6 @@ "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", "optional": true }, - "node_modules/styled-jsx": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", - "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", - "dev": true, - "dependencies": { - "client-only": "0.0.1" - }, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -25617,7 +25461,7 @@ } }, "packages/@apphosting/adapter-nextjs": { - "version": "14.0.18", + "version": "15.0.0", "license": "Apache-2.0", "dependencies": { "@apphosting/common": "*", @@ -25633,7 +25477,7 @@ "@types/mocha": "*", "@types/tmp": "*", "mocha": "*", - "next": "~14.0.0", + "next": "15.6.0-canary.54", "semver": "*", "tmp": "*", "ts-mocha": "*", @@ -25650,28 +25494,737 @@ } } }, - "packages/@apphosting/build": { - "version": "0.1.6", + "packages/@apphosting/adapter-nextjs-exp": { + "version": "15.0.0", + "extraneous": true, "license": "Apache-2.0", "dependencies": { "@apphosting/common": "*", - "@npmcli/promise-spawn": "^3.0.0", - "colorette": "^2.0.20", - "commander": "^11.1.0", - "npm-pick-manifest": "^9.0.0", - "ts-node": "^10.9.1" + "fs-extra": "^11.1.1", + "yaml": "^2.3.4" }, "bin": { - "apphosting-local-build": "dist/bin/localbuild.js" + "apphosting-adapter-nextjs-build": "dist/bin/build.js", + "apphosting-adapter-nextjs-create": "dist/bin/create.js" }, "devDependencies": { - "@types/commander": "*", + "@types/fs-extra": "*", + "@types/mocha": "*", + "@types/tmp": "*", + "mocha": "*", + "next": "~14.0.0", + "semver": "*", + "tmp": "*", "ts-mocha": "*", "ts-node": "*", - "typescript": "*" + "typescript": "*", + "verdaccio": "^5.30.3" + }, + "peerDependencies": { + "next": "*" + }, + "peerDependenciesMeta": { + "next": { + "optional": true + } } }, - "packages/@apphosting/build/node_modules/@npmcli/promise-spawn": { + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.4.tgz", + "integrity": "sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.3" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-darwin-x64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.4.tgz", + "integrity": "sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.3" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.3.tgz", + "integrity": "sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.3.tgz", + "integrity": "sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.3.tgz", + "integrity": "sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.3.tgz", + "integrity": "sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.3.tgz", + "integrity": "sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.3.tgz", + "integrity": "sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.3.tgz", + "integrity": "sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.3.tgz", + "integrity": "sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-linux-arm": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.4.tgz", + "integrity": "sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.3" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-linux-arm64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.4.tgz", + "integrity": "sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.3" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-linux-s390x": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.4.tgz", + "integrity": "sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.3" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-linux-x64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.4.tgz", + "integrity": "sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.3" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.4.tgz", + "integrity": "sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.3" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.4.tgz", + "integrity": "sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.3" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-wasm32": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.4.tgz", + "integrity": "sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.5.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-win32-ia32": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.4.tgz", + "integrity": "sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@img/sharp-win32-x64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.4.tgz", + "integrity": "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@next/env": { + "version": "15.6.0-canary.54", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.6.0-canary.54.tgz", + "integrity": "sha512-JgxtLpWVwu7iAC2oKmXSEZlAn7ogsPVWqBVGftwj9QpP0ufHASbt3UTHBXo2Fc4/Msl8PYeL19DlahcRfUDwaQ==", + "dev": true, + "license": "MIT" + }, + "packages/@apphosting/adapter-nextjs/node_modules/@next/swc-darwin-arm64": { + "version": "15.6.0-canary.54", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.6.0-canary.54.tgz", + "integrity": "sha512-B+QjESWfG3LdzQ9FhpmIrJQdYmJP9VhulKxaYUAimA2T+E+qxTk+IfeVkwqOmqWcubZeVBOLiREE+VOPXZtnAQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@next/swc-darwin-x64": { + "version": "15.6.0-canary.54", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.6.0-canary.54.tgz", + "integrity": "sha512-loW60NZS+xvItpdMRBCF1N0JJ98JmDmEH1jDsqO0VzQsrgS3cNnbVslnC6N3+7ndMDN+reasYA9gfkvFVn1Aww==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.6.0-canary.54", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.6.0-canary.54.tgz", + "integrity": "sha512-p66oPQzprGvp1TEvtNFuEiWxfflHOsvfJBfVJpOefmwnwsHbys2wSeA2tJD2xk8yzk5+ChT1X168atpKBdMKgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@next/swc-linux-arm64-musl": { + "version": "15.6.0-canary.54", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.6.0-canary.54.tgz", + "integrity": "sha512-JER2Y58ywlAQTa3eds3p6tNu9ts7nwVf31XBoA59yNIwQ1sgAm4+MGhs257FS/AW7FRclbSJw+FspEaq1SxbOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@next/swc-linux-x64-gnu": { + "version": "15.6.0-canary.54", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.6.0-canary.54.tgz", + "integrity": "sha512-lyc7WPq8l7wNS5l22ylDBcZw4m0+3kWKVuCQEL4u8RVHVkqds2XiW6T8hrdKMoHUynBJQxn0OnUvLTT7+1NCpQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@next/swc-linux-x64-musl": { + "version": "15.6.0-canary.54", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.6.0-canary.54.tgz", + "integrity": "sha512-NKa4/hFvHpSq7hvCzrnRwXyfj3PN7/Cquaz8aAlELfzEc+gGDUg2KjXwhEqtf4Br4PppLlDJSJZBr5hnCKJkLA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.6.0-canary.54", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.6.0-canary.54.tgz", + "integrity": "sha512-Zgib659a4e1fyunnyvP2WPClJei+riSVElY6ON5kNKu9sxVJNRHg6NidaJvJlv0kC+Twxwvrr9NF2h76hLpXsQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@next/swc-win32-x64-msvc": { + "version": "15.6.0-canary.54", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.6.0-canary.54.tgz", + "integrity": "sha512-/17K8vkgT5H4RbNFL6clVdtVnz5W/xLj1194uDF6ThiVfXG9Ml4mG3Jitiz2TUYS9uhAcwyhbCuqqR2/FcvFvg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/next": { + "version": "15.6.0-canary.54", + "resolved": "https://registry.npmjs.org/next/-/next-15.6.0-canary.54.tgz", + "integrity": "sha512-y7nLDe600/T6rbAz5JjQOCSHUzn9vm0t+OXy7F8qv+ZHCSaMj/hXgOiu9i4Z9O59v+rUrNV8n/vXi5yxgm7ZWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/env": "15.6.0-canary.54", + "@swc/helpers": "0.5.15", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.6.0-canary.54", + "@next/swc-darwin-x64": "15.6.0-canary.54", + "@next/swc-linux-arm64-gnu": "15.6.0-canary.54", + "@next/swc-linux-arm64-musl": "15.6.0-canary.54", + "@next/swc-linux-x64-gnu": "15.6.0-canary.54", + "@next/swc-linux-x64-musl": "15.6.0-canary.54", + "@next/swc-win32-arm64-msvc": "15.6.0-canary.54", + "@next/swc-win32-x64-msvc": "15.6.0-canary.54", + "sharp": "^0.34.4" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/sharp": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.4.tgz", + "integrity": "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.0", + "semver": "^7.7.2" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.4", + "@img/sharp-darwin-x64": "0.34.4", + "@img/sharp-libvips-darwin-arm64": "1.2.3", + "@img/sharp-libvips-darwin-x64": "1.2.3", + "@img/sharp-libvips-linux-arm": "1.2.3", + "@img/sharp-libvips-linux-arm64": "1.2.3", + "@img/sharp-libvips-linux-ppc64": "1.2.3", + "@img/sharp-libvips-linux-s390x": "1.2.3", + "@img/sharp-libvips-linux-x64": "1.2.3", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", + "@img/sharp-libvips-linuxmusl-x64": "1.2.3", + "@img/sharp-linux-arm": "0.34.4", + "@img/sharp-linux-arm64": "0.34.4", + "@img/sharp-linux-ppc64": "0.34.4", + "@img/sharp-linux-s390x": "0.34.4", + "@img/sharp-linux-x64": "0.34.4", + "@img/sharp-linuxmusl-arm64": "0.34.4", + "@img/sharp-linuxmusl-x64": "0.34.4", + "@img/sharp-wasm32": "0.34.4", + "@img/sharp-win32-arm64": "0.34.4", + "@img/sharp-win32-ia32": "0.34.4", + "@img/sharp-win32-x64": "0.34.4" + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "packages/@apphosting/adapter-nextjs/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "packages/@apphosting/build": { + "version": "0.1.6", + "license": "Apache-2.0", + "dependencies": { + "@apphosting/common": "*", + "@npmcli/promise-spawn": "^3.0.0", + "colorette": "^2.0.20", + "commander": "^11.1.0", + "npm-pick-manifest": "^9.0.0", + "ts-node": "^10.9.1" + }, + "bin": { + "apphosting-local-build": "dist/bin/localbuild.js" + }, + "devDependencies": { + "@types/commander": "*", + "ts-mocha": "*", + "ts-node": "*", + "typescript": "*" + } + }, + "packages/@apphosting/build/node_modules/@npmcli/promise-spawn": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz", "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", @@ -25753,7 +26306,7 @@ } }, "packages/@apphosting/common": { - "version": "0.0.8", + "version": "0.0.9", "license": "Apache-2.0" }, "packages/@apphosting/create": { diff --git a/packages/@apphosting/adapter-nextjs/package.json b/packages/@apphosting/adapter-nextjs/package.json index 3490ab47..0984abe6 100644 --- a/packages/@apphosting/adapter-nextjs/package.json +++ b/packages/@apphosting/adapter-nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@apphosting/adapter-nextjs", - "version": "14.0.18", + "version": "15.0.0", "main": "dist/index.js", "description": "Experimental addon to the Firebase CLI to add web framework support", "repository": { @@ -21,7 +21,7 @@ "type": "module", "sideEffects": false, "scripts": { - "build": "rm -rf dist && tsc && chmod +x ./dist/bin/*", + "build": "rm -rf dist && tsc && chmod +x ./dist/bin/* && npx -y esbuild ./dist/index.js --bundle --format=cjs --platform=node --outfile=./dist/index.cjs", "test": "npm run test:unit && npm run test:functional", "test:unit": "ts-mocha -p tsconfig.json 'src/**/*.spec.ts' 'src/*.spec.ts'", "test:functional": "node --loader ts-node/esm ./e2e/run-local.ts", @@ -30,7 +30,7 @@ }, "exports": { ".": { - "node": "./dist/index.js", + "node": "./dist/index.cjs", "default": null }, "./dist/*": { @@ -60,7 +60,7 @@ "@types/mocha": "*", "@types/tmp": "*", "mocha": "*", - "next": "~14.0.0", + "next": "15.6.0-canary.54", "semver": "*", "tmp": "*", "ts-mocha": "*", diff --git a/packages/@apphosting/adapter-nextjs/src/bin/build.spec.ts b/packages/@apphosting/adapter-nextjs/src/bin/build.spec.ts index e98d9f52..e68d5731 100644 --- a/packages/@apphosting/adapter-nextjs/src/bin/build.spec.ts +++ b/packages/@apphosting/adapter-nextjs/src/bin/build.spec.ts @@ -50,8 +50,6 @@ describe("build commands", () => { tmpDir, outputBundleOptions, path.join(tmpDir, ".next"), - defaultNextVersion, - adapterMetadata, ); await validateOutputDirectory(outputBundleOptions, path.join(tmpDir, ".next")); @@ -116,8 +114,6 @@ outputFiles: serverFilePath: path.join(tmpDir, ".next", "standalone", "apps", "next-app", "server.js"), }, path.join(tmpDir, ".next"), - defaultNextVersion, - adapterMetadata, ); const expectedFiles = { @@ -154,11 +150,6 @@ outputFiles: tmpDir, outputBundleOptions, path.join(tmpDir, ".next"), - defaultNextVersion, - { - adapterPackageName: "@apphosting/adapter-nextjs", - adapterVersion: "14.0.1", - }, ); assert.rejects( async () => await validateOutputDirectory(outputBundleOptions, path.join(tmpDir, ".next")), @@ -184,8 +175,6 @@ outputFiles: serverFilePath: path.join(standaloneAppPath, "server.js"), }, path.join(tmpDir, ".next"), - defaultNextVersion, - adapterMetadata, ); const expectedFiles = { @@ -214,8 +203,6 @@ outputFiles: tmpDir, outputBundleOptions, path.join(tmpDir, ".next"), - defaultNextVersion, - adapterMetadata, ); await validateOutputDirectory(outputBundleOptions, path.join(tmpDir, ".next")); @@ -240,11 +227,6 @@ outputFiles: tmpDir, outputBundleOptions, path.join(tmpDir, ".next"), - defaultNextVersion, - { - adapterPackageName: "@apphosting/adapter-nextjs", - adapterVersion: "14.0.1", - }, ); await validateOutputDirectory(outputBundleOptions, path.join(tmpDir, ".next")); @@ -276,8 +258,6 @@ outputFiles: tmpDir, outputBundleOptions, path.join(tmpDir, ".next"), - defaultNextVersion, - adapterMetadata, ); await validateOutputDirectory(outputBundleOptions, path.join(tmpDir, ".next")); diff --git a/packages/@apphosting/adapter-nextjs/src/bin/build.ts b/packages/@apphosting/adapter-nextjs/src/bin/build.ts index 1572adee..52b84632 100644 --- a/packages/@apphosting/adapter-nextjs/src/bin/build.ts +++ b/packages/@apphosting/adapter-nextjs/src/bin/build.ts @@ -1,78 +1,30 @@ #! /usr/bin/env node -import { - loadConfig, - populateOutputBundleOptions, - generateBuildOutput, - validateOutputDirectory, - getAdapterMetadata, - exists, -} from "../utils.js"; -import { join } from "path"; import { getBuildOptions, runBuild } from "@apphosting/common"; -import { - addRouteOverrides, - overrideNextConfig, - restoreNextConfig, - validateNextConfigOverride, -} from "../overrides.js"; +import { generateBuildOutput, getAdapterMetadata, loadConfig, populateOutputBundleOptions, validateOutputDirectory } from "../utils.js"; +import { join } from "node:path"; -const root = process.cwd(); -const opts = getBuildOptions(); - -// Set standalone mode -process.env.NEXT_PRIVATE_STANDALONE = "true"; // Opt-out sending telemetry to Vercel process.env.NEXT_TELEMETRY_DISABLED = "1"; -const nextConfig = await loadConfig(root, opts.projectDirectory); +await runBuild(); -/** - * Override user's Next Config to optimize the app for Firebase App Hosting - * and validate that the override resulted in a valid config that Next.js can - * load. - * - * We restore the user's Next Config at the end of the build, after the config file has been - * copied over to the output directory, so that the user's original code is not modified. - * - * If the app does not have a next.config.[js|mjs|ts] file in the first place, - * then can skip config override. - * - * Note: loadConfig always returns a fileName (default: next.config.js) even if - * one does not exist in the app's root: https://github.com/vercel/next.js/blob/23681508ca34b66a6ef55965c5eac57de20eb67f/packages/next/src/server/config.ts#L1115 - */ -const nextConfigPath = join(root, nextConfig.configFileName); -if (await exists(nextConfigPath)) { - await overrideNextConfig(root, nextConfig.configFileName); - await validateNextConfigOverride(root, opts.projectDirectory, nextConfig.configFileName); -} +const opts = getBuildOptions(); +const root = process.cwd(); -try { - await runBuild(); +const nextConfig = await loadConfig(root, opts.projectDirectory); - const adapterMetadata = getAdapterMetadata(); - const nextBuildDirectory = join(opts.projectDirectory, nextConfig.distDir); - const outputBundleOptions = populateOutputBundleOptions( +const nextBuildDirectory = join(opts.projectDirectory, nextConfig.distDir); +const outputBundleOptions = populateOutputBundleOptions( root, opts.projectDirectory, nextBuildDirectory, - ); +); - await addRouteOverrides( - outputBundleOptions.outputDirectoryAppPath, - nextConfig.distDir, - adapterMetadata, - ); - - const nextjsVersion = process.env.FRAMEWORK_VERSION || "unspecified"; - await generateBuildOutput( +await generateBuildOutput( root, opts.projectDirectory, outputBundleOptions, nextBuildDirectory, - nextjsVersion, - adapterMetadata, - ); - await validateOutputDirectory(outputBundleOptions, nextBuildDirectory); -} finally { - await restoreNextConfig(root, nextConfig.configFileName); -} +); + +await validateOutputDirectory(outputBundleOptions, nextBuildDirectory); diff --git a/packages/@apphosting/adapter-nextjs/src/index.ts b/packages/@apphosting/adapter-nextjs/src/index.ts index cb0ff5c3..7f4d7c13 100644 --- a/packages/@apphosting/adapter-nextjs/src/index.ts +++ b/packages/@apphosting/adapter-nextjs/src/index.ts @@ -1 +1,72 @@ -export {}; +import { generateBundleYaml, getAdapterMetadata, populateOutputBundleOptions } from "./utils.js"; +import type { NextAdapter } from "next"; +import { addRouteOverrides } from "./overrides.js"; +import { PHASE_PRODUCTION_BUILD } from "./constants.js"; + +const adapter: NextAdapter = { + name: '@apphosting/adapter-nextjs', + // FEEDBACK: we need to be able to override user-defined config, before defaults injected + // it would be nice if this where a separate phase or callback + async modifyConfig(config, { phase }) { + if (phase === PHASE_PRODUCTION_BUILD) { + return { + ...config, + images: { + ...(config.images || {}), + ...(config.images?.unoptimized === undefined && config.images?.loader === undefined + ? { unoptimized: true } + : {}), + }, + headers: async () => { + const originalHeaders = config.headers && await config.headers() || []; + const adapterMetadata = getAdapterMetadata(); + // TODO add our middleware header OR not... :P + return [ + ...originalHeaders, + { + source: "/(.*)", + headers: [{ + key: "x-fah-adapter", + value: `nextjs-${adapterMetadata.adapterVersion}`, + }], + }, + ] + }, + experimental: { + ...(config.experimental || {}), + nodeMiddleware: true, + }, + output: 'standalone', + } + } + // TODO override config for production build + return config; + }, + // This fires before standalone is bundled, so we need to pick things back up after build in bin/build.ts + // FEEDBACK: can we get a hook after bundle? + async onBuildComplete(context) { + + const nextBuildDirectory = context.distDir; + + if (context.outputs.middleware?.config?.matchers) { + await addRouteOverrides(nextBuildDirectory, context.outputs.middleware.config.matchers); + } + + const outputBundleOptions = populateOutputBundleOptions( + context.repoRoot, + context.projectDir, + nextBuildDirectory, + ); + + const adapterMetadata = getAdapterMetadata(); + + const root = process.cwd(); + + const nextjsVersion = process.env.FRAMEWORK_VERSION || context.nextVersion || "unspecified"; + + await generateBundleYaml(outputBundleOptions, root, nextjsVersion, adapterMetadata); + + }, +}; + +module.exports = adapter; diff --git a/packages/@apphosting/adapter-nextjs/src/overrides.spec.ts b/packages/@apphosting/adapter-nextjs/src/overrides.spec.ts deleted file mode 100644 index e223037c..00000000 --- a/packages/@apphosting/adapter-nextjs/src/overrides.spec.ts +++ /dev/null @@ -1,445 +0,0 @@ -import assert from "assert"; -import fs from "fs"; -import path from "path"; -import os from "os"; -import { RoutesManifest, MiddlewareManifest } from "./interfaces.js"; -const importOverrides = import("@apphosting/adapter-nextjs/dist/overrides.js"); - -describe("route overrides", () => { - let tmpDir: string; - let routesManifestPath: string; - let middlewareManifestPath: string; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "test-manifests-")); - routesManifestPath = path.join(tmpDir, ".next", "routes-manifest.json"); - middlewareManifestPath = path.join(tmpDir, ".next", "server", "middleware-manifest.json"); - - fs.mkdirSync(path.dirname(routesManifestPath), { recursive: true }); - fs.mkdirSync(path.dirname(middlewareManifestPath), { recursive: true }); - }); - - it("should add default fah headers to routes manifest", async () => { - const { addRouteOverrides } = await importOverrides; - const initialManifest: RoutesManifest = { - version: 3, - basePath: "", - pages404: true, - staticRoutes: [], - dynamicRoutes: [], - dataRoutes: [], - headers: [ - { - source: "/existing", - headers: [{ key: "X-Custom", value: "test" }], - regex: "^/existing$", - }, - ], - rewrites: [], - redirects: [], - }; - - fs.writeFileSync(routesManifestPath, JSON.stringify(initialManifest)); - fs.writeFileSync( - middlewareManifestPath, - JSON.stringify({ version: 1, sortedMiddleware: [], middleware: {}, functions: {} }), - ); - - await addRouteOverrides(tmpDir, ".next", { - adapterPackageName: "@apphosting/adapter-nextjs", - adapterVersion: "1.0.0", - }); - - const updatedManifest = JSON.parse( - fs.readFileSync(routesManifestPath, "utf-8"), - ) as RoutesManifest; - - const expectedManifest: RoutesManifest = { - version: 3, - basePath: "", - pages404: true, - staticRoutes: [], - dynamicRoutes: [], - dataRoutes: [], - redirects: [], - rewrites: [], - headers: [ - { - source: "/existing", - headers: [{ key: "X-Custom", value: "test" }], - regex: "^/existing$", - }, - { - source: "/:path*", - regex: "^(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))?(?:/)?$", - headers: [ - { - key: "x-fah-adapter", - value: "nextjs-1.0.0", - }, - ], - }, - ], - }; - - assert.deepStrictEqual(updatedManifest, expectedManifest); - }); - - it("should add middleware header only to routes for which middleware is enabled", async () => { - const { addRouteOverrides } = await importOverrides; - const initialManifest: RoutesManifest = { - version: 3, - basePath: "", - pages404: true, - staticRoutes: [], - dynamicRoutes: [], - dataRoutes: [], - headers: [], - rewrites: [], - redirects: [], - }; - - const middlewareManifest: MiddlewareManifest = { - version: 3, - sortedMiddleware: ["/"], - middleware: { - "/": { - files: ["middleware.ts"], - name: "middleware", - page: "/", - matchers: [ - { - regexp: "/hello", - originalSource: "/hello", - }, - ], - }, - }, - functions: {}, - }; - - fs.writeFileSync(routesManifestPath, JSON.stringify(initialManifest)); - fs.writeFileSync(middlewareManifestPath, JSON.stringify(middlewareManifest)); - - await addRouteOverrides(tmpDir, ".next", { - adapterPackageName: "@apphosting/adapter-nextjs", - adapterVersion: "1.0.0", - }); - - const updatedManifest = JSON.parse( - fs.readFileSync(routesManifestPath, "utf-8"), - ) as RoutesManifest; - - assert.strictEqual(updatedManifest.headers.length, 2); - - const expectedManifest: RoutesManifest = { - version: 3, - basePath: "", - pages404: true, - staticRoutes: [], - dynamicRoutes: [], - dataRoutes: [], - rewrites: [], - redirects: [], - headers: [ - { - source: "/:path*", - regex: "^(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))?(?:/)?$", - headers: [ - { - key: "x-fah-adapter", - value: "nextjs-1.0.0", - }, - ], - }, - { - source: "/hello", - regex: "/hello", - headers: [{ key: "x-fah-middleware", value: "true" }], - }, - ], - }; - - assert.deepStrictEqual(updatedManifest, expectedManifest); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); -}); - -describe("next config overrides", () => { - let tmpDir: string; - const nextConfigOverrideBody = ` - // This file was automatically generated by Firebase App Hosting adapter - const fahOptimizedConfig = (config) => ({ - ...config, - images: { - ...(config.images || {}), - ...(config.images?.unoptimized === undefined && config.images?.loader === undefined - ? { unoptimized: true } - : {}), - }, - }); - - const config = typeof originalConfig === 'function' - ? async (...args) => { - const resolvedConfig = await originalConfig(...args); - return fahOptimizedConfig(resolvedConfig); - } - : fahOptimizedConfig(originalConfig); - `; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "test-overrides")); - }); - - it("should set images.unoptimized to true - js normal config", async () => { - const { overrideNextConfig } = await importOverrides; - const originalConfig = ` - // @ts-check - - /** @type {import('next').NextConfig} */ - const nextConfig = { - /* config options here */ - } - - module.exports = nextConfig - `; - - fs.writeFileSync(path.join(tmpDir, "next.config.js"), originalConfig); - await overrideNextConfig(tmpDir, "next.config.js"); - - const updatedConfig = fs.readFileSync(path.join(tmpDir, "next.config.js"), "utf-8"); - - assert.equal( - normalizeWhitespace(updatedConfig), - normalizeWhitespace(` - // @ts-nocheck - const originalConfig = require('./next.config.original.js'); - - ${nextConfigOverrideBody} - - module.exports = config; - `), - ); - }); - - it("should set images.unoptimized to true - ECMAScript Modules", async () => { - const { overrideNextConfig } = await importOverrides; - const originalConfig = ` - // @ts-check - - /** - * @type {import('next').NextConfig} - */ - const nextConfig = { - /* config options here */ - } - - export default nextConfig - `; - - fs.writeFileSync(path.join(tmpDir, "next.config.mjs"), originalConfig); - await overrideNextConfig(tmpDir, "next.config.mjs"); - - const updatedConfig = fs.readFileSync(path.join(tmpDir, "next.config.mjs"), "utf-8"); - assert.equal( - normalizeWhitespace(updatedConfig), - normalizeWhitespace(` - // @ts-nocheck - import originalConfig from './next.config.original.mjs'; - - ${nextConfigOverrideBody} - - export default config; - `), - ); - }); - - it("should set images.unoptimized to true - ECMAScript Function", async () => { - const { overrideNextConfig } = await importOverrides; - const originalConfig = ` - // @ts-check - - export default (phase, { defaultConfig }) => { - /** - * @type {import('next').NextConfig} - */ - const nextConfig = { - /* config options here */ - } - return nextConfig - } - `; - - fs.writeFileSync(path.join(tmpDir, "next.config.mjs"), originalConfig); - await overrideNextConfig(tmpDir, "next.config.mjs"); - - const updatedConfig = fs.readFileSync(path.join(tmpDir, "next.config.mjs"), "utf-8"); - assert.equal( - normalizeWhitespace(updatedConfig), - normalizeWhitespace(` - // @ts-nocheck - import originalConfig from './next.config.original.mjs'; - - ${nextConfigOverrideBody} - - export default config; - `), - ); - }); - - it("should set images.unoptimized to true - TypeScript", async () => { - const { overrideNextConfig } = await importOverrides; - const originalConfig = ` - import type { NextConfig } from 'next' - - const nextConfig: NextConfig = { - /* config options here */ - } - - export default nextConfig - `; - - fs.writeFileSync(path.join(tmpDir, "next.config.ts"), originalConfig); - await overrideNextConfig(tmpDir, "next.config.ts"); - - const updatedConfig = fs.readFileSync(path.join(tmpDir, "next.config.ts"), "utf-8"); - assert.equal( - normalizeWhitespace(updatedConfig), - normalizeWhitespace(` - // @ts-nocheck - import originalConfig from './next.config.original'; - - ${nextConfigOverrideBody} - - module.exports = config; - `), - ); - }); - - it("should not do anything if no next.config.* file exists", async () => { - const { overrideNextConfig } = await importOverrides; - await overrideNextConfig(tmpDir, "next.config.js"); - - // Assert that no next.config* files were created - const files = fs.readdirSync(tmpDir); - const nextConfigFiles = files.filter((file) => file.startsWith("next.config")); - assert.strictEqual(nextConfigFiles.length, 0, "No next.config files should exist"); - }); -}); - -describe("validateNextConfigOverride", () => { - let tmpDir: string; - let root: string; - let projectRoot: string; - let originalConfigFileName: string; - let newConfigFileName: string; - let originalConfigPath: string; - let newConfigPath: string; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "test-next-config-override")); - root = tmpDir; - projectRoot = tmpDir; - originalConfigFileName = "next.config.js"; - newConfigFileName = "next.config.original.js"; - originalConfigPath = path.join(root, originalConfigFileName); - newConfigPath = path.join(root, newConfigFileName); - - fs.mkdirSync(root, { recursive: true }); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - it("should throw an error when new config file doesn't exist", async () => { - fs.writeFileSync(originalConfigPath, "module.exports = {}"); - - const { validateNextConfigOverride } = await importOverrides; - - await assert.rejects( - async () => await validateNextConfigOverride(root, projectRoot, originalConfigFileName), - /New Next.js config file not found/, - ); - }); - - it("should throw an error when original config file doesn't exist", async () => { - fs.writeFileSync(newConfigPath, "module.exports = {}"); - - const { validateNextConfigOverride } = await importOverrides; - - await assert.rejects( - async () => await validateNextConfigOverride(root, projectRoot, originalConfigFileName), - /Original Next.js config file not found/, - ); - }); -}); - -describe("next config restore", () => { - let tmpDir: string; - const nextConfigOriginalBody = ` - // @ts-check - - /** @type {import('next').NextConfig} */ - const nextConfig = { - /* config options here */ - } - - module.exports = nextConfig - `; - const nextConfigBody = ` - // This file was automatically generated by Firebase App Hosting adapter - const fahOptimizedConfig = (config) => ({ - ...config, - images: { - ...(config.images || {}), - ...(config.images?.unoptimized === undefined && config.images?.loader === undefined - ? { unoptimized: true } - : {}), - }, - }); - - const config = typeof originalConfig === 'function' - ? async (...args) => { - const resolvedConfig = await originalConfig(...args); - return fahOptimizedConfig(resolvedConfig); - } - : fahOptimizedConfig(originalConfig); - `; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "test-overrides")); - }); - - it("handle no original config file found", async () => { - const { restoreNextConfig } = await importOverrides; - fs.writeFileSync(path.join(tmpDir, "next.config.mjs"), nextConfigBody); - await restoreNextConfig(tmpDir, "next.config.mjs"); - - const restoredConfig = fs.readFileSync(path.join(tmpDir, "next.config.mjs"), "utf-8"); - assert.equal(restoredConfig, nextConfigBody); - }); - - it("handle no config file found", async () => { - const { restoreNextConfig } = await importOverrides; - assert.doesNotReject(restoreNextConfig(tmpDir, "next.config.mjs")); - }); - - it("original config file restored", async () => { - const { restoreNextConfig } = await importOverrides; - fs.writeFileSync(path.join(tmpDir, "next.config.mjs"), nextConfigBody); - fs.writeFileSync(path.join(tmpDir, "next.config.original.mjs"), nextConfigOriginalBody); - await restoreNextConfig(tmpDir, "next.config.mjs"); - - const restoredConfig = fs.readFileSync(path.join(tmpDir, "next.config.mjs"), "utf-8"); - assert.equal(restoredConfig, nextConfigOriginalBody); - }); -}); - -// Normalize whitespace for comparison -function normalizeWhitespace(str: string) { - return str.replace(/\s+/g, " ").trim(); -} diff --git a/packages/@apphosting/adapter-nextjs/src/overrides.ts b/packages/@apphosting/adapter-nextjs/src/overrides.ts index 5edd0d54..a2d7f656 100644 --- a/packages/@apphosting/adapter-nextjs/src/overrides.ts +++ b/packages/@apphosting/adapter-nextjs/src/overrides.ts @@ -1,169 +1,8 @@ -import { AdapterMetadata } from "./interfaces.js"; +import type { MiddlewareMatcher } from "next/dist/build/analysis/get-page-static-info.js"; import { loadRouteManifest, writeRouteManifest, - loadMiddlewareManifest, - exists, - writeFile, - loadConfig, } from "./utils.js"; -import { join, extname } from "path"; -import { rename as renamePromise } from "fs/promises"; - -/** - * Overrides the user's Next Config file (next.config.[ts|js|mjs]) to add configs - * optimized for Firebase App Hosting. - */ -export async function overrideNextConfig(projectRoot: string, nextConfigFileName: string) { - console.log(`Overriding Next Config to add configs optmized for Firebase App Hosting`); - // Check if the file exists in the current working directory - const configPath = join(projectRoot, nextConfigFileName); - - if (!(await exists(configPath))) { - console.log(`No Next.js config file found at ${configPath}`); - return; - } - - // Determine the file extension - const fileExtension = extname(nextConfigFileName); - const originalConfigName = `next.config.original${fileExtension}`; - - // Rename the original config file - try { - const originalPath = join(projectRoot, originalConfigName); - await renamePromise(configPath, originalPath); - - // Create a new config file with the appropriate import - let importStatement; - switch (fileExtension) { - case ".js": - importStatement = `const originalConfig = require('./${originalConfigName}');`; - break; - case ".mjs": - importStatement = `import originalConfig from './${originalConfigName}';`; - break; - case ".ts": - importStatement = `import originalConfig from './${originalConfigName.replace( - ".ts", - "", - )}';`; - break; - default: - throw new Error( - `Unsupported file extension for Next Config: "${fileExtension}", please use ".js", ".mjs", or ".ts"`, - ); - } - - // Create the new config content with our overrides - const newConfigContent = getCustomNextConfig(importStatement, fileExtension); - - // Write the new config file - await writeFile(join(projectRoot, nextConfigFileName), newConfigContent); - console.log(`Successfully created ${nextConfigFileName} with Firebase App Hosting overrides`); - } catch (error) { - console.error(`Error overriding Next.js config: ${error}`); - throw error; - } -} - -/** - * Returns a custom Next.js config that optimizes the app for Firebase App Hosting. - * - * Current overrides include: - * - images.unoptimized = true, unless user explicitly sets images.unoptimized to false or - * is using a custom image loader. - * @param importStatement The import statement for the original config. - * @param fileExtension The file extension of the original config. Use ".js", ".mjs", or ".ts" - * @return The custom Next.js config. - */ -function getCustomNextConfig(importStatement: string, fileExtension: string) { - return ` - // @ts-nocheck - ${importStatement} - - // This file was automatically generated by Firebase App Hosting adapter - const fahOptimizedConfig = (config) => ({ - ...config, - images: { - ...(config.images || {}), - ...(config.images?.unoptimized === undefined && config.images?.loader === undefined - ? { unoptimized: true } - : {}), - }, - }); - - const config = typeof originalConfig === 'function' - ? async (...args) => { - const resolvedConfig = await originalConfig(...args); - return fahOptimizedConfig(resolvedConfig); - } - : fahOptimizedConfig(originalConfig); - - ${fileExtension === ".mjs" ? "export default config;" : "module.exports = config;"} - `; -} - -/** - * This function is used to validate the state of an app after running the - * overrideNextConfig. It validates that: - * 1. original next config is preserved - * 2. a new next config is created - * 3. new next config can be loaded by NextJs without any issues. - */ -export async function validateNextConfigOverride( - root: string, - projectRoot: string, - originalConfigFileName: string, -) { - const originalConfigExtension = extname(originalConfigFileName); - const newConfigFileName = `next.config.original${originalConfigExtension}`; - const newConfigFilePath = join(root, newConfigFileName); - if (!(await exists(newConfigFilePath))) { - throw new Error( - `Next Config Override Failed: New Next.js config file not found at ${newConfigFilePath}`, - ); - } - - const originalNextConfigFilePath = join(root, originalConfigFileName); - if (!(await exists(originalNextConfigFilePath))) { - throw new Error( - `Next Config Override Failed: Original Next.js config file not found at ${originalNextConfigFilePath}`, - ); - } - - try { - await loadConfig(root, projectRoot); - } catch (error) { - throw new Error( - `Resulting Next Config is invalid: ${ - error instanceof Error ? error.message : "Unknown error" - }`, - ); - } -} - -/** - * Restores the user's original Next Config file (next.config.original.[ts|js|mjs]) - * to leave user code the way we found it. - */ -export async function restoreNextConfig(projectRoot: string, nextConfigFileName: string) { - // Determine the file extension - const fileExtension = extname(nextConfigFileName); - const originalConfigPath = join(projectRoot, `next.config.original${fileExtension}`); - - if (!(await exists(originalConfigPath))) { - // No backup file found, nothing to restore. - return; - } - console.log(`Restoring original next config in project root`); - - const configPath = join(projectRoot, nextConfigFileName); - try { - await renamePromise(originalConfigPath, configPath); - } catch (error) { - console.error(`Error restoring Next config: ${error}`); - } -} /** * Modifies the app's route manifest (routes-manifest.json) to add Firebase App Hosting @@ -179,39 +18,12 @@ export async function restoreNextConfig(projectRoot: string, nextConfigFileName: * @param adapterMetadata The adapter metadata. */ export async function addRouteOverrides( - appPath: string, distDir: string, - adapterMetadata: AdapterMetadata, + middlewareMatchers: MiddlewareMatcher[], ) { - const routeManifest = loadRouteManifest(appPath, distDir); - - // Add the adapter version to all routes - routeManifest.headers.push({ - source: "/:path*", - headers: [ - { - key: "x-fah-adapter", - value: `nextjs-${adapterMetadata.adapterVersion}`, - }, - ], - /* - NextJs converts the source string to a regex using path-to-regexp (https://github.com/pillarjs/path-to-regexp) at - build time: https://github.com/vercel/next.js/blob/canary/packages/next/src/build/index.ts#L1273. - This regex is then used to match the route against the request path. - - This regex was generated by building a sample NextJs app with the source string `/:path*` and then inspecting the - routes-manifest.json file. - */ - regex: "^(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))?(?:/)?$", - }); - - // Add the middleware header to all routes for which middleware is enabled - const middlewareManifest = loadMiddlewareManifest(appPath, distDir); - const rootMiddleware = middlewareManifest.middleware["/"]; - if (rootMiddleware?.matchers) { - console.log("Middleware detected, adding middleware headers to matching routes"); + const routeManifest = loadRouteManifest(distDir); - rootMiddleware.matchers.forEach((matcher) => { + middlewareMatchers.forEach((matcher) => { routeManifest.headers.push({ source: matcher.originalSource, headers: [ @@ -223,7 +35,6 @@ export async function addRouteOverrides( regex: matcher.regexp, }); }); - } - await writeRouteManifest(appPath, distDir, routeManifest); -} + await writeRouteManifest(distDir, routeManifest); +} \ No newline at end of file diff --git a/packages/@apphosting/adapter-nextjs/src/utils.spec.ts b/packages/@apphosting/adapter-nextjs/src/utils.spec.ts index 5ae25a08..c55f4dc5 100644 --- a/packages/@apphosting/adapter-nextjs/src/utils.spec.ts +++ b/packages/@apphosting/adapter-nextjs/src/utils.spec.ts @@ -4,7 +4,7 @@ import assert from "assert"; import fs from "fs"; import path from "path"; import os from "os"; -import { RoutesManifest, MiddlewareManifest } from "../src/interfaces.js"; +import { RoutesManifest, MiddlewareManifest } from "./interfaces.js"; describe("manifest utils", () => { let tmpDir: string; diff --git a/packages/@apphosting/adapter-nextjs/src/utils.ts b/packages/@apphosting/adapter-nextjs/src/utils.ts index 3c6ab548..2e535027 100644 --- a/packages/@apphosting/adapter-nextjs/src/utils.ts +++ b/packages/@apphosting/adapter-nextjs/src/utils.ts @@ -1,23 +1,29 @@ import fsExtra from "fs-extra"; -import { createRequire } from "node:module"; import { join, dirname, relative, normalize } from "path"; -import { fileURLToPath } from "url"; import { stringify as yamlStringify } from "yaml"; +import { createRequire } from "node:module"; -import { PHASE_PRODUCTION_BUILD, ROUTES_MANIFEST, MIDDLEWARE_MANIFEST } from "./constants.js"; import { OutputBundleOptions, - RoutesManifest, AdapterMetadata, - MiddlewareManifest, + RoutesManifest, } from "./interfaces.js"; -import { NextConfigComplete } from "next/dist/server/config-shared.js"; import { OutputBundleConfig, updateOrCreateGitignore } from "@apphosting/common"; +import { fileURLToPath } from "url"; + +import { PHASE_PRODUCTION_BUILD, ROUTES_MANIFEST } from "./constants.js"; +import type { NextConfigComplete } from "next/dist/server/config-shared.js"; // fs-extra is CJS, readJson can't be imported using shorthand export const { copy, exists, writeFile, readJson, readdir, readFileSync, existsSync, ensureDir } = fsExtra; +export const isMain = (meta: ImportMeta): boolean => { + if (!meta) return false; + if (!process.argv[1]) return false; + return process.argv[1] === fileURLToPath(meta.url); +}; + // Loads the user's next.config.js file. export async function loadConfig(root: string, projectRoot: string): Promise { // createRequire() gives us access to Node's CommonJS implementation of require.resolve() @@ -38,53 +44,6 @@ export async function loadConfig(root: string, projectRoot: string): Promise { - const manifestPath = join(standalonePath, distDir, ROUTES_MANIFEST); - await writeFile(manifestPath, JSON.stringify(customManifest)); -} - -export const isMain = (meta: ImportMeta): boolean => { - if (!meta) return false; - if (!process.argv[1]) return false; - return process.argv[1] === fileURLToPath(meta.url); -}; /** * Provides the paths in the output bundle for the built artifacts. @@ -115,6 +74,33 @@ export function populateOutputBundleOptions( }; } +/** + * Loads the route manifest from the standalone directory. + * @param standalonePath The path to the standalone directory. + * @param distDir The path to the dist directory. + * @return The route manifest. + */ +export function loadRouteManifest(distDir: string): RoutesManifest { + const manifestPath = join(distDir, ROUTES_MANIFEST); + const json = readFileSync(manifestPath, "utf-8"); + return JSON.parse(json) as RoutesManifest; +} + + +/** + * Writes the route manifest to the standalone directory. + * @param standalonePath The path to the standalone directory. + * @param distDir The path to the dist directory. + * @param customManifest The route manifest to write. + */ +export async function writeRouteManifest( + distDir: string, + customManifest: RoutesManifest, +): Promise { + const manifestPath = join(distDir, ROUTES_MANIFEST); + await writeFile(manifestPath, JSON.stringify(customManifest)); +} + /** * Copy static assets and other resources into the standlone directory, also generates the bundle.yaml * @param rootDir The root directory of the uploaded source code. @@ -126,14 +112,11 @@ export async function generateBuildOutput( appDir: string, opts: OutputBundleOptions, nextBuildDirectory: string, - nextVersion: string, - adapterMetadata: AdapterMetadata, ): Promise { const staticDirectory = join(nextBuildDirectory, "static"); await Promise.all([ copy(staticDirectory, opts.outputStaticDirectoryPath, { overwrite: true }), copyResources(appDir, opts.outputDirectoryAppPath, opts.bundleYamlPath), - generateBundleYaml(opts, rootDir, nextVersion, adapterMetadata), ]); // generateBundleYaml creates the output directory (if it does not already exist). // We need to make sure it is gitignored. @@ -165,8 +148,7 @@ async function copyResources( } export function getAdapterMetadata(): AdapterMetadata { - const directoryName = dirname(fileURLToPath(import.meta.url)); - const packageJsonPath = `${directoryName}/../package.json`; + const packageJsonPath = `${__dirname}/../package.json`; if (!existsSync(packageJsonPath)) { throw new Error(`Next.js adapter package.json file does not exist at ${packageJsonPath}`); } @@ -179,7 +161,7 @@ export function getAdapterMetadata(): AdapterMetadata { } // generate bundle.yaml -async function generateBundleYaml( +export async function generateBundleYaml( opts: OutputBundleOptions, cwd: string, nextVersion: string,