diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e074a6c909ac..47d7daf588ba 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -28,13 +28,13 @@ # Tooling & Telemetry -/packages/next/src/build/ @timneutkens @ijjk @shuding @huozhi @ztanner @feedthejim @vercel/web-tooling -/packages/next/src/server/lib/router-utils/setup-dev.ts @timneutkens @ijjk @shuding @huozhi @feedthejim @ztanner @wyattjoh @vercel/web-tooling -/packages/next/src/telemetry/ @timneutkens @ijjk @shuding @padmaia -/packages/next-swc/ @timneutkens @ijjk @shuding @huozhi @vercel/web-tooling -Cargo.toml @timneutkens @ijjk @shuding @huozhi @vercel/web-tooling -Cargo.lock @timneutkens @ijjk @shuding @huozhi @vercel/web-tooling -/.cargo/config.toml @timneutkens @ijjk @shuding @huozhi @vercel/web-tooling -/.config/nextest.toml @timneutkens @ijjk @shuding @huozhi @vercel/web-tooling -/test/build-turbopack-tests-manifest.js @timneutkens @ijjk @shuding @huozhi @vercel/web-tooling -/test/turbopack-tests-manifest.json @timneutkens @ijjk @shuding @huozhi @vercel/web-tooling +/packages/next/src/build/ @timneutkens @ijjk @shuding @huozhi @ztanner @feedthejim @vercel/web-tooling +/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts @timneutkens @ijjk @shuding @huozhi @feedthejim @ztanner @wyattjoh @vercel/web-tooling +/packages/next/src/telemetry/ @timneutkens @ijjk @shuding @padmaia +/packages/next-swc/ @timneutkens @ijjk @shuding @huozhi @vercel/web-tooling +Cargo.toml @timneutkens @ijjk @shuding @huozhi @vercel/web-tooling +Cargo.lock @timneutkens @ijjk @shuding @huozhi @vercel/web-tooling +/.cargo/config.toml @timneutkens @ijjk @shuding @huozhi @vercel/web-tooling +/.config/nextest.toml @timneutkens @ijjk @shuding @huozhi @vercel/web-tooling +/test/build-turbopack-tests-manifest.js @timneutkens @ijjk @shuding @huozhi @vercel/web-tooling +/test/turbopack-tests-manifest.json @timneutkens @ijjk @shuding @huozhi @vercel/web-tooling diff --git a/Cargo.lock b/Cargo.lock index cbe4f11704af..a1b72d2c8712 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -289,9 +289,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", @@ -321,7 +321,7 @@ dependencies = [ [[package]] name = "auto-hash-map" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "serde", "smallvec", @@ -3515,7 +3515,7 @@ dependencies = [ [[package]] name = "node-file-trace" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "serde", @@ -7368,7 +7368,7 @@ dependencies = [ [[package]] name = "turbo-tasks" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "async-trait", @@ -7400,7 +7400,7 @@ dependencies = [ [[package]] name = "turbo-tasks-build" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "cargo-lock", @@ -7412,7 +7412,7 @@ dependencies = [ [[package]] name = "turbo-tasks-bytes" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "bytes", @@ -7427,7 +7427,7 @@ dependencies = [ [[package]] name = "turbo-tasks-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "dotenvs", @@ -7441,7 +7441,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fetch" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -7458,7 +7458,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fs" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "auto-hash-map", @@ -7488,7 +7488,7 @@ dependencies = [ [[package]] name = "turbo-tasks-hash" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "base16", "hex", @@ -7500,7 +7500,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -7514,7 +7514,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros-shared" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "proc-macro2", "quote", @@ -7524,7 +7524,7 @@ dependencies = [ [[package]] name = "turbo-tasks-malloc" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "mimalloc", ] @@ -7532,7 +7532,7 @@ dependencies = [ [[package]] name = "turbo-tasks-memory" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "auto-hash-map", @@ -7557,7 +7557,7 @@ dependencies = [ [[package]] name = "turbopack" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "async-recursion", @@ -7588,7 +7588,7 @@ dependencies = [ [[package]] name = "turbopack-binding" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "auto-hash-map", "mdxjs", @@ -7628,7 +7628,7 @@ dependencies = [ [[package]] name = "turbopack-build" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -7650,7 +7650,7 @@ dependencies = [ [[package]] name = "turbopack-cli-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "clap 4.4.2", @@ -7674,7 +7674,7 @@ dependencies = [ [[package]] name = "turbopack-core" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "async-recursion", @@ -7703,7 +7703,7 @@ dependencies = [ [[package]] name = "turbopack-css" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "async-trait", @@ -7725,7 +7725,7 @@ dependencies = [ [[package]] name = "turbopack-dev" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -7749,7 +7749,7 @@ dependencies = [ [[package]] name = "turbopack-dev-server" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "async-compression", @@ -7786,7 +7786,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "async-trait", @@ -7820,7 +7820,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-hmr-protocol" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "serde", "serde_json", @@ -7831,7 +7831,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-plugins" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "async-trait", @@ -7854,7 +7854,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-runtime" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "indoc", @@ -7871,7 +7871,7 @@ dependencies = [ [[package]] name = "turbopack-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -7887,7 +7887,7 @@ dependencies = [ [[package]] name = "turbopack-image" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "base64 0.21.4", @@ -7907,7 +7907,7 @@ dependencies = [ [[package]] name = "turbopack-json" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "serde", @@ -7922,7 +7922,7 @@ dependencies = [ [[package]] name = "turbopack-mdx" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "mdxjs", @@ -7937,7 +7937,7 @@ dependencies = [ [[package]] name = "turbopack-node" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "async-stream", @@ -7972,7 +7972,7 @@ dependencies = [ [[package]] name = "turbopack-static" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "serde", @@ -7988,7 +7988,7 @@ dependencies = [ [[package]] name = "turbopack-swc-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "swc_core", "turbo-tasks", @@ -7999,7 +7999,7 @@ dependencies = [ [[package]] name = "turbopack-wasm" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231002.1#dc1e2a7a4aa4cbd88c7144bf0bdd4fd0589373c1" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231006.2#624521ff91ac654c11072581867f558c26d285ab" dependencies = [ "anyhow", "indexmap 1.9.3", diff --git a/Cargo.toml b/Cargo.toml index 5d2d40a9adb0..0d80789e361c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,11 +40,11 @@ swc_core = { version = "0.83.28", features = [ testing = { version = "0.34.1" } # Turbo crates -turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231002.1" } +turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231006.2" } # [TODO]: need to refactor embed_directory! macro usages, as well as resolving turbo_tasks::function, macros.. -turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231002.1" } +turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231006.2" } # [TODO]: need to refactor embed_directory! macro usage in next-core -turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231002.1" } +turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231006.2" } # General Deps diff --git a/lerna.json b/lerna.json index b4ff2eda07dc..73f7830deabd 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "13.5.5-canary.2" + "version": "13.5.5-canary.3" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 1ca01794a8ee..bda0b44a9471 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index ab5cafb81e28..eb08d2c37fbb 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "13.5.5-canary.2", + "@next/eslint-plugin-next": "13.5.5-canary.3", "@rushstack/eslint-patch": "^1.3.3", "@typescript-eslint/parser": "^5.4.2 || ^6.0.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index d37cf3822c4f..98de0667bb45 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index e8dac1caf89d..26ab2c54328d 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 44ac0d40b40a..6a61ed82deca 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 81b150a3b928..eb8b9aa8c42f 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index e3c5a99ea548..441ce48dd794 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 102a8ed4d33e..70af876473f6 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index cd3dca272564..a6eefa6c8379 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index d498743e0287..5985e40f640d 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index c715e5a21092..c327aa6ecdf1 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/crates/core/src/react_server_components.rs b/packages/next-swc/crates/core/src/react_server_components.rs index 8dd923dc61c7..8d136e78b09d 100644 --- a/packages/next-swc/crates/core/src/react_server_components.rs +++ b/packages/next-swc/crates/core/src/react_server_components.rs @@ -344,6 +344,10 @@ impl ReactServerComponents { } fn assert_server_graph(&self, imports: &[ModuleImports], module: &Module) { + // If the + if self.is_from_node_modules(&self.filepath) { + return; + } for import in imports { let source = import.source.0.clone(); if self.invalid_server_imports.contains(&source) { @@ -391,6 +395,9 @@ impl ReactServerComponents { } fn assert_server_filename(&self, module: &Module) { + if self.is_from_node_modules(&self.filepath) { + return; + } let is_error_file = Regex::new(r"[\\/]error\.(ts|js)x?$") .unwrap() .is_match(&self.filepath); @@ -416,6 +423,9 @@ impl ReactServerComponents { } fn assert_client_graph(&self, imports: &[ModuleImports]) { + if self.is_from_node_modules(&self.filepath) { + return; + } for import in imports { let source = import.source.0.clone(); if self.invalid_client_imports.contains(&source) { @@ -432,6 +442,9 @@ impl ReactServerComponents { } fn assert_invalid_api(&self, module: &Module, is_client_entry: bool) { + if self.is_from_node_modules(&self.filepath) { + return; + } let is_layout_or_page = Regex::new(r"[\\/](page|layout)\.(ts|js)x?$") .unwrap() .is_match(&self.filepath); @@ -562,6 +575,12 @@ impl ReactServerComponents { }, ); } + + fn is_from_node_modules(&self, filepath: &str) -> bool { + Regex::new(r"[\\/]node_modules[\\/]") + .unwrap() + .is_match(filepath) + } } pub fn server_components( diff --git a/packages/next-swc/crates/next-api/src/app.rs b/packages/next-swc/crates/next-api/src/app.rs index cd9ac1a0e352..1b0684d6746d 100644 --- a/packages/next-swc/crates/next-api/src/app.rs +++ b/packages/next-swc/crates/next-api/src/app.rs @@ -39,8 +39,9 @@ use turbopack_binding::{ turbopack::{ core::{ asset::{Asset, AssetContent}, - chunk::{ChunkableModule, ChunkingContext, EvaluatableAssets}, + chunk::{ChunkingContext, EvaluatableAssets}, file_source::FileSource, + module::Module, output::{OutputAsset, OutputAssets}, virtual_output::VirtualOutputAsset, }, @@ -507,7 +508,13 @@ impl AppEndpoint { let mut server_assets = vec![]; let mut client_assets = vec![]; + let app_entry = app_entry.await?; + let client_shared_chunks = get_app_client_shared_chunks( + app_entry + .rsc_entry + .ident() + .with_modifier(Vc::cell("client_shared_chunks".to_string())), this.app_project.client_runtime_entries(), this.app_project.project().client_chunking_context(), ); @@ -524,7 +531,6 @@ impl AppEndpoint { } } - let app_entry = app_entry.await?; let rsc_entry = app_entry.rsc_entry; let rsc_entry_asset = Vc::upcast(rsc_entry); @@ -707,9 +713,7 @@ impl AppEndpoint { } let files = chunking_context.evaluated_chunk_group( - app_entry - .rsc_entry - .as_root_chunk(Vc::upcast(chunking_context)), + app_entry.rsc_entry.ident(), Vc::cell(evaluatable_assets), ); server_assets.extend(files.await?.iter().copied()); diff --git a/packages/next-swc/crates/next-api/src/middleware.rs b/packages/next-swc/crates/next-api/src/middleware.rs index b86185ccb80e..ba5f17524f77 100644 --- a/packages/next-swc/crates/next-api/src/middleware.rs +++ b/packages/next-swc/crates/next-api/src/middleware.rs @@ -13,7 +13,7 @@ use turbopack_binding::{ turbopack::{ core::{ asset::AssetContent, - chunk::{ChunkableModule, ChunkingContext}, + chunk::ChunkingContext, context::AssetContext, module::Module, output::{OutputAsset, OutputAssets}, @@ -88,10 +88,8 @@ impl MiddlewareEndpoint { let edge_chunking_context = self.project.edge_middleware_chunking_context(); - let edge_files = edge_chunking_context.evaluated_chunk_group( - module.as_root_chunk(Vc::upcast(edge_chunking_context)), - Vc::cell(evaluatable_assets), - ); + let edge_files = edge_chunking_context + .evaluated_chunk_group(module.ident(), Vc::cell(evaluatable_assets)); Ok(edge_files) } diff --git a/packages/next-swc/crates/next-api/src/pages.rs b/packages/next-swc/crates/next-api/src/pages.rs index b4e5ec17bc77..8d8f6705e8b1 100644 --- a/packages/next-swc/crates/next-api/src/pages.rs +++ b/packages/next-swc/crates/next-api/src/pages.rs @@ -37,10 +37,11 @@ use turbopack_binding::{ build::BuildChunkingContext, core::{ asset::AssetContent, - chunk::{ChunkableModule, ChunkingContext, EvaluatableAssets}, + chunk::{ChunkingContext, EvaluatableAssets}, context::AssetContext, file_source::FileSource, issue::{IssueSeverity, OptionIssueSource}, + module::Module, output::{OutputAsset, OutputAssets}, reference_type::{ EcmaScriptModulesReferenceSubType, EntryReferenceSubType, ReferenceType, @@ -549,11 +550,9 @@ impl PageEndpoint { let client_chunking_context = this.pages_project.project().client_chunking_context(); - let client_entry_chunk = client_module.as_root_chunk(Vc::upcast(client_chunking_context)); - let mut client_chunks = client_chunking_context .evaluated_chunk_group( - client_entry_chunk, + client_module.ident(), this.pages_project .client_runtime_entries() .with_entry(Vc::upcast(client_main_module)) @@ -611,10 +610,8 @@ impl PageEndpoint { }; evaluatable_assets.push(evaluatable); - let edge_files = edge_chunking_context.evaluated_chunk_group( - ssr_module.as_root_chunk(Vc::upcast(edge_chunking_context)), - Vc::cell(evaluatable_assets), - ); + let edge_files = edge_chunking_context + .evaluated_chunk_group(ssr_module.ident(), Vc::cell(evaluatable_assets)); Ok(SsrChunk::Edge { files: edge_files }.cell()) } else { diff --git a/packages/next-swc/crates/next-api/src/server_actions.rs b/packages/next-swc/crates/next-api/src/server_actions.rs index 7b0428d5ad39..3ef3583dee0b 100644 --- a/packages/next-swc/crates/next-api/src/server_actions.rs +++ b/packages/next-swc/crates/next-api/src/server_actions.rs @@ -16,13 +16,18 @@ use turbopack_binding::{ turbo::tasks_fs::{rope::RopeBuilder, File, FileSystemPath}, turbopack::{ core::{ - asset::AssetContent, chunk::EvaluatableAsset, context::AssetContext, module::Module, - output::OutputAsset, reference::primary_referenced_modules, - reference_type::ReferenceType, virtual_output::VirtualOutputAsset, + asset::AssetContent, + chunk::{ChunkItemExt, ChunkableModule, EvaluatableAsset}, + context::AssetContext, + module::Module, + output::OutputAsset, + reference::primary_referenced_modules, + reference_type::ReferenceType, + virtual_output::VirtualOutputAsset, virtual_source::VirtualSource, }, ecmascript::{ - chunk::{EcmascriptChunkItemExt, EcmascriptChunkPlaceable, EcmascriptChunkingContext}, + chunk::{EcmascriptChunkPlaceable, EcmascriptChunkingContext}, parse::ParseResult, EcmascriptModuleAsset, }, @@ -72,7 +77,10 @@ pub(crate) async fn create_server_actions_manifest( bail!("loader module must be evaluatable"); }; - let loader_id = loader.as_chunk_item(chunking_context).id().to_string(); + let loader_id = loader + .as_chunk_item(Vc::upcast(chunking_context)) + .id() + .to_string(); let manifest = build_manifest(node_root, pathname, page_name, runtime, actions, loader_id).await?; Ok((Some(evaluable), manifest)) diff --git a/packages/next-swc/crates/next-build/src/next_app/app_entries.rs b/packages/next-swc/crates/next-build/src/next_app/app_entries.rs index 57c5143babb9..e8a05d1a8626 100644 --- a/packages/next-swc/crates/next-build/src/next_app/app_entries.rs +++ b/packages/next-swc/crates/next-build/src/next_app/app_entries.rs @@ -27,7 +27,10 @@ use turbopack_binding::{ turbopack::{ build::BuildChunkingContext, core::{ - chunk::EvaluatableAssets, compile_time_info::CompileTimeInfo, file_source::FileSource, + chunk::{ChunkingContext, EvaluatableAssets}, + compile_time_info::CompileTimeInfo, + file_source::FileSource, + ident::AssetIdent, output::OutputAsset, }, ecmascript::chunk::EcmascriptChunkingContext, @@ -256,8 +259,15 @@ pub async fn compute_app_entries_chunks( ) -> Result<()> { let client_relative_path_ref = client_relative_path.await?; - let app_client_shared_chunks = - get_app_client_shared_chunks(app_entries.client_runtime_entries, client_chunking_context); + let app_client_shared_chunks = get_app_client_shared_chunks( + AssetIdent::from_path( + client_chunking_context + .context_path() + .join("client shared chunk group".to_string()), + ), + app_entries.client_runtime_entries, + client_chunking_context, + ); let mut app_shared_client_chunks_paths = vec![]; for chunk in app_client_shared_chunks.await?.iter().copied() { diff --git a/packages/next-swc/crates/next-build/src/next_pages/page_entries.rs b/packages/next-swc/crates/next-build/src/next_pages/page_entries.rs index bbbe6c9ae3fc..0b183f7e535e 100644 --- a/packages/next-swc/crates/next-build/src/next_pages/page_entries.rs +++ b/packages/next-swc/crates/next-build/src/next_pages/page_entries.rs @@ -27,10 +27,11 @@ use turbopack_binding::{ turbopack::{ build::BuildChunkingContext, core::{ - chunk::{ChunkableModule, ChunkingContext, EvaluatableAssets}, + chunk::{ChunkingContext, EvaluatableAssets}, compile_time_info::CompileTimeInfo, context::AssetContext, file_source::FileSource, + module::Module, output::OutputAsset, reference_type::{EntryReferenceSubType, ReferenceType}, source::Source, @@ -400,12 +401,8 @@ pub async fn compute_page_entries_chunks( .insert(pathname.clone_value(), asset_path.to_string()); } - let client_entry_chunk = page_entry - .client_module - .as_root_chunk(Vc::upcast(client_chunking_context)); - let client_chunks = client_chunking_context.evaluated_chunk_group( - client_entry_chunk, + page_entry.client_module.ident(), page_entries .client_runtime_entries .with_entry(Vc::upcast(page_entry.client_module)), diff --git a/packages/next-swc/crates/next-core/src/middleware.rs b/packages/next-swc/crates/next-core/src/middleware.rs index 13ec57a4af39..ff372feabd15 100644 --- a/packages/next-swc/crates/next-core/src/middleware.rs +++ b/packages/next-swc/crates/next-core/src/middleware.rs @@ -1,13 +1,12 @@ use anyhow::Result; use indexmap::indexmap; use turbo_tasks::{Value, Vc}; -use turbo_tasks_fs::{File, FileSystemPath}; +use turbo_tasks_fs::FileSystemPath; use turbopack_binding::turbopack::core::{ - asset::AssetContent, context::AssetContext, module::Module, reference_type::ReferenceType, - virtual_source::VirtualSource, + context::AssetContext, module::Module, reference_type::ReferenceType, }; -use crate::util::{load_next_js_template, virtual_next_js_template_path}; +use crate::util::load_next_js_template; #[turbo_tasks::function] pub async fn middleware_files(page_extensions: Vc>) -> Result>> { @@ -29,23 +28,25 @@ pub async fn get_middleware_module( project_root: Vc, userland_module: Vc>, ) -> Result>> { - let template_file = "middleware.js"; + const INNER: &str = "INNER_MIDDLEWARE_MODULE"; // Load the file from the next.js codebase. - let file = load_next_js_template(project_root, template_file.to_string()).await?; - - let file = File::from(file.clone_value()); - - let template_path = virtual_next_js_template_path(project_root, template_file.to_string()); - - let virtual_source = VirtualSource::new(template_path, AssetContent::file(file.into())); + let source = load_next_js_template( + "middleware.js", + project_root, + indexmap! { + "VAR_USERLAND" => INNER.to_string(), + }, + indexmap! {}, + ) + .await?; let inner_assets = indexmap! { - "VAR_USERLAND".to_string() => userland_module + INNER.to_string() => userland_module }; let module = context.process( - Vc::upcast(virtual_source), + source, Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), ); diff --git a/packages/next-swc/crates/next-core/src/next_app/app_client_references_chunks.rs b/packages/next-swc/crates/next-core/src/next_app/app_client_references_chunks.rs index 554b11e92e40..83ba23239b68 100644 --- a/packages/next-swc/crates/next-core/src/next_app/app_client_references_chunks.rs +++ b/packages/next-swc/crates/next-core/src/next_app/app_client_references_chunks.rs @@ -4,10 +4,7 @@ use serde::{Deserialize, Serialize}; use turbo_tasks::{debug::ValueDebugFormat, trace::TraceRawVcs, TryJoinIterExt, Vc}; use turbopack_binding::turbopack::{ build::BuildChunkingContext, - core::{ - chunk::{ChunkableModule, ChunkingContext}, - output::OutputAssets, - }, + core::{chunk::ChunkingContextExt, output::OutputAssets}, ecmascript::chunk::EcmascriptChunkingContext, }; @@ -46,24 +43,21 @@ pub async fn get_app_client_references_chunks( match client_reference_ty { ClientReferenceType::EcmascriptClientReference(ecmascript_client_reference) => { let ecmascript_client_reference_ref = ecmascript_client_reference.await?; - let client_entry_chunk = ecmascript_client_reference_ref - .client_module - .as_root_chunk(Vc::upcast(client_chunking_context)); - let ssr_entry_chunk = ecmascript_client_reference_ref - .ssr_module - .as_root_chunk(Vc::upcast(ssr_chunking_context)); ClientReferenceChunks { - client_chunks: client_chunking_context.chunk_group(client_entry_chunk), - ssr_chunks: ssr_chunking_context.chunk_group(ssr_entry_chunk), + client_chunks: client_chunking_context.root_chunk_group(Vc::upcast( + ecmascript_client_reference_ref.client_module, + )), + ssr_chunks: ssr_chunking_context.root_chunk_group(Vc::upcast( + ecmascript_client_reference_ref.ssr_module, + )), } } ClientReferenceType::CssClientReference(css_client_reference) => { let css_client_reference_ref = css_client_reference.await?; - let client_entry_chunk = css_client_reference_ref - .client_module - .as_root_chunk(Vc::upcast(client_chunking_context)); ClientReferenceChunks { - client_chunks: client_chunking_context.chunk_group(client_entry_chunk), + client_chunks: client_chunking_context.root_chunk_group(Vc::upcast( + css_client_reference_ref.client_module, + )), ssr_chunks: OutputAssets::empty(), } } diff --git a/packages/next-swc/crates/next-core/src/next_app/app_client_shared_chunks.rs b/packages/next-swc/crates/next-core/src/next_app/app_client_shared_chunks.rs index cedcd7a506a6..e7e288181690 100644 --- a/packages/next-swc/crates/next-core/src/next_app/app_client_shared_chunks.rs +++ b/packages/next-swc/crates/next-core/src/next_app/app_client_shared_chunks.rs @@ -1,41 +1,17 @@ use anyhow::Result; -use turbo_tasks::{TryJoinIterExt, Value, Vc}; +use turbo_tasks::Vc; use turbopack_binding::turbopack::{ core::{ - chunk::{availability_info::AvailabilityInfo, ChunkingContext, EvaluatableAssets}, + chunk::{ChunkingContext, EvaluatableAssets}, + ident::AssetIdent, output::OutputAssets, }, - ecmascript::chunk::{EcmascriptChunk, EcmascriptChunkPlaceable, EcmascriptChunkingContext}, + ecmascript::chunk::EcmascriptChunkingContext, }; -#[turbo_tasks::function] -pub async fn get_app_shared_client_chunk( - app_client_runtime_entries: Vc, - client_chunking_context: Vc>, -) -> Result> { - let client_runtime_entries: Vec<_> = app_client_runtime_entries - .await? - .iter() - .map(|entry| async move { - Ok(Vc::try_resolve_sidecast::>(*entry).await?) - }) - .try_join() - .await? - .into_iter() - .flatten() - .collect(); - - Ok(EcmascriptChunk::new_normalized( - client_chunking_context, - // TODO(alexkirsz) Should this accept Evaluatable instead? - Vc::cell(client_runtime_entries), - None, - Value::new(AvailabilityInfo::Untracked), - )) -} - #[turbo_tasks::function] pub async fn get_app_client_shared_chunks( + ident: Vc, app_client_runtime_entries: Vc, client_chunking_context: Vc>, ) -> Result> { @@ -43,13 +19,8 @@ pub async fn get_app_client_shared_chunks( return Ok(OutputAssets::empty()); } - let app_client_shared_chunk = - get_app_shared_client_chunk(app_client_runtime_entries, client_chunking_context); - - let app_client_shared_chunks = client_chunking_context.evaluated_chunk_group( - Vc::upcast(app_client_shared_chunk), - app_client_runtime_entries, - ); + let app_client_shared_chunks = + client_chunking_context.evaluated_chunk_group(ident, app_client_runtime_entries); Ok(app_client_shared_chunks) } diff --git a/packages/next-swc/crates/next-core/src/next_app/app_page_entry.rs b/packages/next-swc/crates/next-core/src/next_app/app_page_entry.rs index 1b50862bc0d6..d6d16e7dde62 100644 --- a/packages/next-swc/crates/next-core/src/next_app/app_page_entry.rs +++ b/packages/next-swc/crates/next-core/src/next_app/app_page_entry.rs @@ -1,12 +1,16 @@ use std::io::Write; use anyhow::{bail, Result}; +use indexmap::indexmap; use turbo_tasks::{TryJoinIterExt, Value, ValueToString, Vc}; use turbopack_binding::{ turbo::tasks_fs::{rope::RopeBuilder, File, FileSystemPath}, turbopack::{ core::{ - asset::AssetContent, context::AssetContext, reference_type::ReferenceType, + asset::{Asset, AssetContent}, + context::AssetContext, + reference_type::ReferenceType, + source::Source, virtual_source::VirtualSource, }, ecmascript::{chunk::EcmascriptChunkPlaceable, utils::StringifyJs}, @@ -22,7 +26,7 @@ use crate::{ next_app::{AppPage, AppPath}, next_server_component::NextServerComponentTransition, parse_segment_config_from_loader_tree, - util::{load_next_js_template, virtual_next_js_template_path, NextRuntime}, + util::{file_content_rope, load_next_js_template, NextRuntime}, }; /// Computes the entry for a Next.js app page. @@ -70,59 +74,32 @@ pub async fn get_app_page_entry( let original_name = page.to_string(); let pathname = AppPath::from(page.clone()).to_string(); - let template_file = "app-page.js"; - // Load the file from the next.js codebase. - let file = load_next_js_template(project_root, template_file.to_string()).await?; - - let mut file = file - .to_str()? - .replace( - "\"VAR_DEFINITION_PAGE\"", - &StringifyJs(&page.to_string()).to_string(), - ) - .replace( - "\"VAR_DEFINITION_PATHNAME\"", - &StringifyJs(&pathname).to_string(), - ) - .replace( - "\"VAR_ORIGINAL_PATHNAME\"", - &StringifyJs(&original_name).to_string(), - ) - // TODO(alexkirsz) Support custom global error. - .replace( - "\"VAR_MODULE_GLOBAL_ERROR\"", - &StringifyJs("next/dist/client/components/error-boundary").to_string(), - ) - .replace( - "// INJECT:tree", - format!("const tree = {};", loader_tree_code).as_str(), - ) - .replace( - "// INJECT:pages", - format!("const pages = {};", StringifyJs(&pages)).as_str(), - ) - .replace( - "// INJECT:__next_app_require__", - "const __next_app_require__ = __turbopack_require__", - ) - .replace( - "// INJECT:__next_app_load_chunk__", - "const __next_app_load_chunk__ = __turbopack_load__", - ); - - // Ensure that the last line is a newline. - if !file.ends_with('\n') { - file.push('\n'); - } - - result.push_bytes(file.as_bytes()); + let source = load_next_js_template( + "app-page.js", + project_root, + indexmap! { + "VAR_DEFINITION_PAGE" => page.to_string(), + "VAR_DEFINITION_PATHNAME" => pathname.clone(), + "VAR_ORIGINAL_PATHNAME" => original_name.clone(), + // TODO(alexkirsz) Support custom global error. + "VAR_MODULE_GLOBAL_ERROR" => "next/dist/client/components/error-boundary".to_string(), + }, + indexmap! { + "tree" => loader_tree_code, + "pages" => StringifyJs(&pages).to_string(), + "__next_app_require__" => "__turbopack_require__".to_string(), + "__next_app_load_chunk__" => " __turbopack_load__".to_string(), + }, + ) + .await?; - let file = File::from(result.build()); + let source_content = &*file_content_rope(source.content().file_content()).await?; - let template_path = virtual_next_js_template_path(project_root, template_file.to_string()); + result.concat(source_content); - let source = VirtualSource::new(template_path, AssetContent::file(file.into())); + let file = File::from(result.build()); + let source = VirtualSource::new(source.ident().path(), AssetContent::file(file.into())); let rsc_entry = context.process( Vc::upcast(source), @@ -140,7 +117,7 @@ pub async fn get_app_page_entry( }; Ok(AppEntry { - pathname: pathname.to_string(), + pathname, original_name, rsc_entry, config, diff --git a/packages/next-swc/crates/next-core/src/next_app/app_route_entry.rs b/packages/next-swc/crates/next-core/src/next_app/app_route_entry.rs index 014328c97f30..c2d682179834 100644 --- a/packages/next-swc/crates/next-core/src/next_app/app_route_entry.rs +++ b/packages/next-swc/crates/next-core/src/next_app/app_route_entry.rs @@ -23,7 +23,7 @@ use turbopack_binding::{ use crate::{ next_app::{AppEntry, AppPage, AppPath}, parse_segment_config_from_source, - util::{load_next_js_template, virtual_next_js_template_path, NextRuntime}, + util::{load_next_js_template, NextRuntime}, }; /// Computes the entry for a Next.js app route. @@ -49,62 +49,32 @@ pub async fn get_app_route_entry( nodejs_context }; - let mut result = RopeBuilder::default(); - let original_name = page.to_string(); let pathname = AppPath::from(page.clone()).to_string(); let path = source.ident().path(); - let template_file = "app-route.js"; + const INNER: &str = "INNER_APP_ROUTE"; // Load the file from the next.js codebase. - let file = load_next_js_template(project_root, template_file.to_string()).await?; - - let mut file = file - .to_str()? - .replace( - "\"VAR_DEFINITION_PAGE\"", - &StringifyJs(&original_name).to_string(), - ) - .replace( - "\"VAR_DEFINITION_PATHNAME\"", - &StringifyJs(&pathname).to_string(), - ) - .replace( - "\"VAR_DEFINITION_FILENAME\"", - &StringifyJs(&path.file_stem().await?.as_ref().unwrap().clone()).to_string(), - ) - // TODO(alexkirsz) Is this necessary? - .replace( - "\"VAR_DEFINITION_BUNDLE_PATH\"", - &StringifyJs("").to_string(), - ) - .replace( - "\"VAR_ORIGINAL_PATHNAME\"", - &StringifyJs(&original_name).to_string(), - ) - .replace( - "\"VAR_RESOLVED_PAGE_PATH\"", - &StringifyJs(&path.to_string().await?).to_string(), - ) - .replace( - "// INJECT:nextConfigOutput", - "const nextConfigOutput = \"\"", - ); - - // Ensure that the last line is a newline. - if !file.ends_with('\n') { - file.push('\n'); - } - - result.push_bytes(file.as_bytes()); - - let file = File::from(result.build()); - - let template_path = virtual_next_js_template_path(project_root, template_file.to_string()); - - let virtual_source = VirtualSource::new(template_path, AssetContent::file(file.into())); + let virtual_source = load_next_js_template( + "app-route.js", + project_root, + indexmap! { + "VAR_DEFINITION_PAGE" => page.to_string(), + "VAR_DEFINITION_PATHNAME" => pathname.clone(), + "VAR_DEFINITION_FILENAME" => path.file_stem().await?.as_ref().unwrap().clone(), + // TODO(alexkirsz) Is this necessary? + "VAR_DEFINITION_BUNDLE_PATH" => "".to_string(), + "VAR_ORIGINAL_PATHNAME" => original_name.clone(), + "VAR_RESOLVED_PAGE_PATH" => path.to_string().await?.clone_value(), + "VAR_USERLAND" => INNER.to_string(), + }, + indexmap! { + "nextConfigOutput" => "\"\"".to_string(), + }, + ) + .await?; let userland_module = context.process( source, @@ -112,7 +82,7 @@ pub async fn get_app_route_entry( ); let inner_assets = indexmap! { - "VAR_USERLAND".to_string() => userland_module + INNER.to_string() => userland_module }; let mut rsc_entry = context.process( diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index fe3b43aaf156..08069da234d6 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -19,7 +19,6 @@ use turbopack_binding::{ }, dev::{react_refresh::assert_can_resolve_react_refresh, DevChunkingContext}, ecmascript::chunk::EcmascriptChunkingContext, - ecmascript_plugin::transform::directives::server::ServerDirectiveTransformer, node::execution_context::ExecutionContext, turbopack::{ condition::ContextCondition, @@ -232,11 +231,6 @@ pub async fn get_client_module_options_context( *get_emotion_transform_plugin(next_config).await?, *get_styled_components_transform_plugin(next_config).await?, *get_styled_jsx_transform_plugin().await?, - Some(Vc::cell(Box::new(ServerDirectiveTransformer::new( - // ServerDirective is not implemented yet and always reports an issue. - // We don't have to pass a valid transition name yet, but the API is prepared. - &Vc::cell("TODO".to_string()), - )) as _)), ] .into_iter() .flatten() diff --git a/packages/next-swc/crates/next-core/src/next_client_component/with_chunking_context_scope_asset.rs b/packages/next-swc/crates/next-core/src/next_client_component/with_chunking_context_scope_asset.rs index f8cede2ba285..694db16ba4d1 100644 --- a/packages/next-swc/crates/next-core/src/next_client_component/with_chunking_context_scope_asset.rs +++ b/packages/next-swc/crates/next-core/src/next_client_component/with_chunking_context_scope_asset.rs @@ -1,17 +1,13 @@ -use anyhow::{Context, Result}; -use turbo_tasks::{Value, Vc}; +use turbo_tasks::Vc; use turbopack_binding::turbopack::{ core::{ asset::{Asset, AssetContent}, - chunk::{availability_info::AvailabilityInfo, Chunk, ChunkableModule, ChunkingContext}, + chunk::{ChunkableModule, ChunkingContext}, ident::AssetIdent, module::Module, reference::ModuleReferences, }, - ecmascript::chunk::EcmascriptChunkingContext, - turbopack::ecmascript::chunk::{ - EcmascriptChunk, EcmascriptChunkItem, EcmascriptChunkPlaceable, EcmascriptExports, - }, + turbopack::ecmascript::chunk::{EcmascriptChunkPlaceable, EcmascriptExports}, }; #[turbo_tasks::function] @@ -49,38 +45,19 @@ impl Asset for WithChunkingContextScopeAsset { #[turbo_tasks::value_impl] impl ChunkableModule for WithChunkingContextScopeAsset { #[turbo_tasks::function] - fn as_chunk( + fn as_chunk_item( &self, - context: Vc>, - availability_info: Value, - ) -> Vc> { - Vc::upcast(EcmascriptChunk::new( - context.with_layer(self.layer.clone()), + chunking_context: Vc>, + ) -> Vc> { + Vc::upcast(ChunkableModule::as_chunk_item( self.asset, - availability_info, + chunking_context.with_layer(self.layer.clone()), )) } } #[turbo_tasks::value_impl] impl EcmascriptChunkPlaceable for WithChunkingContextScopeAsset { - #[turbo_tasks::function] - async fn as_chunk_item( - &self, - context: Vc>, - ) -> Result>> { - Ok(self.asset.as_chunk_item( - Vc::try_resolve_sidecast::>( - context.with_layer(self.layer.clone()), - ) - .await? - .context( - "ChunkingContext::with_layer should not return a different kind of chunking \ - context", - )?, - )) - } - #[turbo_tasks::function] fn get_exports(&self) -> Vc { self.asset.get_exports() diff --git a/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs b/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs index 87779c061e8b..9674a55f8374 100644 --- a/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs +++ b/packages/next-swc/crates/next-core/src/next_client_component/with_client_chunks.rs @@ -7,9 +7,9 @@ use turbopack_binding::{ core::{ asset::{Asset, AssetContent}, chunk::{ - availability_info::AvailabilityInfo, Chunk, ChunkData, ChunkItem, ChunkableModule, - ChunkableModuleReference, ChunkingContext, ChunkingType, ChunkingTypeOption, - ChunksData, + availability_info::AvailabilityInfo, Chunk, ChunkData, ChunkItem, ChunkItemExt, + ChunkableModule, ChunkableModuleReference, ChunkingContext, ChunkingContextExt, + ChunkingType, ChunkingTypeOption, ChunksData, }, ident::AssetIdent, module::Module, @@ -18,7 +18,7 @@ use turbopack_binding::{ reference::{ModuleReference, ModuleReferences, SingleOutputAssetReference}, resolve::ModuleResolveResult, }, - ecmascript::chunk::{EcmascriptChunkData, EcmascriptChunkItemExt}, + ecmascript::chunk::EcmascriptChunkData, turbopack::ecmascript::{ chunk::{ EcmascriptChunk, EcmascriptChunkItem, EcmascriptChunkItemContent, @@ -68,43 +68,30 @@ impl Asset for WithClientChunksAsset { #[turbo_tasks::value_impl] impl ChunkableModule for WithClientChunksAsset { - #[turbo_tasks::function] - fn as_chunk( - self: Vc, - context: Vc>, - availability_info: Value, - ) -> Vc> { - Vc::upcast(EcmascriptChunk::new( - context.with_layer("rsc".to_string()), - Vc::upcast(self), - availability_info, - )) - } -} - -#[turbo_tasks::value_impl] -impl EcmascriptChunkPlaceable for WithClientChunksAsset { #[turbo_tasks::function] async fn as_chunk_item( self: Vc, - context: Vc>, - ) -> Result>> { + chunking_context: Vc>, + ) -> Result>> { + let context = Vc::try_resolve_sidecast::>( + chunking_context.with_layer("rsc".to_string()), + ) + .await? + .context( + "ChunkingContext::with_layer should not return a different kind of chunking context", + )?; Ok(Vc::upcast( WithClientChunksChunkItem { - context: Vc::try_resolve_sidecast::>( - context.with_layer("rsc".to_string()), - ) - .await? - .context( - "ChunkingContext::with_layer should not return a different kind of chunking \ - context", - )?, + context, inner: self, } .cell(), )) } +} +#[turbo_tasks::value_impl] +impl EcmascriptChunkPlaceable for WithClientChunksAsset { #[turbo_tasks::function] fn get_exports(&self) -> Vc { // TODO This should be EsmExports @@ -124,9 +111,7 @@ impl WithClientChunksChunkItem { async fn chunks(self: Vc) -> Result> { let this = self.await?; let inner = this.inner.await?; - Ok(this - .context - .chunk_group(inner.asset.as_root_chunk(Vc::upcast(this.context)))) + Ok(this.context.root_chunk_group(Vc::upcast(inner.asset))) } #[turbo_tasks::function] @@ -183,7 +168,11 @@ impl EcmascriptChunkItem for WithClientChunksChunkItem { .map(|chunk_data| EcmascriptChunkData::new(chunk_data)) .collect(); - let module_id = inner.asset.as_chunk_item(this.context).id().await?; + let module_id = inner + .asset + .as_chunk_item(Vc::upcast(this.context)) + .id() + .await?; Ok(EcmascriptChunkItemContent { inner_code: formatdoc!( // We store the chunks in a binding, otherwise a new array would be created every @@ -243,6 +232,20 @@ impl ChunkItem for WithClientChunksChunkItem { } Ok(Vc::cell(references)) } + + #[turbo_tasks::function] + async fn chunking_context(&self) -> Vc> { + Vc::upcast(self.context) + } + + #[turbo_tasks::function] + fn as_chunk(&self, availability_info: Value) -> Vc> { + Vc::upcast(EcmascriptChunk::new( + Vc::upcast(self.context.with_layer("rsc".to_string())), + Vc::upcast(self.inner), + availability_info, + )) + } } #[turbo_tasks::value] diff --git a/packages/next-swc/crates/next-core/src/next_client_reference/ecmascript_client_reference/ecmascript_client_reference_proxy_module.rs b/packages/next-swc/crates/next-core/src/next_client_reference/ecmascript_client_reference/ecmascript_client_reference_proxy_module.rs index b4adf43c325e..fe3c06999ff3 100644 --- a/packages/next-swc/crates/next-core/src/next_client_reference/ecmascript_client_reference/ecmascript_client_reference_proxy_module.rs +++ b/packages/next-swc/crates/next-core/src/next_client_reference/ecmascript_client_reference/ecmascript_client_reference_proxy_module.rs @@ -1,6 +1,6 @@ use std::{io::Write, iter::once}; -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; use indoc::writedoc; use turbo_tasks::{Value, ValueToString, Vc}; use turbo_tasks_fs::File; @@ -85,7 +85,7 @@ impl EcmascriptClientReferenceProxyModule { // and the $$typeof value is for rendering logic to determine if the module // is a client boundary. const {{ __esModule, $$typeof }} = proxy; - + export {{ __esModule, $$typeof }}; export default proxy; "#, @@ -164,36 +164,35 @@ impl Asset for EcmascriptClientReferenceProxyModule { #[turbo_tasks::value_impl] impl ChunkableModule for EcmascriptClientReferenceProxyModule { #[turbo_tasks::function] - fn as_chunk( + async fn as_chunk_item( self: Vc, - context: Vc>, - availability_info: Value, - ) -> Vc> { - Vc::upcast(EcmascriptChunk::new( - context, - Vc::upcast(self), - availability_info, - )) - } -} + chunking_context: Vc>, + ) -> Result>> { + let item = self.proxy_module().as_chunk_item(chunking_context); + let ecmascript_item = Vc::try_resolve_downcast::>(item) + .await? + .context("EcmascriptModuleAsset must implement EcmascriptChunkItem")?; + let chunking_context = + Vc::try_resolve_downcast::>(chunking_context) + .await? + .context( + "chunking context must impl EcmascriptChunkingContext to use \ + EcmascriptClientReferenceProxyModule", + )?; -#[turbo_tasks::value_impl] -impl EcmascriptChunkPlaceable for EcmascriptClientReferenceProxyModule { - #[turbo_tasks::function] - fn as_chunk_item( - self: Vc, - chunking_context: Vc>, - ) -> Vc> { - Vc::upcast( + Ok(Vc::upcast( ProxyModuleChunkItem { client_proxy_asset: self, - inner_proxy_module_chunk_item: self.proxy_module().as_chunk_item(chunking_context), + inner_proxy_module_chunk_item: ecmascript_item, chunking_context, } .cell(), - ) + )) } +} +#[turbo_tasks::value_impl] +impl EcmascriptChunkPlaceable for EcmascriptClientReferenceProxyModule { #[turbo_tasks::function] fn get_exports(self: Vc) -> Vc { self.proxy_module().get_exports() @@ -232,6 +231,20 @@ impl ChunkItem for ProxyModuleChunkItem { fn references(&self) -> Vc { self.client_proxy_asset.references() } + + #[turbo_tasks::function] + async fn chunking_context(&self) -> Vc> { + Vc::upcast(self.chunking_context) + } + + #[turbo_tasks::function] + fn as_chunk(&self, availability_info: Value) -> Vc> { + Vc::upcast(EcmascriptChunk::new( + Vc::upcast(self.chunking_context), + Vc::upcast(self.client_proxy_asset), + availability_info, + )) + } } #[turbo_tasks::value_impl] @@ -252,6 +265,6 @@ impl EcmascriptChunkItem for ProxyModuleChunkItem { #[turbo_tasks::function] fn chunking_context(&self) -> Vc> { - self.inner_proxy_module_chunk_item.chunking_context() + EcmascriptChunkItem::chunking_context(self.inner_proxy_module_chunk_item) } } diff --git a/packages/next-swc/crates/next-core/src/next_dynamic/dynamic_module.rs b/packages/next-swc/crates/next-core/src/next_dynamic/dynamic_module.rs index b4fe032aa82d..8e20f4c4dabf 100644 --- a/packages/next-swc/crates/next-core/src/next_dynamic/dynamic_module.rs +++ b/packages/next-swc/crates/next-core/src/next_dynamic/dynamic_module.rs @@ -2,7 +2,7 @@ use anyhow::{bail, Result}; use turbo_tasks::Vc; use turbopack_binding::turbopack::core::{ asset::{Asset, AssetContent}, - chunk::{ChunkableModule, ChunkingContext}, + chunk::{ChunkableModule, ChunkingContext, ChunkingContextExt}, ident::AssetIdent, module::Module, output::OutputAssets, @@ -41,8 +41,7 @@ impl NextDynamicEntryModule { bail!("dynamic client asset must be chunkable"); }; - let client_entry_chunk = client_entry_module.as_root_chunk(client_chunking_context); - Ok(client_chunking_context.chunk_group(client_entry_chunk)) + Ok(client_chunking_context.root_chunk_group(client_entry_module)) } } diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index cec565798086..3d0f2b788b67 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -280,6 +280,20 @@ pub async fn get_next_server_import_map( "next/dist/build/webpack/loaders/next-flight-loader/action-proxy", ), ); + import_map.insert_exact_alias( + "private-next-rsc-action-client-wrapper", + request_to_import_mapping( + project_path, + "next/dist/build/webpack/loaders/next-flight-loader/action-client-wrapper", + ), + ); + import_map.insert_exact_alias( + "private-next-rsc-action-validate", + request_to_import_mapping( + project_path, + "next/dist/build/webpack/loaders/next-flight-loader/action-validate", + ), + ); import_map.insert_exact_alias( "next/head", request_to_import_mapping(project_path, "next/dist/client/components/noop-head"), diff --git a/packages/next-swc/crates/next-core/src/next_manifests/client_reference_manifest.rs b/packages/next-swc/crates/next-core/src/next_manifests/client_reference_manifest.rs index 527f588da1c3..f99625cec5e2 100644 --- a/packages/next-swc/crates/next-core/src/next_manifests/client_reference_manifest.rs +++ b/packages/next-swc/crates/next-core/src/next_manifests/client_reference_manifest.rs @@ -4,13 +4,12 @@ use turbo_tasks::{TryJoinIterExt, ValueToString, Vc}; use turbo_tasks_fs::{File, FileSystemPath}; use turbopack_binding::turbopack::{ core::{ - asset::AssetContent, chunk::ModuleId as TurbopackModuleId, output::OutputAsset, + asset::AssetContent, + chunk::{ChunkItemExt, ChunkableModule, ModuleId as TurbopackModuleId}, + output::OutputAsset, virtual_output::VirtualOutputAsset, }, - ecmascript::{ - chunk::{EcmascriptChunkItemExt, EcmascriptChunkPlaceable, EcmascriptChunkingContext}, - utils::StringifyJs, - }, + ecmascript::{chunk::EcmascriptChunkingContext, utils::StringifyJs}, }; use super::{ClientReferenceManifest, ManifestNode, ManifestNodeEntry, ModuleId}; @@ -117,12 +116,12 @@ impl ClientReferenceManifest { let client_module_id = ecmascript_client_reference .client_module - .as_chunk_item(client_chunking_context) + .as_chunk_item(Vc::upcast(client_chunking_context)) .id() .await?; let ssr_module_id = ecmascript_client_reference .ssr_module - .as_chunk_item(ssr_chunking_context) + .as_chunk_item(Vc::upcast(ssr_chunking_context)) .id() .await?; diff --git a/packages/next-swc/crates/next-core/src/next_pages/page_entry.rs b/packages/next-swc/crates/next-core/src/next_pages/page_entry.rs index c05121a79c98..ac48b95e239c 100644 --- a/packages/next-swc/crates/next-core/src/next_pages/page_entry.rs +++ b/packages/next-swc/crates/next-core/src/next_pages/page_entry.rs @@ -11,19 +11,19 @@ use turbopack_binding::{ }, turbopack::{ core::{ - asset::AssetContent, + asset::{Asset, AssetContent}, context::AssetContext, reference_type::{EntryReferenceSubType, ReferenceType}, source::Source, virtual_source::VirtualSource, }, - ecmascript::{chunk::EcmascriptChunkPlaceable, utils::StringifyJs}, + ecmascript::chunk::EcmascriptChunkPlaceable, }, }; use crate::{ next_edge::entry::wrap_edge_entry, - util::{load_next_js_template, virtual_next_js_template_path, NextRuntime}, + util::{file_content_rope, load_next_js_template, NextRuntime}, }; #[turbo_tasks::function] @@ -36,8 +36,8 @@ pub async fn create_page_ssr_entry_module( next_original_name: Vc, runtime: NextRuntime, ) -> Result>> { - let definition_page = next_original_name.await?; - let definition_pathname = pathname.await?; + let definition_page = &*next_original_name.await?; + let definition_pathname = &*pathname.await?; let ssr_module = ssr_module_context.process(source, reference_type.clone()); @@ -59,64 +59,57 @@ pub async fn create_page_ssr_entry_module( _ => bail!("Invalid path type"), }; - // Load the file from the next.js codebase. - let file = load_next_js_template(project_root, template_file.to_string()).await?; - - let mut file = file - .to_str()? - .replace( - "\"VAR_DEFINITION_PAGE\"", - &StringifyJs(&definition_page).to_string(), - ) - .replace( - "\"VAR_DEFINITION_PATHNAME\"", - &StringifyJs(&definition_pathname).to_string(), - ); - - if reference_type == ReferenceType::Entry(EntryReferenceSubType::Page) { - file = file - .replace( - "\"VAR_MODULE_DOCUMENT\"", - &StringifyJs("@vercel/turbopack-next/pages/_document").to_string(), - ) - .replace( - "\"VAR_MODULE_APP\"", - &StringifyJs("@vercel/turbopack-next/pages/_app").to_string(), - ); - } - - // Ensure that the last line is a newline. - if !file.ends_with('\n') { - file.push('\n'); - } + const INNER: &str = "INNER_PAGE"; - let mut result = RopeBuilder::default(); - result.push_bytes(file.as_bytes()); + let mut replacements = indexmap! { + "VAR_DEFINITION_PAGE" => definition_page.clone(), + "VAR_DEFINITION_PATHNAME" => definition_pathname.clone(), + "VAR_USERLAND" => INNER.to_string(), + }; if reference_type == ReferenceType::Entry(EntryReferenceSubType::Page) { - // When we're building the instrumentation page (only when the - // instrumentation file conflicts with a page also labeled - // /instrumentation) hoist the `register` method. - if definition_page.to_string() == "/instrumentation" - || definition_page.to_string() == "/src/instrumentation" - { - writeln!( - result, - r#"export const register = hoist(userland, "register")"# - )?; - } + replacements.insert( + "VAR_MODULE_DOCUMENT", + "@vercel/turbopack-next/pages/_document".to_string(), + ); + replacements.insert( + "VAR_MODULE_APP", + "@vercel/turbopack-next/pages/_app".to_string(), + ); } - let file = File::from(result.build()); - - let template_path = virtual_next_js_template_path(project_root, template_file.to_string()); - - let source = VirtualSource::new(template_path, AssetContent::file(file.into())); + // Load the file from the next.js codebase. + let mut source = + load_next_js_template(template_file, project_root, replacements, indexmap! {}).await?; + + // When we're building the instrumentation page (only when the + // instrumentation file conflicts with a page also labeled + // /instrumentation) hoist the `register` method. + if reference_type == ReferenceType::Entry(EntryReferenceSubType::Page) + && (*definition_page == "/instrumentation" || *definition_page == "/src/instrumentation") + { + let file = &*file_content_rope(source.content().file_content()).await?; + + let mut result = RopeBuilder::default(); + result += file; + + writeln!( + result, + r#"export const register = hoist(userland, "register")"# + )?; + + let file = File::from(result.build()); + + source = Vc::upcast(VirtualSource::new( + source.ident().path(), + AssetContent::file(file.into()), + )); + } let mut ssr_module = ssr_module_context.process( - Vc::upcast(source), + source, Value::new(ReferenceType::Internal(Vc::cell(indexmap! { - "VAR_USERLAND".to_string() => ssr_module, + INNER.to_string() => ssr_module, }))), ); diff --git a/packages/next-swc/crates/next-core/src/next_server/context.rs b/packages/next-swc/crates/next-core/src/next_server/context.rs index d789721362c5..02f64a86c574 100644 --- a/packages/next-swc/crates/next-core/src/next_server/context.rs +++ b/packages/next-swc/crates/next-core/src/next_server/context.rs @@ -19,9 +19,7 @@ use turbopack_binding::{ resolve::{parse::Request, pattern::Pattern}, }, ecmascript::TransformPlugin, - ecmascript_plugin::transform::directives::{ - client::ClientDirectiveTransformer, server::ServerDirectiveTransformer, - }, + ecmascript_plugin::transform::directives::client::ClientDirectiveTransformer, node::execution_context::ExecutionContext, turbopack::{ condition::ContextCondition, @@ -276,12 +274,6 @@ pub async fn get_server_module_options_context( let styled_components_transform_plugin = *get_styled_components_transform_plugin(next_config).await?; let styled_jsx_transform_plugin = *get_styled_jsx_transform_plugin().await?; - let server_directive_transform_plugin = - Some(Vc::cell(Box::new(ServerDirectiveTransformer::new( - // ServerDirective is not implemented yet and always reports an issue. - // We don't have to pass a valid transition name yet, but the API is prepared. - &Vc::cell("TODO".to_string()), - )) as _)); // ModuleOptionsContext related options let tsconfig = get_typescript_transform_options(project_path); @@ -374,7 +366,6 @@ pub async fn get_server_module_options_context( let mut base_source_transforms: Vec> = vec![ styled_components_transform_plugin, styled_jsx_transform_plugin, - server_directive_transform_plugin, ] .into_iter() .flatten() @@ -433,13 +424,11 @@ pub async fn get_server_module_options_context( ecmascript_client_reference_transition_name, .. } => { - let mut base_source_transforms: Vec> = vec![ - styled_components_transform_plugin, - server_directive_transform_plugin, - ] - .into_iter() - .flatten() - .collect(); + let mut base_source_transforms: Vec> = + vec![styled_components_transform_plugin] + .into_iter() + .flatten() + .collect(); if let Some(ecmascript_client_reference_transition_name) = ecmascript_client_reference_transition_name diff --git a/packages/next-swc/crates/next-core/src/next_server_component/server_component_module.rs b/packages/next-swc/crates/next-core/src/next_server_component/server_component_module.rs index f5253735faa9..bd89ee608195 100644 --- a/packages/next-swc/crates/next-core/src/next_server_component/server_component_module.rs +++ b/packages/next-swc/crates/next-core/src/next_server_component/server_component_module.rs @@ -1,4 +1,4 @@ -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; use indoc::formatdoc; use turbo_tasks::{Value, Vc}; use turbo_tasks_fs::FileSystemPath; @@ -6,13 +6,13 @@ use turbopack_binding::turbopack::{ core::{ asset::{Asset, AssetContent}, chunk::{ - availability_info::AvailabilityInfo, Chunk, ChunkItem, ChunkableModule, ChunkingContext, + availability_info::AvailabilityInfo, Chunk, ChunkItem, ChunkItemExt, ChunkableModule, + ChunkingContext, }, ident::AssetIdent, module::Module, reference::ModuleReferences, }, - ecmascript::chunk::EcmascriptChunkItemExt, turbopack::ecmascript::{ chunk::{ EcmascriptChunk, EcmascriptChunkItem, EcmascriptChunkItemContent, @@ -73,27 +73,18 @@ impl Asset for NextServerComponentModule { #[turbo_tasks::value_impl] impl ChunkableModule for NextServerComponentModule { - #[turbo_tasks::function] - fn as_chunk( - self: Vc, - context: Vc>, - availability_info: Value, - ) -> Vc> { - Vc::upcast(EcmascriptChunk::new( - context, - Vc::upcast(self), - availability_info, - )) - } -} - -#[turbo_tasks::value_impl] -impl EcmascriptChunkPlaceable for NextServerComponentModule { #[turbo_tasks::function] async fn as_chunk_item( self: Vc, - context: Vc>, - ) -> Result>> { + chunking_context: Vc>, + ) -> Result>> { + let context = + Vc::try_resolve_downcast::>(chunking_context) + .await? + .context( + "chunking context must impl EcmascriptChunkingContext to use \ + NextServerComponentModule", + )?; Ok(Vc::upcast( BuildServerComponentChunkItem { context, @@ -102,7 +93,10 @@ impl EcmascriptChunkPlaceable for NextServerComponentModule { .cell(), )) } +} +#[turbo_tasks::value_impl] +impl EcmascriptChunkPlaceable for NextServerComponentModule { #[turbo_tasks::function] fn get_exports(&self) -> Vc { // TODO This should be EsmExports @@ -128,7 +122,11 @@ impl EcmascriptChunkItem for BuildServerComponentChunkItem { let this = self.await?; let inner = this.inner.await?; - let module_id = inner.module.as_chunk_item(this.context).id().await?; + let module_id = inner + .module + .as_chunk_item(Vc::upcast(this.context)) + .id() + .await?; Ok(EcmascriptChunkItemContent { inner_code: formatdoc!( r#" @@ -156,4 +154,18 @@ impl ChunkItem for BuildServerComponentChunkItem { fn references(&self) -> Vc { self.inner.references() } + + #[turbo_tasks::function] + async fn chunking_context(&self) -> Vc> { + Vc::upcast(self.context) + } + + #[turbo_tasks::function] + fn as_chunk(&self, availability_info: Value) -> Vc> { + Vc::upcast(EcmascriptChunk::new( + Vc::upcast(self.context), + Vc::upcast(self.inner), + availability_info, + )) + } } diff --git a/packages/next-swc/crates/next-core/src/page_loader.rs b/packages/next-swc/crates/next-core/src/page_loader.rs index b1f37a0d5c59..7ac15c7b65a9 100644 --- a/packages/next-swc/crates/next-core/src/page_loader.rs +++ b/packages/next-swc/crates/next-core/src/page_loader.rs @@ -9,10 +9,7 @@ use turbopack_binding::{ turbopack::{ core::{ asset::{Asset, AssetContent}, - chunk::{ - ChunkData, ChunkableModule, ChunkingContext, ChunksData, EvaluatableAsset, - EvaluatableAssets, - }, + chunk::{ChunkData, ChunkingContext, ChunksData, EvaluatableAsset, EvaluatableAssets}, context::AssetContext, ident::AssetIdent, module::Module, @@ -138,10 +135,9 @@ impl PageLoaderAsset { bail!("internal module must be evaluatable"); }; - Ok(this.client_chunking_context.evaluated_chunk_group( - module.as_root_chunk(this.client_chunking_context), - EvaluatableAssets::one(module), - )) + Ok(this + .client_chunking_context + .evaluated_chunk_group(module.ident(), EvaluatableAssets::one(module))) } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-core/src/util.rs b/packages/next-swc/crates/next-core/src/util.rs index 374d27551f76..6b1479255a09 100644 --- a/packages/next-swc/crates/next-core/src/util.rs +++ b/packages/next-swc/crates/next-core/src/util.rs @@ -1,21 +1,26 @@ -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; +use indexmap::{IndexMap, IndexSet}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_json::Value as JsonValue; use swc_core::ecma::ast::Program; use turbo_tasks::{trace::TraceRawVcs, TaskInput, ValueDefault, ValueToString, Vc}; -use turbo_tasks_fs::rope::Rope; +use turbo_tasks_fs::{rope::Rope, util::join_path, File}; use turbopack_binding::{ turbo::tasks_fs::{json::parse_json_rope_with_source_context, FileContent, FileSystemPath}, turbopack::{ core::{ + asset::AssetContent, environment::{ServerAddr, ServerInfo}, ident::AssetIdent, issue::{Issue, IssueExt, IssueSeverity}, module::Module, + source::Source, + virtual_source::VirtualSource, }, ecmascript::{ analyzer::{JsValue, ObjectPart}, parse::ParseResult, + utils::StringifyJs, EcmascriptModuleAsset, }, turbopack::condition::ContextCondition, @@ -347,14 +352,202 @@ fn parse_config_from_js_value(module: Vc>, value: &JsValue) -> N config } -#[turbo_tasks::function] +/// Loads a next.js template, replaces `replacements` and `injections` and makes +/// sure there are none left over. +// TODO: should this be a turbo tasks function? +// #[turbo_tasks::function] pub async fn load_next_js_template( + path: &str, project_path: Vc, - file: String, -) -> Result> { - let file_path = virtual_next_js_template_path(project_path, file); + replacements: IndexMap<&'static str, String>, + injections: IndexMap<&'static str, String>, +) -> Result>> { + let path = virtual_next_js_template_path(project_path, path.to_string()); + + let content = &*file_content_rope(path.read()).await?; + let content = content.to_str()?.to_string(); + + let parent_path = path.parent(); + let parent_path_value = &*parent_path.await?; + + let package_root = get_next_package(project_path).parent(); + let package_root_value = &*package_root.await?; + + /// See [regex::Regex::replace_all]. + fn replace_all( + re: ®ex::Regex, + haystack: &str, + mut replacement: impl FnMut(®ex::Captures) -> Result, + ) -> Result { + let mut new = String::with_capacity(haystack.len()); + let mut last_match = 0; + for caps in re.captures_iter(haystack) { + let m = caps.get(0).unwrap(); + new.push_str(&haystack[last_match..m.start()]); + new.push_str(&replacement(&caps)?); + last_match = m.end(); + } + new.push_str(&haystack[last_match..]); + Ok(new) + } - let content = &*file_path.read().await?; + // Update the relative imports to be absolute. This will update any relative + // imports to be relative to the root of the `next` package. + let regex = lazy_regex::regex!("(?:from \"(\\..*)\"|import \"(\\..*)\")"); + + let mut count = 0; + let mut content = replace_all(regex, &content, |caps| { + let from_request = caps.get(1).map_or("", |c| c.as_str()); + let import_request = caps.get(2).map_or("", |c| c.as_str()); + + count += 1; + let is_from_request = !from_request.is_empty(); + + let imported = FileSystemPath { + fs: package_root_value.fs, + path: join_path( + &parent_path_value.path, + if is_from_request { + from_request + } else { + import_request + }, + ) + .context("path should not leave the fs")?, + }; + + let relative = package_root_value + .get_relative_path_to(&imported) + .context("path has to be relative to package root")?; + + if !relative.starts_with("./next/") { + bail!( + "Invariant: Expected relative import to start with \"./next/\", found \"{}\"", + relative + ) + } + + let relative = relative + .strip_prefix("./") + .context("should be able to strip the prefix")?; + + Ok(if is_from_request { + format!("from {}", StringifyJs(relative)) + } else { + format!("import {}", StringifyJs(relative)) + }) + }) + .context("replacing imports failed")?; + + // Verify that at least one import was replaced. It's the case today where + // every template file has at least one import to update, so this ensures that + // we don't accidentally remove the import replacement code or use the wrong + // template file. + if count == 0 { + bail!("Invariant: Expected to replace at least one import") + } + + // Replace all the template variables with the actual values. If a template + // variable is missing, throw an error. + let mut replaced = IndexSet::new(); + for (key, replacement) in &replacements { + let full = format!("\"{}\"", key); + + if content.contains(&full) { + replaced.insert(*key); + content = content.replace(&full, &StringifyJs(&replacement).to_string()); + } + } + + // Check to see if there's any remaining template variables. + let regex = lazy_regex::regex!("/VAR_[A-Z_]+"); + let matches = regex + .find_iter(&content) + .map(|m| m.as_str().to_string()) + .collect::>(); + + if !matches.is_empty() { + bail!( + "Invariant: Expected to replace all template variables, found {}", + matches.join(", "), + ) + } + + // Check to see if any template variable was provided but not used. + if replaced.len() != replacements.len() { + // Find the difference between the provided replacements and the replaced + // template variables. This will let us notify the user of any template + // variables that were not used but were provided. + let difference = replacements + .keys() + .filter(|k| !replaced.contains(*k)) + .cloned() + .collect::>(); + + bail!( + "Invariant: Expected to replace all template variables, missing {} in template", + difference.join(", "), + ) + } + + // Replace the injections. + let mut injected = IndexSet::new(); + for (key, injection) in &injections { + let full = format!("// INJECT:{}", key); + + if content.contains(&full) { + // Track all the injections to ensure that we're not missing any. + injected.insert(*key); + content = content.replace(&full, &format!("const {} = {}", key, injection)); + } + } + + // Check to see if there's any remaining injections. + let regex = lazy_regex::regex!("// INJECT:[A-Za-z0-9_]+"); + let matches = regex + .find_iter(&content) + .map(|m| m.as_str().to_string()) + .collect::>(); + + if !matches.is_empty() { + bail!( + "Invariant: Expected to inject all injections, found {}", + matches.join(", "), + ) + } + + // Check to see if any injection was provided but not used. + if injected.len() != injections.len() { + // Find the difference between the provided replacements and the replaced + // template variables. This will let us notify the user of any template + // variables that were not used but were provided. + let difference = injections + .keys() + .filter(|k| !injected.contains(*k)) + .cloned() + .collect::>(); + + bail!( + "Invariant: Expected to inject all injections, missing {} in template", + difference.join(", "), + ) + } + + // Ensure that the last line is a newline. + if !content.ends_with('\n') { + content.push('\n'); + } + + let file = File::from(content); + + let source = VirtualSource::new(path, AssetContent::file(file.into())); + + Ok(Vc::upcast(source)) +} + +#[turbo_tasks::function] +pub async fn file_content_rope(content: Vc) -> Result> { + let content = &*content.await?; let FileContent::Content(file) = content else { bail!("Expected file content for file"); @@ -363,7 +556,6 @@ pub async fn load_next_js_template( Ok(file.content().to_owned().cell()) } -#[turbo_tasks::function] pub fn virtual_next_js_template_path( project_path: Vc, file: String, diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index eb13e7a3d6d4..3efe409b5eba 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 842f76584ca4..c19051cb5c19 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -90,7 +90,7 @@ ] }, "dependencies": { - "@next/env": "13.5.5-canary.2", + "@next/env": "13.5.5-canary.3", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -144,14 +144,13 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "13.5.5-canary.2", - "@next/polyfill-nomodule": "13.5.5-canary.2", - "@next/react-dev-overlay": "13.5.5-canary.2", - "@next/react-refresh-utils": "13.5.5-canary.2", - "@next/swc": "13.5.5-canary.2", + "@next/polyfill-module": "13.5.5-canary.3", + "@next/polyfill-nomodule": "13.5.5-canary.3", + "@next/react-dev-overlay": "13.5.5-canary.3", + "@next/react-refresh-utils": "13.5.5-canary.3", + "@next/swc": "13.5.5-canary.3", "@opentelemetry/api": "1.4.1", "@playwright/test": "^1.35.1", - "@segment/ajv-human-errors": "2.1.2", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", "@types/amphtml-validator": "1.0.0", @@ -192,9 +191,8 @@ "@types/ws": "8.2.0", "@vercel/ncc": "0.34.0", "@vercel/nft": "0.22.6", - "@vercel/turbopack-ecmascript-runtime": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231002.1", + "@vercel/turbopack-ecmascript-runtime": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231006.2", "acorn": "8.5.0", - "ajv": "8.11.0", "amphtml-validator": "1.0.35", "anser": "1.4.9", "arg": "4.1.0", @@ -314,7 +312,8 @@ "webpack": "5.86.0", "webpack-sources1": "npm:webpack-sources@1.4.3", "webpack-sources3": "npm:webpack-sources@3.2.3", - "ws": "8.2.3" + "ws": "8.2.3", + "zod": "3.22.3" }, "engines": { "node": ">=16.14.0" diff --git a/packages/next/src/build/templates/app-page.ts b/packages/next/src/build/templates/app-page.ts index f0d2ab692e2a..11dba21ddded 100644 --- a/packages/next/src/build/templates/app-page.ts +++ b/packages/next/src/build/templates/app-page.ts @@ -1,13 +1,14 @@ import type { LoaderTree } from '../../server/lib/app-dir-module' -// @ts-ignore this need to be imported from next/dist to be external -import * as module from 'next/dist/server/future/route-modules/app-page/module.compiled' +import { AppPageRouteModule } from '../../server/future/route-modules/app-page/module.compiled' import { RouteKind } from '../../server/future/route-kind' -const AppPageRouteModule = - module.AppPageRouteModule as unknown as typeof import('../../server/future/route-modules/app-page/module').AppPageRouteModule - // These are injected by the loader afterwards. + +/** + * The tree created in next-app-loader that holds component segments and modules + * and I've updated it. + */ declare const tree: LoaderTree declare const pages: any @@ -18,7 +19,6 @@ declare const pages: any export { tree, pages } -// @ts-expect-error - replaced by webpack/turbopack loader export { default as GlobalError } from 'VAR_MODULE_GLOBAL_ERROR' // These are injected by the loader afterwards. diff --git a/packages/next/src/build/templates/app-route.ts b/packages/next/src/build/templates/app-route.ts index b4b8e5b0fe6c..2b8f9d101aee 100644 --- a/packages/next/src/build/templates/app-route.ts +++ b/packages/next/src/build/templates/app-route.ts @@ -1,17 +1,13 @@ import '../../server/node-polyfill-headers' -// @ts-ignore this need to be imported from next/dist to be external -import * as module from 'next/dist/server/future/route-modules/app-route/module.compiled' - -import type { AppRouteRouteModuleOptions } from '../../server/future/route-modules/app-route/module' +import { + AppRouteRouteModule, + type AppRouteRouteModuleOptions, +} from '../../server/future/route-modules/app-route/module.compiled' import { RouteKind } from '../../server/future/route-kind' -// @ts-expect-error - replaced by webpack/turbopack loader import * as userland from 'VAR_USERLAND' -const AppRouteRouteModule = - module.AppRouteRouteModule as unknown as typeof import('../../server/future/route-modules/app-route/module').AppRouteRouteModule - // These are injected by the loader afterwards. This is injected as a variable // instead of a replacement because this could also be `undefined` instead of // an empty string. diff --git a/packages/next/src/build/templates/edge-app-route.ts b/packages/next/src/build/templates/edge-app-route.ts index 69b12643ecfa..226252d06908 100644 --- a/packages/next/src/build/templates/edge-app-route.ts +++ b/packages/next/src/build/templates/edge-app-route.ts @@ -1,7 +1,6 @@ import { EdgeRouteModuleWrapper } from '../../server/web/edge-route-module-wrapper' // Import the userland code. -// @ts-expect-error - replaced by webpack/turbopack loader import * as module from 'VAR_USERLAND' export const ComponentMod = module diff --git a/packages/next/src/build/templates/middleware.ts b/packages/next/src/build/templates/middleware.ts index 15dda841e113..3ede209e4d28 100644 --- a/packages/next/src/build/templates/middleware.ts +++ b/packages/next/src/build/templates/middleware.ts @@ -1,9 +1,10 @@ -import '../../server/web/globals' import type { AdapterOptions } from '../../server/web/adapter' + +import '../../server/web/globals' + import { adapter } from '../../server/web/adapter' // Import the userland code. -// @ts-expect-error - replaced by webpack/turbopack loader import * as _mod from 'VAR_USERLAND' const mod = { ..._mod } diff --git a/packages/next/src/build/templates/pages-api.ts b/packages/next/src/build/templates/pages-api.ts index eaeec836cb61..54033fe42908 100644 --- a/packages/next/src/build/templates/pages-api.ts +++ b/packages/next/src/build/templates/pages-api.ts @@ -1,14 +1,9 @@ -// @ts-ignore this need to be imported from next/dist to be external -import * as module from 'next/dist/server/future/route-modules/pages-api/module.compiled' - +import { PagesAPIRouteModule } from '../../server/future/route-modules/pages-api/module.compiled' import { RouteKind } from '../../server/future/route-kind' -import { hoist } from './helpers' -const PagesAPIRouteModule = - module.PagesAPIRouteModule as unknown as typeof import('../../server/future/route-modules/pages-api/module').PagesAPIRouteModule +import { hoist } from './helpers' // Import the userland code. -// @ts-expect-error - replaced by webpack/turbopack loader import * as userland from 'VAR_USERLAND' // Re-export the handler (should be the default export). diff --git a/packages/next/src/build/templates/pages-edge-api.ts b/packages/next/src/build/templates/pages-edge-api.ts index 7d453a69720b..90b31feb21aa 100644 --- a/packages/next/src/build/templates/pages-edge-api.ts +++ b/packages/next/src/build/templates/pages-edge-api.ts @@ -1,10 +1,11 @@ -import '../../server/web/globals' import type { AdapterOptions } from '../../server/web/adapter' + +import '../../server/web/globals' + import { adapter } from '../../server/web/adapter' import { IncrementalCache } from '../../server/lib/incremental-cache' // Import the userland code. -// @ts-expect-error - replaced by webpack/turbopack loader import handler from 'VAR_USERLAND' const page = 'VAR_DEFINITION_PAGE' diff --git a/packages/next/src/build/templates/pages.ts b/packages/next/src/build/templates/pages.ts index b5def5d13c55..87093f682e65 100644 --- a/packages/next/src/build/templates/pages.ts +++ b/packages/next/src/build/templates/pages.ts @@ -1,21 +1,14 @@ -// @ts-ignore this need to be imported from next/dist to be external -import * as module from 'next/dist/server/future/route-modules/pages/module.compiled' +import { PagesRouteModule } from '../../server/future/route-modules/pages/module.compiled' import { RouteKind } from '../../server/future/route-kind' import { hoist } from './helpers' // Import the app and document modules. -// @ts-expect-error - replaced by webpack/turbopack loader import Document from 'VAR_MODULE_DOCUMENT' -// @ts-expect-error - replaced by webpack/turbopack loader import App from 'VAR_MODULE_APP' // Import the userland code. -// @ts-expect-error - replaced by webpack/turbopack loader import * as userland from 'VAR_USERLAND' -const PagesRouteModule = - module.PagesRouteModule as unknown as typeof import('../../server/future/route-modules/pages/module').PagesRouteModule - // Re-export the component (should be the default export). export default hoist(userland, 'default') diff --git a/packages/next/src/build/utils.ts b/packages/next/src/build/utils.ts index b12532aad7b1..824d86b9845e 100644 --- a/packages/next/src/build/utils.ts +++ b/packages/next/src/build/utils.ts @@ -14,8 +14,8 @@ import type { EdgeFunctionDefinition, MiddlewareManifest, } from './webpack/plugins/middleware-plugin' -import type { StaticGenerationAsyncStorage } from '../client/components/static-generation-async-storage.external' import type { WebpackLayerName } from '../lib/constants' +import type { AppPageModule } from '../server/future/route-modules/app-page/module' import '../server/require-hook' import '../server/node-polyfill-fetch' @@ -68,9 +68,7 @@ import { nodeFs } from '../server/lib/node-fs-methods' import * as ciEnvironment from '../telemetry/ci-info' import { normalizeAppPath } from '../shared/lib/router/utils/app-paths' import { denormalizeAppPagePath } from '../shared/lib/page-path/denormalize-app-path' - -const { AppRouteRouteModule } = - require('../server/future/route-modules/app-route/module.compiled') as typeof import('../server/future/route-modules/app-route/module') +import { AppRouteRouteModule } from '../server/future/route-modules/app-route/module.compiled' export type ROUTER_TYPE = 'pages' | 'app' @@ -1469,25 +1467,12 @@ export async function isPageStatic({ | undefined if (pageType === 'app') { - isClientComponent = isClientReference(componentsResult.ComponentMod) - const tree = componentsResult.ComponentMod.tree - - const staticGenerationAsyncStorage: StaticGenerationAsyncStorage = - componentsResult.ComponentMod.staticGenerationAsyncStorage - if (!staticGenerationAsyncStorage) { - throw new Error( - 'Invariant: staticGenerationAsyncStorage should be defined on the module' - ) - } + const ComponentMod: AppPageModule = componentsResult.ComponentMod - const serverHooks = componentsResult.ComponentMod.serverHooks - if (!serverHooks) { - throw new Error( - 'Invariant: serverHooks should be defined on the module' - ) - } + isClientComponent = isClientReference(componentsResult.ComponentMod) - const { routeModule } = componentsResult + const { tree, staticGenerationAsyncStorage, serverHooks, routeModule } = + ComponentMod const generateParams: GenerateParams = routeModule && AppRouteRouteModule.is(routeModule) diff --git a/packages/next/src/build/webpack/loaders/next-app-loader.ts b/packages/next/src/build/webpack/loaders/next-app-loader.ts index 017536bbc73d..69e97eb0812a 100644 --- a/packages/next/src/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-app-loader.ts @@ -1,4 +1,4 @@ -import type webpack from 'webpack' +import type webpack from 'next/dist/compiled/webpack/webpack' import type { ValueOf } from '../../../shared/lib/constants' import type { ModuleReference, CollectedMetadata } from './metadata/types' diff --git a/packages/next/src/compiled/babel-packages/package.json b/packages/next/src/compiled/babel-packages/package.json index bd756542b973..96340f93f599 100644 --- a/packages/next/src/compiled/babel-packages/package.json +++ b/packages/next/src/compiled/babel-packages/package.json @@ -1 +1 @@ -{"name":"babel-packages","main":"./packages-bundle.js"} \ No newline at end of file +{"name":"babel-packages","main":"./packages-bundle.js"} diff --git a/packages/next/src/compiled/constants-browserify/package.json b/packages/next/src/compiled/constants-browserify/package.json index bf04940e17e9..eddc7606b465 100644 --- a/packages/next/src/compiled/constants-browserify/package.json +++ b/packages/next/src/compiled/constants-browserify/package.json @@ -1 +1 @@ -{"name":"constants-browserify","main":"./constants.json"} \ No newline at end of file +{"name":"constants-browserify","main":"./constants.json"} diff --git a/packages/next/src/compiled/zod/LICENSE b/packages/next/src/compiled/zod/LICENSE new file mode 100644 index 000000000000..2c93bb52b933 --- /dev/null +++ b/packages/next/src/compiled/zod/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Colin McDonnell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/next/src/compiled/zod/index.js b/packages/next/src/compiled/zod/index.js new file mode 100644 index 000000000000..daacf47c5dbb --- /dev/null +++ b/packages/next/src/compiled/zod/index.js @@ -0,0 +1 @@ +(()=>{"use strict";var e={815:(e,t,s)=>{Object.defineProperty(t,"__esModule",{value:true});t.ZodError=t.quotelessJson=t.ZodIssueCode=void 0;const r=s(900);t.ZodIssueCode=r.util.arrayToEnum(["invalid_type","invalid_literal","custom","invalid_union","invalid_union_discriminator","invalid_enum_value","unrecognized_keys","invalid_arguments","invalid_return_type","invalid_date","invalid_string","too_small","too_big","invalid_intersection_types","not_multiple_of","not_finite"]);const quotelessJson=e=>{const t=JSON.stringify(e,null,2);return t.replace(/"([^"]+)":/g,"$1:")};t.quotelessJson=quotelessJson;class ZodError extends Error{constructor(e){super();this.issues=[];this.addIssue=e=>{this.issues=[...this.issues,e]};this.addIssues=(e=[])=>{this.issues=[...this.issues,...e]};const t=new.target.prototype;if(Object.setPrototypeOf){Object.setPrototypeOf(this,t)}else{this.__proto__=t}this.name="ZodError";this.issues=e}get errors(){return this.issues}format(e){const t=e||function(e){return e.message};const s={_errors:[]};const processError=e=>{for(const r of e.issues){if(r.code==="invalid_union"){r.unionErrors.map(processError)}else if(r.code==="invalid_return_type"){processError(r.returnTypeError)}else if(r.code==="invalid_arguments"){processError(r.argumentsError)}else if(r.path.length===0){s._errors.push(t(r))}else{let e=s;let a=0;while(ae.message)){const t={};const s=[];for(const r of this.issues){if(r.path.length>0){t[r.path[0]]=t[r.path[0]]||[];t[r.path[0]].push(e(r))}else{s.push(e(r))}}return{formErrors:s,fieldErrors:t}}get formErrors(){return this.flatten()}}t.ZodError=ZodError;ZodError.create=e=>{const t=new ZodError(e);return t}},564:function(e,t,s){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:true});t.getErrorMap=t.setErrorMap=t.defaultErrorMap=void 0;const a=r(s(209));t.defaultErrorMap=a.default;let n=a.default;function setErrorMap(e){n=e}t.setErrorMap=setErrorMap;function getErrorMap(){return n}t.getErrorMap=getErrorMap},631:function(e,t,s){var r=this&&this.__createBinding||(Object.create?function(e,t,s,r){if(r===undefined)r=s;Object.defineProperty(e,r,{enumerable:true,get:function(){return t[s]}})}:function(e,t,s,r){if(r===undefined)r=s;e[r]=t[s]});var a=this&&this.__exportStar||function(e,t){for(var s in e)if(s!=="default"&&!Object.prototype.hasOwnProperty.call(t,s))r(t,e,s)};Object.defineProperty(t,"__esModule",{value:true});a(s(564),t);a(s(79),t);a(s(212),t);a(s(900),t);a(s(973),t);a(s(815),t)},97:(e,t)=>{Object.defineProperty(t,"__esModule",{value:true});t.errorUtil=void 0;var s;(function(e){e.errToObj=e=>typeof e==="string"?{message:e}:e||{};e.toString=e=>typeof e==="string"?e:e===null||e===void 0?void 0:e.message})(s=t.errorUtil||(t.errorUtil={}))},79:function(e,t,s){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:true});t.isAsync=t.isValid=t.isDirty=t.isAborted=t.OK=t.DIRTY=t.INVALID=t.ParseStatus=t.addIssueToContext=t.EMPTY_PATH=t.makeIssue=void 0;const a=s(564);const n=r(s(209));const makeIssue=e=>{const{data:t,path:s,errorMaps:r,issueData:a}=e;const n=[...s,...a.path||[]];const o={...a,path:n};let i="";const d=r.filter((e=>!!e)).slice().reverse();for(const e of d){i=e(o,{data:t,defaultError:i}).message}return{...a,path:n,message:a.message||i}};t.makeIssue=makeIssue;t.EMPTY_PATH=[];function addIssueToContext(e,s){const r=(0,t.makeIssue)({issueData:s,data:e.data,path:e.path,errorMaps:[e.common.contextualErrorMap,e.schemaErrorMap,(0,a.getErrorMap)(),n.default].filter((e=>!!e))});e.common.issues.push(r)}t.addIssueToContext=addIssueToContext;class ParseStatus{constructor(){this.value="valid"}dirty(){if(this.value==="valid")this.value="dirty"}abort(){if(this.value!=="aborted")this.value="aborted"}static mergeArray(e,s){const r=[];for(const a of s){if(a.status==="aborted")return t.INVALID;if(a.status==="dirty")e.dirty();r.push(a.value)}return{status:e.value,value:r}}static async mergeObjectAsync(e,t){const s=[];for(const e of t){s.push({key:await e.key,value:await e.value})}return ParseStatus.mergeObjectSync(e,s)}static mergeObjectSync(e,s){const r={};for(const a of s){const{key:s,value:n}=a;if(s.status==="aborted")return t.INVALID;if(n.status==="aborted")return t.INVALID;if(s.status==="dirty")e.dirty();if(n.status==="dirty")e.dirty();if(s.value!=="__proto__"&&(typeof n.value!=="undefined"||a.alwaysSet)){r[s.value]=n.value}}return{status:e.value,value:r}}}t.ParseStatus=ParseStatus;t.INVALID=Object.freeze({status:"aborted"});const DIRTY=e=>({status:"dirty",value:e});t.DIRTY=DIRTY;const OK=e=>({status:"valid",value:e});t.OK=OK;const isAborted=e=>e.status==="aborted";t.isAborted=isAborted;const isDirty=e=>e.status==="dirty";t.isDirty=isDirty;const isValid=e=>e.status==="valid";t.isValid=isValid;const isAsync=e=>typeof Promise!=="undefined"&&e instanceof Promise;t.isAsync=isAsync},212:(e,t)=>{Object.defineProperty(t,"__esModule",{value:true})},900:(e,t)=>{Object.defineProperty(t,"__esModule",{value:true});t.getParsedType=t.ZodParsedType=t.objectUtil=t.util=void 0;var s;(function(e){e.assertEqual=e=>e;function assertIs(e){}e.assertIs=assertIs;function assertNever(e){throw new Error}e.assertNever=assertNever;e.arrayToEnum=e=>{const t={};for(const s of e){t[s]=s}return t};e.getValidEnumValues=t=>{const s=e.objectKeys(t).filter((e=>typeof t[t[e]]!=="number"));const r={};for(const e of s){r[e]=t[e]}return e.objectValues(r)};e.objectValues=t=>e.objectKeys(t).map((function(e){return t[e]}));e.objectKeys=typeof Object.keys==="function"?e=>Object.keys(e):e=>{const t=[];for(const s in e){if(Object.prototype.hasOwnProperty.call(e,s)){t.push(s)}}return t};e.find=(e,t)=>{for(const s of e){if(t(s))return s}return undefined};e.isInteger=typeof Number.isInteger==="function"?e=>Number.isInteger(e):e=>typeof e==="number"&&isFinite(e)&&Math.floor(e)===e;function joinValues(e,t=" | "){return e.map((e=>typeof e==="string"?`'${e}'`:e)).join(t)}e.joinValues=joinValues;e.jsonStringifyReplacer=(e,t)=>{if(typeof t==="bigint"){return t.toString()}return t}})(s=t.util||(t.util={}));var r;(function(e){e.mergeShapes=(e,t)=>({...e,...t})})(r=t.objectUtil||(t.objectUtil={}));t.ZodParsedType=s.arrayToEnum(["string","nan","number","integer","float","boolean","date","bigint","symbol","function","undefined","null","array","object","unknown","promise","void","never","map","set"]);const getParsedType=e=>{const s=typeof e;switch(s){case"undefined":return t.ZodParsedType.undefined;case"string":return t.ZodParsedType.string;case"number":return isNaN(e)?t.ZodParsedType.nan:t.ZodParsedType.number;case"boolean":return t.ZodParsedType.boolean;case"function":return t.ZodParsedType.function;case"bigint":return t.ZodParsedType.bigint;case"symbol":return t.ZodParsedType.symbol;case"object":if(Array.isArray(e)){return t.ZodParsedType.array}if(e===null){return t.ZodParsedType.null}if(e.then&&typeof e.then==="function"&&e.catch&&typeof e.catch==="function"){return t.ZodParsedType.promise}if(typeof Map!=="undefined"&&e instanceof Map){return t.ZodParsedType.map}if(typeof Set!=="undefined"&&e instanceof Set){return t.ZodParsedType.set}if(typeof Date!=="undefined"&&e instanceof Date){return t.ZodParsedType.date}return t.ZodParsedType.object;default:return t.ZodParsedType.unknown}};t.getParsedType=getParsedType},773:function(e,t,s){var r=this&&this.__createBinding||(Object.create?function(e,t,s,r){if(r===undefined)r=s;Object.defineProperty(e,r,{enumerable:true,get:function(){return t[s]}})}:function(e,t,s,r){if(r===undefined)r=s;e[r]=t[s]});var a=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var s in e)if(s!=="default"&&Object.prototype.hasOwnProperty.call(e,s))r(t,e,s);a(t,e);return t};var o=this&&this.__exportStar||function(e,t){for(var s in e)if(s!=="default"&&!Object.prototype.hasOwnProperty.call(t,s))r(t,e,s)};Object.defineProperty(t,"__esModule",{value:true});t.z=void 0;const i=n(s(631));t.z=i;o(s(631),t);t["default"]=i},209:(e,t,s)=>{Object.defineProperty(t,"__esModule",{value:true});const r=s(900);const a=s(815);const errorMap=(e,t)=>{let s;switch(e.code){case a.ZodIssueCode.invalid_type:if(e.received===r.ZodParsedType.undefined){s="Required"}else{s=`Expected ${e.expected}, received ${e.received}`}break;case a.ZodIssueCode.invalid_literal:s=`Invalid literal value, expected ${JSON.stringify(e.expected,r.util.jsonStringifyReplacer)}`;break;case a.ZodIssueCode.unrecognized_keys:s=`Unrecognized key(s) in object: ${r.util.joinValues(e.keys,", ")}`;break;case a.ZodIssueCode.invalid_union:s=`Invalid input`;break;case a.ZodIssueCode.invalid_union_discriminator:s=`Invalid discriminator value. Expected ${r.util.joinValues(e.options)}`;break;case a.ZodIssueCode.invalid_enum_value:s=`Invalid enum value. Expected ${r.util.joinValues(e.options)}, received '${e.received}'`;break;case a.ZodIssueCode.invalid_arguments:s=`Invalid function arguments`;break;case a.ZodIssueCode.invalid_return_type:s=`Invalid function return type`;break;case a.ZodIssueCode.invalid_date:s=`Invalid date`;break;case a.ZodIssueCode.invalid_string:if(typeof e.validation==="object"){if("includes"in e.validation){s=`Invalid input: must include "${e.validation.includes}"`;if(typeof e.validation.position==="number"){s=`${s} at one or more positions greater than or equal to ${e.validation.position}`}}else if("startsWith"in e.validation){s=`Invalid input: must start with "${e.validation.startsWith}"`}else if("endsWith"in e.validation){s=`Invalid input: must end with "${e.validation.endsWith}"`}else{r.util.assertNever(e.validation)}}else if(e.validation!=="regex"){s=`Invalid ${e.validation}`}else{s="Invalid"}break;case a.ZodIssueCode.too_small:if(e.type==="array")s=`Array must contain ${e.exact?"exactly":e.inclusive?`at least`:`more than`} ${e.minimum} element(s)`;else if(e.type==="string")s=`String must contain ${e.exact?"exactly":e.inclusive?`at least`:`over`} ${e.minimum} character(s)`;else if(e.type==="number")s=`Number must be ${e.exact?`exactly equal to `:e.inclusive?`greater than or equal to `:`greater than `}${e.minimum}`;else if(e.type==="date")s=`Date must be ${e.exact?`exactly equal to `:e.inclusive?`greater than or equal to `:`greater than `}${new Date(Number(e.minimum))}`;else s="Invalid input";break;case a.ZodIssueCode.too_big:if(e.type==="array")s=`Array must contain ${e.exact?`exactly`:e.inclusive?`at most`:`less than`} ${e.maximum} element(s)`;else if(e.type==="string")s=`String must contain ${e.exact?`exactly`:e.inclusive?`at most`:`under`} ${e.maximum} character(s)`;else if(e.type==="number")s=`Number must be ${e.exact?`exactly`:e.inclusive?`less than or equal to`:`less than`} ${e.maximum}`;else if(e.type==="bigint")s=`BigInt must be ${e.exact?`exactly`:e.inclusive?`less than or equal to`:`less than`} ${e.maximum}`;else if(e.type==="date")s=`Date must be ${e.exact?`exactly`:e.inclusive?`smaller than or equal to`:`smaller than`} ${new Date(Number(e.maximum))}`;else s="Invalid input";break;case a.ZodIssueCode.custom:s=`Invalid input`;break;case a.ZodIssueCode.invalid_intersection_types:s=`Intersection results could not be merged`;break;case a.ZodIssueCode.not_multiple_of:s=`Number must be a multiple of ${e.multipleOf}`;break;case a.ZodIssueCode.not_finite:s="Number must be finite";break;default:s=t.defaultError;r.util.assertNever(e)}return{message:s}};t["default"]=errorMap},973:(e,t,s)=>{Object.defineProperty(t,"__esModule",{value:true});t.date=t.boolean=t.bigint=t.array=t.any=t.coerce=t.ZodFirstPartyTypeKind=t.late=t.ZodSchema=t.Schema=t.custom=t.ZodReadonly=t.ZodPipeline=t.ZodBranded=t.BRAND=t.ZodNaN=t.ZodCatch=t.ZodDefault=t.ZodNullable=t.ZodOptional=t.ZodTransformer=t.ZodEffects=t.ZodPromise=t.ZodNativeEnum=t.ZodEnum=t.ZodLiteral=t.ZodLazy=t.ZodFunction=t.ZodSet=t.ZodMap=t.ZodRecord=t.ZodTuple=t.ZodIntersection=t.ZodDiscriminatedUnion=t.ZodUnion=t.ZodObject=t.ZodArray=t.ZodVoid=t.ZodNever=t.ZodUnknown=t.ZodAny=t.ZodNull=t.ZodUndefined=t.ZodSymbol=t.ZodDate=t.ZodBoolean=t.ZodBigInt=t.ZodNumber=t.ZodString=t.ZodType=void 0;t.NEVER=t["void"]=t.unknown=t.union=t.undefined=t.tuple=t.transformer=t.symbol=t.string=t.strictObject=t.set=t.record=t.promise=t.preprocess=t.pipeline=t.ostring=t.optional=t.onumber=t.oboolean=t.object=t.number=t.nullable=t["null"]=t.never=t.nativeEnum=t.nan=t.map=t.literal=t.lazy=t.intersection=t["instanceof"]=t["function"]=t["enum"]=t.effect=t.discriminatedUnion=void 0;const r=s(564);const a=s(97);const n=s(79);const o=s(900);const i=s(815);class ParseInputLazyPath{constructor(e,t,s,r){this._cachedPath=[];this.parent=e;this.data=t;this._path=s;this._key=r}get path(){if(!this._cachedPath.length){if(this._key instanceof Array){this._cachedPath.push(...this._path,...this._key)}else{this._cachedPath.push(...this._path,this._key)}}return this._cachedPath}}const handleResult=(e,t)=>{if((0,n.isValid)(t)){return{success:true,data:t.value}}else{if(!e.common.issues.length){throw new Error("Validation failed but no issues detected.")}return{success:false,get error(){if(this._error)return this._error;const t=new i.ZodError(e.common.issues);this._error=t;return this._error}}}};function processCreateParams(e){if(!e)return{};const{errorMap:t,invalid_type_error:s,required_error:r,description:a}=e;if(t&&(s||r)){throw new Error(`Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.`)}if(t)return{errorMap:t,description:a};const customMap=(e,t)=>{if(e.code!=="invalid_type")return{message:t.defaultError};if(typeof t.data==="undefined"){return{message:r!==null&&r!==void 0?r:t.defaultError}}return{message:s!==null&&s!==void 0?s:t.defaultError}};return{errorMap:customMap,description:a}}class ZodType{constructor(e){this.spa=this.safeParseAsync;this._def=e;this.parse=this.parse.bind(this);this.safeParse=this.safeParse.bind(this);this.parseAsync=this.parseAsync.bind(this);this.safeParseAsync=this.safeParseAsync.bind(this);this.spa=this.spa.bind(this);this.refine=this.refine.bind(this);this.refinement=this.refinement.bind(this);this.superRefine=this.superRefine.bind(this);this.optional=this.optional.bind(this);this.nullable=this.nullable.bind(this);this.nullish=this.nullish.bind(this);this.array=this.array.bind(this);this.promise=this.promise.bind(this);this.or=this.or.bind(this);this.and=this.and.bind(this);this.transform=this.transform.bind(this);this.brand=this.brand.bind(this);this.default=this.default.bind(this);this.catch=this.catch.bind(this);this.describe=this.describe.bind(this);this.pipe=this.pipe.bind(this);this.readonly=this.readonly.bind(this);this.isNullable=this.isNullable.bind(this);this.isOptional=this.isOptional.bind(this)}get description(){return this._def.description}_getType(e){return(0,o.getParsedType)(e.data)}_getOrReturnCtx(e,t){return t||{common:e.parent.common,data:e.data,parsedType:(0,o.getParsedType)(e.data),schemaErrorMap:this._def.errorMap,path:e.path,parent:e.parent}}_processInputParams(e){return{status:new n.ParseStatus,ctx:{common:e.parent.common,data:e.data,parsedType:(0,o.getParsedType)(e.data),schemaErrorMap:this._def.errorMap,path:e.path,parent:e.parent}}}_parseSync(e){const t=this._parse(e);if((0,n.isAsync)(t)){throw new Error("Synchronous parse encountered promise.")}return t}_parseAsync(e){const t=this._parse(e);return Promise.resolve(t)}parse(e,t){const s=this.safeParse(e,t);if(s.success)return s.data;throw s.error}safeParse(e,t){var s;const r={common:{issues:[],async:(s=t===null||t===void 0?void 0:t.async)!==null&&s!==void 0?s:false,contextualErrorMap:t===null||t===void 0?void 0:t.errorMap},path:(t===null||t===void 0?void 0:t.path)||[],schemaErrorMap:this._def.errorMap,parent:null,data:e,parsedType:(0,o.getParsedType)(e)};const a=this._parseSync({data:e,path:r.path,parent:r});return handleResult(r,a)}async parseAsync(e,t){const s=await this.safeParseAsync(e,t);if(s.success)return s.data;throw s.error}async safeParseAsync(e,t){const s={common:{issues:[],contextualErrorMap:t===null||t===void 0?void 0:t.errorMap,async:true},path:(t===null||t===void 0?void 0:t.path)||[],schemaErrorMap:this._def.errorMap,parent:null,data:e,parsedType:(0,o.getParsedType)(e)};const r=this._parse({data:e,path:s.path,parent:s});const a=await((0,n.isAsync)(r)?r:Promise.resolve(r));return handleResult(s,a)}refine(e,t){const getIssueProperties=e=>{if(typeof t==="string"||typeof t==="undefined"){return{message:t}}else if(typeof t==="function"){return t(e)}else{return t}};return this._refinement(((t,s)=>{const r=e(t);const setError=()=>s.addIssue({code:i.ZodIssueCode.custom,...getIssueProperties(t)});if(typeof Promise!=="undefined"&&r instanceof Promise){return r.then((e=>{if(!e){setError();return false}else{return true}}))}if(!r){setError();return false}else{return true}}))}refinement(e,t){return this._refinement(((s,r)=>{if(!e(s)){r.addIssue(typeof t==="function"?t(s,r):t);return false}else{return true}}))}_refinement(e){return new ZodEffects({schema:this,typeName:y.ZodEffects,effect:{type:"refinement",refinement:e}})}superRefine(e){return this._refinement(e)}optional(){return ZodOptional.create(this,this._def)}nullable(){return ZodNullable.create(this,this._def)}nullish(){return this.nullable().optional()}array(){return ZodArray.create(this,this._def)}promise(){return ZodPromise.create(this,this._def)}or(e){return ZodUnion.create([this,e],this._def)}and(e){return ZodIntersection.create(this,e,this._def)}transform(e){return new ZodEffects({...processCreateParams(this._def),schema:this,typeName:y.ZodEffects,effect:{type:"transform",transform:e}})}default(e){const t=typeof e==="function"?e:()=>e;return new ZodDefault({...processCreateParams(this._def),innerType:this,defaultValue:t,typeName:y.ZodDefault})}brand(){return new ZodBranded({typeName:y.ZodBranded,type:this,...processCreateParams(this._def)})}catch(e){const t=typeof e==="function"?e:()=>e;return new ZodCatch({...processCreateParams(this._def),innerType:this,catchValue:t,typeName:y.ZodCatch})}describe(e){const t=this.constructor;return new t({...this._def,description:e})}pipe(e){return ZodPipeline.create(this,e)}readonly(){return ZodReadonly.create(this)}isOptional(){return this.safeParse(undefined).success}isNullable(){return this.safeParse(null).success}}t.ZodType=ZodType;t.Schema=ZodType;t.ZodSchema=ZodType;const d=/^c[^\s-]{8,}$/i;const u=/^[a-z][a-z0-9]*$/;const c=/[0-9A-HJKMNP-TV-Z]{26}/;const l=/^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/i;const p=/^(?!\.)(?!.*\.\.)([A-Z0-9_+-\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i;const f=/^(\p{Extended_Pictographic}|\p{Emoji_Component})+$/u;const h=/^(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))$/;const m=/^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/;const datetimeRegex=e=>{if(e.precision){if(e.offset){return new RegExp(`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{${e.precision}}(([+-]\\d{2}(:?\\d{2})?)|Z)$`)}else{return new RegExp(`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{${e.precision}}Z$`)}}else if(e.precision===0){if(e.offset){return new RegExp(`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(([+-]\\d{2}(:?\\d{2})?)|Z)$`)}else{return new RegExp(`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$`)}}else{if(e.offset){return new RegExp(`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(([+-]\\d{2}(:?\\d{2})?)|Z)$`)}else{return new RegExp(`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?Z$`)}}};function isValidIP(e,t){if((t==="v4"||!t)&&h.test(e)){return true}if((t==="v6"||!t)&&m.test(e)){return true}return false}class ZodString extends ZodType{constructor(){super(...arguments);this._regex=(e,t,s)=>this.refinement((t=>e.test(t)),{validation:t,code:i.ZodIssueCode.invalid_string,...a.errorUtil.errToObj(s)});this.nonempty=e=>this.min(1,a.errorUtil.errToObj(e));this.trim=()=>new ZodString({...this._def,checks:[...this._def.checks,{kind:"trim"}]});this.toLowerCase=()=>new ZodString({...this._def,checks:[...this._def.checks,{kind:"toLowerCase"}]});this.toUpperCase=()=>new ZodString({...this._def,checks:[...this._def.checks,{kind:"toUpperCase"}]})}_parse(e){if(this._def.coerce){e.data=String(e.data)}const t=this._getType(e);if(t!==o.ZodParsedType.string){const t=this._getOrReturnCtx(e);(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.string,received:t.parsedType});return n.INVALID}const s=new n.ParseStatus;let r=undefined;for(const t of this._def.checks){if(t.kind==="min"){if(e.data.lengtht.value){r=this._getOrReturnCtx(e,r);(0,n.addIssueToContext)(r,{code:i.ZodIssueCode.too_big,maximum:t.value,type:"string",inclusive:true,exact:false,message:t.message});s.dirty()}}else if(t.kind==="length"){const a=e.data.length>t.value;const o=e.data.lengthe.kind==="datetime"))}get isEmail(){return!!this._def.checks.find((e=>e.kind==="email"))}get isURL(){return!!this._def.checks.find((e=>e.kind==="url"))}get isEmoji(){return!!this._def.checks.find((e=>e.kind==="emoji"))}get isUUID(){return!!this._def.checks.find((e=>e.kind==="uuid"))}get isCUID(){return!!this._def.checks.find((e=>e.kind==="cuid"))}get isCUID2(){return!!this._def.checks.find((e=>e.kind==="cuid2"))}get isULID(){return!!this._def.checks.find((e=>e.kind==="ulid"))}get isIP(){return!!this._def.checks.find((e=>e.kind==="ip"))}get minLength(){let e=null;for(const t of this._def.checks){if(t.kind==="min"){if(e===null||t.value>e)e=t.value}}return e}get maxLength(){let e=null;for(const t of this._def.checks){if(t.kind==="max"){if(e===null||t.value{var t;return new ZodString({checks:[],typeName:y.ZodString,coerce:(t=e===null||e===void 0?void 0:e.coerce)!==null&&t!==void 0?t:false,...processCreateParams(e)})};function floatSafeRemainder(e,t){const s=(e.toString().split(".")[1]||"").length;const r=(t.toString().split(".")[1]||"").length;const a=s>r?s:r;const n=parseInt(e.toFixed(a).replace(".",""));const o=parseInt(t.toFixed(a).replace(".",""));return n%o/Math.pow(10,a)}class ZodNumber extends ZodType{constructor(){super(...arguments);this.min=this.gte;this.max=this.lte;this.step=this.multipleOf}_parse(e){if(this._def.coerce){e.data=Number(e.data)}const t=this._getType(e);if(t!==o.ZodParsedType.number){const t=this._getOrReturnCtx(e);(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.number,received:t.parsedType});return n.INVALID}let s=undefined;const r=new n.ParseStatus;for(const t of this._def.checks){if(t.kind==="int"){if(!o.util.isInteger(e.data)){s=this._getOrReturnCtx(e,s);(0,n.addIssueToContext)(s,{code:i.ZodIssueCode.invalid_type,expected:"integer",received:"float",message:t.message});r.dirty()}}else if(t.kind==="min"){const a=t.inclusive?e.datat.value:e.data>=t.value;if(a){s=this._getOrReturnCtx(e,s);(0,n.addIssueToContext)(s,{code:i.ZodIssueCode.too_big,maximum:t.value,type:"number",inclusive:t.inclusive,exact:false,message:t.message});r.dirty()}}else if(t.kind==="multipleOf"){if(floatSafeRemainder(e.data,t.value)!==0){s=this._getOrReturnCtx(e,s);(0,n.addIssueToContext)(s,{code:i.ZodIssueCode.not_multiple_of,multipleOf:t.value,message:t.message});r.dirty()}}else if(t.kind==="finite"){if(!Number.isFinite(e.data)){s=this._getOrReturnCtx(e,s);(0,n.addIssueToContext)(s,{code:i.ZodIssueCode.not_finite,message:t.message});r.dirty()}}else{o.util.assertNever(t)}}return{status:r.value,value:e.data}}gte(e,t){return this.setLimit("min",e,true,a.errorUtil.toString(t))}gt(e,t){return this.setLimit("min",e,false,a.errorUtil.toString(t))}lte(e,t){return this.setLimit("max",e,true,a.errorUtil.toString(t))}lt(e,t){return this.setLimit("max",e,false,a.errorUtil.toString(t))}setLimit(e,t,s,r){return new ZodNumber({...this._def,checks:[...this._def.checks,{kind:e,value:t,inclusive:s,message:a.errorUtil.toString(r)}]})}_addCheck(e){return new ZodNumber({...this._def,checks:[...this._def.checks,e]})}int(e){return this._addCheck({kind:"int",message:a.errorUtil.toString(e)})}positive(e){return this._addCheck({kind:"min",value:0,inclusive:false,message:a.errorUtil.toString(e)})}negative(e){return this._addCheck({kind:"max",value:0,inclusive:false,message:a.errorUtil.toString(e)})}nonpositive(e){return this._addCheck({kind:"max",value:0,inclusive:true,message:a.errorUtil.toString(e)})}nonnegative(e){return this._addCheck({kind:"min",value:0,inclusive:true,message:a.errorUtil.toString(e)})}multipleOf(e,t){return this._addCheck({kind:"multipleOf",value:e,message:a.errorUtil.toString(t)})}finite(e){return this._addCheck({kind:"finite",message:a.errorUtil.toString(e)})}safe(e){return this._addCheck({kind:"min",inclusive:true,value:Number.MIN_SAFE_INTEGER,message:a.errorUtil.toString(e)})._addCheck({kind:"max",inclusive:true,value:Number.MAX_SAFE_INTEGER,message:a.errorUtil.toString(e)})}get minValue(){let e=null;for(const t of this._def.checks){if(t.kind==="min"){if(e===null||t.value>e)e=t.value}}return e}get maxValue(){let e=null;for(const t of this._def.checks){if(t.kind==="max"){if(e===null||t.valuee.kind==="int"||e.kind==="multipleOf"&&o.util.isInteger(e.value)))}get isFinite(){let e=null,t=null;for(const s of this._def.checks){if(s.kind==="finite"||s.kind==="int"||s.kind==="multipleOf"){return true}else if(s.kind==="min"){if(t===null||s.value>t)t=s.value}else if(s.kind==="max"){if(e===null||s.valuenew ZodNumber({checks:[],typeName:y.ZodNumber,coerce:(e===null||e===void 0?void 0:e.coerce)||false,...processCreateParams(e)});class ZodBigInt extends ZodType{constructor(){super(...arguments);this.min=this.gte;this.max=this.lte}_parse(e){if(this._def.coerce){e.data=BigInt(e.data)}const t=this._getType(e);if(t!==o.ZodParsedType.bigint){const t=this._getOrReturnCtx(e);(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.bigint,received:t.parsedType});return n.INVALID}let s=undefined;const r=new n.ParseStatus;for(const t of this._def.checks){if(t.kind==="min"){const a=t.inclusive?e.datat.value:e.data>=t.value;if(a){s=this._getOrReturnCtx(e,s);(0,n.addIssueToContext)(s,{code:i.ZodIssueCode.too_big,type:"bigint",maximum:t.value,inclusive:t.inclusive,message:t.message});r.dirty()}}else if(t.kind==="multipleOf"){if(e.data%t.value!==BigInt(0)){s=this._getOrReturnCtx(e,s);(0,n.addIssueToContext)(s,{code:i.ZodIssueCode.not_multiple_of,multipleOf:t.value,message:t.message});r.dirty()}}else{o.util.assertNever(t)}}return{status:r.value,value:e.data}}gte(e,t){return this.setLimit("min",e,true,a.errorUtil.toString(t))}gt(e,t){return this.setLimit("min",e,false,a.errorUtil.toString(t))}lte(e,t){return this.setLimit("max",e,true,a.errorUtil.toString(t))}lt(e,t){return this.setLimit("max",e,false,a.errorUtil.toString(t))}setLimit(e,t,s,r){return new ZodBigInt({...this._def,checks:[...this._def.checks,{kind:e,value:t,inclusive:s,message:a.errorUtil.toString(r)}]})}_addCheck(e){return new ZodBigInt({...this._def,checks:[...this._def.checks,e]})}positive(e){return this._addCheck({kind:"min",value:BigInt(0),inclusive:false,message:a.errorUtil.toString(e)})}negative(e){return this._addCheck({kind:"max",value:BigInt(0),inclusive:false,message:a.errorUtil.toString(e)})}nonpositive(e){return this._addCheck({kind:"max",value:BigInt(0),inclusive:true,message:a.errorUtil.toString(e)})}nonnegative(e){return this._addCheck({kind:"min",value:BigInt(0),inclusive:true,message:a.errorUtil.toString(e)})}multipleOf(e,t){return this._addCheck({kind:"multipleOf",value:e,message:a.errorUtil.toString(t)})}get minValue(){let e=null;for(const t of this._def.checks){if(t.kind==="min"){if(e===null||t.value>e)e=t.value}}return e}get maxValue(){let e=null;for(const t of this._def.checks){if(t.kind==="max"){if(e===null||t.value{var t;return new ZodBigInt({checks:[],typeName:y.ZodBigInt,coerce:(t=e===null||e===void 0?void 0:e.coerce)!==null&&t!==void 0?t:false,...processCreateParams(e)})};class ZodBoolean extends ZodType{_parse(e){if(this._def.coerce){e.data=Boolean(e.data)}const t=this._getType(e);if(t!==o.ZodParsedType.boolean){const t=this._getOrReturnCtx(e);(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.boolean,received:t.parsedType});return n.INVALID}return(0,n.OK)(e.data)}}t.ZodBoolean=ZodBoolean;ZodBoolean.create=e=>new ZodBoolean({typeName:y.ZodBoolean,coerce:(e===null||e===void 0?void 0:e.coerce)||false,...processCreateParams(e)});class ZodDate extends ZodType{_parse(e){if(this._def.coerce){e.data=new Date(e.data)}const t=this._getType(e);if(t!==o.ZodParsedType.date){const t=this._getOrReturnCtx(e);(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.date,received:t.parsedType});return n.INVALID}if(isNaN(e.data.getTime())){const t=this._getOrReturnCtx(e);(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_date});return n.INVALID}const s=new n.ParseStatus;let r=undefined;for(const t of this._def.checks){if(t.kind==="min"){if(e.data.getTime()t.value){r=this._getOrReturnCtx(e,r);(0,n.addIssueToContext)(r,{code:i.ZodIssueCode.too_big,message:t.message,inclusive:true,exact:false,maximum:t.value,type:"date"});s.dirty()}}else{o.util.assertNever(t)}}return{status:s.value,value:new Date(e.data.getTime())}}_addCheck(e){return new ZodDate({...this._def,checks:[...this._def.checks,e]})}min(e,t){return this._addCheck({kind:"min",value:e.getTime(),message:a.errorUtil.toString(t)})}max(e,t){return this._addCheck({kind:"max",value:e.getTime(),message:a.errorUtil.toString(t)})}get minDate(){let e=null;for(const t of this._def.checks){if(t.kind==="min"){if(e===null||t.value>e)e=t.value}}return e!=null?new Date(e):null}get maxDate(){let e=null;for(const t of this._def.checks){if(t.kind==="max"){if(e===null||t.valuenew ZodDate({checks:[],coerce:(e===null||e===void 0?void 0:e.coerce)||false,typeName:y.ZodDate,...processCreateParams(e)});class ZodSymbol extends ZodType{_parse(e){const t=this._getType(e);if(t!==o.ZodParsedType.symbol){const t=this._getOrReturnCtx(e);(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.symbol,received:t.parsedType});return n.INVALID}return(0,n.OK)(e.data)}}t.ZodSymbol=ZodSymbol;ZodSymbol.create=e=>new ZodSymbol({typeName:y.ZodSymbol,...processCreateParams(e)});class ZodUndefined extends ZodType{_parse(e){const t=this._getType(e);if(t!==o.ZodParsedType.undefined){const t=this._getOrReturnCtx(e);(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.undefined,received:t.parsedType});return n.INVALID}return(0,n.OK)(e.data)}}t.ZodUndefined=ZodUndefined;ZodUndefined.create=e=>new ZodUndefined({typeName:y.ZodUndefined,...processCreateParams(e)});class ZodNull extends ZodType{_parse(e){const t=this._getType(e);if(t!==o.ZodParsedType.null){const t=this._getOrReturnCtx(e);(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.null,received:t.parsedType});return n.INVALID}return(0,n.OK)(e.data)}}t.ZodNull=ZodNull;ZodNull.create=e=>new ZodNull({typeName:y.ZodNull,...processCreateParams(e)});class ZodAny extends ZodType{constructor(){super(...arguments);this._any=true}_parse(e){return(0,n.OK)(e.data)}}t.ZodAny=ZodAny;ZodAny.create=e=>new ZodAny({typeName:y.ZodAny,...processCreateParams(e)});class ZodUnknown extends ZodType{constructor(){super(...arguments);this._unknown=true}_parse(e){return(0,n.OK)(e.data)}}t.ZodUnknown=ZodUnknown;ZodUnknown.create=e=>new ZodUnknown({typeName:y.ZodUnknown,...processCreateParams(e)});class ZodNever extends ZodType{_parse(e){const t=this._getOrReturnCtx(e);(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.never,received:t.parsedType});return n.INVALID}}t.ZodNever=ZodNever;ZodNever.create=e=>new ZodNever({typeName:y.ZodNever,...processCreateParams(e)});class ZodVoid extends ZodType{_parse(e){const t=this._getType(e);if(t!==o.ZodParsedType.undefined){const t=this._getOrReturnCtx(e);(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.void,received:t.parsedType});return n.INVALID}return(0,n.OK)(e.data)}}t.ZodVoid=ZodVoid;ZodVoid.create=e=>new ZodVoid({typeName:y.ZodVoid,...processCreateParams(e)});class ZodArray extends ZodType{_parse(e){const{ctx:t,status:s}=this._processInputParams(e);const r=this._def;if(t.parsedType!==o.ZodParsedType.array){(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.array,received:t.parsedType});return n.INVALID}if(r.exactLength!==null){const e=t.data.length>r.exactLength.value;const a=t.data.lengthr.maxLength.value){(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.too_big,maximum:r.maxLength.value,type:"array",inclusive:true,exact:false,message:r.maxLength.message});s.dirty()}}if(t.common.async){return Promise.all([...t.data].map(((e,s)=>r.type._parseAsync(new ParseInputLazyPath(t,e,t.path,s))))).then((e=>n.ParseStatus.mergeArray(s,e)))}const a=[...t.data].map(((e,s)=>r.type._parseSync(new ParseInputLazyPath(t,e,t.path,s))));return n.ParseStatus.mergeArray(s,a)}get element(){return this._def.type}min(e,t){return new ZodArray({...this._def,minLength:{value:e,message:a.errorUtil.toString(t)}})}max(e,t){return new ZodArray({...this._def,maxLength:{value:e,message:a.errorUtil.toString(t)}})}length(e,t){return new ZodArray({...this._def,exactLength:{value:e,message:a.errorUtil.toString(t)}})}nonempty(e){return this.min(1,e)}}t.ZodArray=ZodArray;ZodArray.create=(e,t)=>new ZodArray({type:e,minLength:null,maxLength:null,exactLength:null,typeName:y.ZodArray,...processCreateParams(t)});function deepPartialify(e){if(e instanceof ZodObject){const t={};for(const s in e.shape){const r=e.shape[s];t[s]=ZodOptional.create(deepPartialify(r))}return new ZodObject({...e._def,shape:()=>t})}else if(e instanceof ZodArray){return new ZodArray({...e._def,type:deepPartialify(e.element)})}else if(e instanceof ZodOptional){return ZodOptional.create(deepPartialify(e.unwrap()))}else if(e instanceof ZodNullable){return ZodNullable.create(deepPartialify(e.unwrap()))}else if(e instanceof ZodTuple){return ZodTuple.create(e.items.map((e=>deepPartialify(e))))}else{return e}}class ZodObject extends ZodType{constructor(){super(...arguments);this._cached=null;this.nonstrict=this.passthrough;this.augment=this.extend}_getCached(){if(this._cached!==null)return this._cached;const e=this._def.shape();const t=o.util.objectKeys(e);return this._cached={shape:e,keys:t}}_parse(e){const t=this._getType(e);if(t!==o.ZodParsedType.object){const t=this._getOrReturnCtx(e);(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.object,received:t.parsedType});return n.INVALID}const{status:s,ctx:r}=this._processInputParams(e);const{shape:a,keys:d}=this._getCached();const u=[];if(!(this._def.catchall instanceof ZodNever&&this._def.unknownKeys==="strip")){for(const e in r.data){if(!d.includes(e)){u.push(e)}}}const c=[];for(const e of d){const t=a[e];const s=r.data[e];c.push({key:{status:"valid",value:e},value:t._parse(new ParseInputLazyPath(r,s,r.path,e)),alwaysSet:e in r.data})}if(this._def.catchall instanceof ZodNever){const e=this._def.unknownKeys;if(e==="passthrough"){for(const e of u){c.push({key:{status:"valid",value:e},value:{status:"valid",value:r.data[e]}})}}else if(e==="strict"){if(u.length>0){(0,n.addIssueToContext)(r,{code:i.ZodIssueCode.unrecognized_keys,keys:u});s.dirty()}}else if(e==="strip"){}else{throw new Error(`Internal ZodObject error: invalid unknownKeys value.`)}}else{const e=this._def.catchall;for(const t of u){const s=r.data[t];c.push({key:{status:"valid",value:t},value:e._parse(new ParseInputLazyPath(r,s,r.path,t)),alwaysSet:t in r.data})}}if(r.common.async){return Promise.resolve().then((async()=>{const e=[];for(const t of c){const s=await t.key;e.push({key:s,value:await t.value,alwaysSet:t.alwaysSet})}return e})).then((e=>n.ParseStatus.mergeObjectSync(s,e)))}else{return n.ParseStatus.mergeObjectSync(s,c)}}get shape(){return this._def.shape()}strict(e){a.errorUtil.errToObj;return new ZodObject({...this._def,unknownKeys:"strict",...e!==undefined?{errorMap:(t,s)=>{var r,n,o,i;const d=(o=(n=(r=this._def).errorMap)===null||n===void 0?void 0:n.call(r,t,s).message)!==null&&o!==void 0?o:s.defaultError;if(t.code==="unrecognized_keys")return{message:(i=a.errorUtil.errToObj(e).message)!==null&&i!==void 0?i:d};return{message:d}}}:{}})}strip(){return new ZodObject({...this._def,unknownKeys:"strip"})}passthrough(){return new ZodObject({...this._def,unknownKeys:"passthrough"})}extend(e){return new ZodObject({...this._def,shape:()=>({...this._def.shape(),...e})})}merge(e){const t=new ZodObject({unknownKeys:e._def.unknownKeys,catchall:e._def.catchall,shape:()=>({...this._def.shape(),...e._def.shape()}),typeName:y.ZodObject});return t}setKey(e,t){return this.augment({[e]:t})}catchall(e){return new ZodObject({...this._def,catchall:e})}pick(e){const t={};o.util.objectKeys(e).forEach((s=>{if(e[s]&&this.shape[s]){t[s]=this.shape[s]}}));return new ZodObject({...this._def,shape:()=>t})}omit(e){const t={};o.util.objectKeys(this.shape).forEach((s=>{if(!e[s]){t[s]=this.shape[s]}}));return new ZodObject({...this._def,shape:()=>t})}deepPartial(){return deepPartialify(this)}partial(e){const t={};o.util.objectKeys(this.shape).forEach((s=>{const r=this.shape[s];if(e&&!e[s]){t[s]=r}else{t[s]=r.optional()}}));return new ZodObject({...this._def,shape:()=>t})}required(e){const t={};o.util.objectKeys(this.shape).forEach((s=>{if(e&&!e[s]){t[s]=this.shape[s]}else{const e=this.shape[s];let r=e;while(r instanceof ZodOptional){r=r._def.innerType}t[s]=r}}));return new ZodObject({...this._def,shape:()=>t})}keyof(){return createZodEnum(o.util.objectKeys(this.shape))}}t.ZodObject=ZodObject;ZodObject.create=(e,t)=>new ZodObject({shape:()=>e,unknownKeys:"strip",catchall:ZodNever.create(),typeName:y.ZodObject,...processCreateParams(t)});ZodObject.strictCreate=(e,t)=>new ZodObject({shape:()=>e,unknownKeys:"strict",catchall:ZodNever.create(),typeName:y.ZodObject,...processCreateParams(t)});ZodObject.lazycreate=(e,t)=>new ZodObject({shape:e,unknownKeys:"strip",catchall:ZodNever.create(),typeName:y.ZodObject,...processCreateParams(t)});class ZodUnion extends ZodType{_parse(e){const{ctx:t}=this._processInputParams(e);const s=this._def.options;function handleResults(e){for(const t of e){if(t.result.status==="valid"){return t.result}}for(const s of e){if(s.result.status==="dirty"){t.common.issues.push(...s.ctx.common.issues);return s.result}}const s=e.map((e=>new i.ZodError(e.ctx.common.issues)));(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_union,unionErrors:s});return n.INVALID}if(t.common.async){return Promise.all(s.map((async e=>{const s={...t,common:{...t.common,issues:[]},parent:null};return{result:await e._parseAsync({data:t.data,path:t.path,parent:s}),ctx:s}}))).then(handleResults)}else{let e=undefined;const r=[];for(const a of s){const s={...t,common:{...t.common,issues:[]},parent:null};const n=a._parseSync({data:t.data,path:t.path,parent:s});if(n.status==="valid"){return n}else if(n.status==="dirty"&&!e){e={result:n,ctx:s}}if(s.common.issues.length){r.push(s.common.issues)}}if(e){t.common.issues.push(...e.ctx.common.issues);return e.result}const a=r.map((e=>new i.ZodError(e)));(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_union,unionErrors:a});return n.INVALID}}get options(){return this._def.options}}t.ZodUnion=ZodUnion;ZodUnion.create=(e,t)=>new ZodUnion({options:e,typeName:y.ZodUnion,...processCreateParams(t)});const getDiscriminator=e=>{if(e instanceof ZodLazy){return getDiscriminator(e.schema)}else if(e instanceof ZodEffects){return getDiscriminator(e.innerType())}else if(e instanceof ZodLiteral){return[e.value]}else if(e instanceof ZodEnum){return e.options}else if(e instanceof ZodNativeEnum){return Object.keys(e.enum)}else if(e instanceof ZodDefault){return getDiscriminator(e._def.innerType)}else if(e instanceof ZodUndefined){return[undefined]}else if(e instanceof ZodNull){return[null]}else{return null}};class ZodDiscriminatedUnion extends ZodType{_parse(e){const{ctx:t}=this._processInputParams(e);if(t.parsedType!==o.ZodParsedType.object){(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.object,received:t.parsedType});return n.INVALID}const s=this.discriminator;const r=t.data[s];const a=this.optionsMap.get(r);if(!a){(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_union_discriminator,options:Array.from(this.optionsMap.keys()),path:[s]});return n.INVALID}if(t.common.async){return a._parseAsync({data:t.data,path:t.path,parent:t})}else{return a._parseSync({data:t.data,path:t.path,parent:t})}}get discriminator(){return this._def.discriminator}get options(){return this._def.options}get optionsMap(){return this._def.optionsMap}static create(e,t,s){const r=new Map;for(const s of t){const t=getDiscriminator(s.shape[e]);if(!t){throw new Error(`A discriminator value for key \`${e}\` could not be extracted from all schema options`)}for(const a of t){if(r.has(a)){throw new Error(`Discriminator property ${String(e)} has duplicate value ${String(a)}`)}r.set(a,s)}}return new ZodDiscriminatedUnion({typeName:y.ZodDiscriminatedUnion,discriminator:e,options:t,optionsMap:r,...processCreateParams(s)})}}t.ZodDiscriminatedUnion=ZodDiscriminatedUnion;function mergeValues(e,t){const s=(0,o.getParsedType)(e);const r=(0,o.getParsedType)(t);if(e===t){return{valid:true,data:e}}else if(s===o.ZodParsedType.object&&r===o.ZodParsedType.object){const s=o.util.objectKeys(t);const r=o.util.objectKeys(e).filter((e=>s.indexOf(e)!==-1));const a={...e,...t};for(const s of r){const r=mergeValues(e[s],t[s]);if(!r.valid){return{valid:false}}a[s]=r.data}return{valid:true,data:a}}else if(s===o.ZodParsedType.array&&r===o.ZodParsedType.array){if(e.length!==t.length){return{valid:false}}const s=[];for(let r=0;r{if((0,n.isAborted)(e)||(0,n.isAborted)(r)){return n.INVALID}const a=mergeValues(e.value,r.value);if(!a.valid){(0,n.addIssueToContext)(s,{code:i.ZodIssueCode.invalid_intersection_types});return n.INVALID}if((0,n.isDirty)(e)||(0,n.isDirty)(r)){t.dirty()}return{status:t.value,value:a.data}};if(s.common.async){return Promise.all([this._def.left._parseAsync({data:s.data,path:s.path,parent:s}),this._def.right._parseAsync({data:s.data,path:s.path,parent:s})]).then((([e,t])=>handleParsed(e,t)))}else{return handleParsed(this._def.left._parseSync({data:s.data,path:s.path,parent:s}),this._def.right._parseSync({data:s.data,path:s.path,parent:s}))}}}t.ZodIntersection=ZodIntersection;ZodIntersection.create=(e,t,s)=>new ZodIntersection({left:e,right:t,typeName:y.ZodIntersection,...processCreateParams(s)});class ZodTuple extends ZodType{_parse(e){const{status:t,ctx:s}=this._processInputParams(e);if(s.parsedType!==o.ZodParsedType.array){(0,n.addIssueToContext)(s,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.array,received:s.parsedType});return n.INVALID}if(s.data.lengththis._def.items.length){(0,n.addIssueToContext)(s,{code:i.ZodIssueCode.too_big,maximum:this._def.items.length,inclusive:true,exact:false,type:"array"});t.dirty()}const a=[...s.data].map(((e,t)=>{const r=this._def.items[t]||this._def.rest;if(!r)return null;return r._parse(new ParseInputLazyPath(s,e,s.path,t))})).filter((e=>!!e));if(s.common.async){return Promise.all(a).then((e=>n.ParseStatus.mergeArray(t,e)))}else{return n.ParseStatus.mergeArray(t,a)}}get items(){return this._def.items}rest(e){return new ZodTuple({...this._def,rest:e})}}t.ZodTuple=ZodTuple;ZodTuple.create=(e,t)=>{if(!Array.isArray(e)){throw new Error("You must pass an array of schemas to z.tuple([ ... ])")}return new ZodTuple({items:e,typeName:y.ZodTuple,rest:null,...processCreateParams(t)})};class ZodRecord extends ZodType{get keySchema(){return this._def.keyType}get valueSchema(){return this._def.valueType}_parse(e){const{status:t,ctx:s}=this._processInputParams(e);if(s.parsedType!==o.ZodParsedType.object){(0,n.addIssueToContext)(s,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.object,received:s.parsedType});return n.INVALID}const r=[];const a=this._def.keyType;const d=this._def.valueType;for(const e in s.data){r.push({key:a._parse(new ParseInputLazyPath(s,e,s.path,e)),value:d._parse(new ParseInputLazyPath(s,s.data[e],s.path,e))})}if(s.common.async){return n.ParseStatus.mergeObjectAsync(t,r)}else{return n.ParseStatus.mergeObjectSync(t,r)}}get element(){return this._def.valueType}static create(e,t,s){if(t instanceof ZodType){return new ZodRecord({keyType:e,valueType:t,typeName:y.ZodRecord,...processCreateParams(s)})}return new ZodRecord({keyType:ZodString.create(),valueType:e,typeName:y.ZodRecord,...processCreateParams(t)})}}t.ZodRecord=ZodRecord;class ZodMap extends ZodType{get keySchema(){return this._def.keyType}get valueSchema(){return this._def.valueType}_parse(e){const{status:t,ctx:s}=this._processInputParams(e);if(s.parsedType!==o.ZodParsedType.map){(0,n.addIssueToContext)(s,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.map,received:s.parsedType});return n.INVALID}const r=this._def.keyType;const a=this._def.valueType;const d=[...s.data.entries()].map((([e,t],n)=>({key:r._parse(new ParseInputLazyPath(s,e,s.path,[n,"key"])),value:a._parse(new ParseInputLazyPath(s,t,s.path,[n,"value"]))})));if(s.common.async){const e=new Map;return Promise.resolve().then((async()=>{for(const s of d){const r=await s.key;const a=await s.value;if(r.status==="aborted"||a.status==="aborted"){return n.INVALID}if(r.status==="dirty"||a.status==="dirty"){t.dirty()}e.set(r.value,a.value)}return{status:t.value,value:e}}))}else{const e=new Map;for(const s of d){const r=s.key;const a=s.value;if(r.status==="aborted"||a.status==="aborted"){return n.INVALID}if(r.status==="dirty"||a.status==="dirty"){t.dirty()}e.set(r.value,a.value)}return{status:t.value,value:e}}}}t.ZodMap=ZodMap;ZodMap.create=(e,t,s)=>new ZodMap({valueType:t,keyType:e,typeName:y.ZodMap,...processCreateParams(s)});class ZodSet extends ZodType{_parse(e){const{status:t,ctx:s}=this._processInputParams(e);if(s.parsedType!==o.ZodParsedType.set){(0,n.addIssueToContext)(s,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.set,received:s.parsedType});return n.INVALID}const r=this._def;if(r.minSize!==null){if(s.data.sizer.maxSize.value){(0,n.addIssueToContext)(s,{code:i.ZodIssueCode.too_big,maximum:r.maxSize.value,type:"set",inclusive:true,exact:false,message:r.maxSize.message});t.dirty()}}const a=this._def.valueType;function finalizeSet(e){const s=new Set;for(const r of e){if(r.status==="aborted")return n.INVALID;if(r.status==="dirty")t.dirty();s.add(r.value)}return{status:t.value,value:s}}const d=[...s.data.values()].map(((e,t)=>a._parse(new ParseInputLazyPath(s,e,s.path,t))));if(s.common.async){return Promise.all(d).then((e=>finalizeSet(e)))}else{return finalizeSet(d)}}min(e,t){return new ZodSet({...this._def,minSize:{value:e,message:a.errorUtil.toString(t)}})}max(e,t){return new ZodSet({...this._def,maxSize:{value:e,message:a.errorUtil.toString(t)}})}size(e,t){return this.min(e,t).max(e,t)}nonempty(e){return this.min(1,e)}}t.ZodSet=ZodSet;ZodSet.create=(e,t)=>new ZodSet({valueType:e,minSize:null,maxSize:null,typeName:y.ZodSet,...processCreateParams(t)});class ZodFunction extends ZodType{constructor(){super(...arguments);this.validate=this.implement}_parse(e){const{ctx:t}=this._processInputParams(e);if(t.parsedType!==o.ZodParsedType.function){(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.function,received:t.parsedType});return n.INVALID}function makeArgsIssue(e,s){return(0,n.makeIssue)({data:e,path:t.path,errorMaps:[t.common.contextualErrorMap,t.schemaErrorMap,(0,r.getErrorMap)(),r.defaultErrorMap].filter((e=>!!e)),issueData:{code:i.ZodIssueCode.invalid_arguments,argumentsError:s}})}function makeReturnsIssue(e,s){return(0,n.makeIssue)({data:e,path:t.path,errorMaps:[t.common.contextualErrorMap,t.schemaErrorMap,(0,r.getErrorMap)(),r.defaultErrorMap].filter((e=>!!e)),issueData:{code:i.ZodIssueCode.invalid_return_type,returnTypeError:s}})}const s={errorMap:t.common.contextualErrorMap};const a=t.data;if(this._def.returns instanceof ZodPromise){const e=this;return(0,n.OK)((async function(...t){const r=new i.ZodError([]);const n=await e._def.args.parseAsync(t,s).catch((e=>{r.addIssue(makeArgsIssue(t,e));throw r}));const o=await Reflect.apply(a,this,n);const d=await e._def.returns._def.type.parseAsync(o,s).catch((e=>{r.addIssue(makeReturnsIssue(o,e));throw r}));return d}))}else{const e=this;return(0,n.OK)((function(...t){const r=e._def.args.safeParse(t,s);if(!r.success){throw new i.ZodError([makeArgsIssue(t,r.error)])}const n=Reflect.apply(a,this,r.data);const o=e._def.returns.safeParse(n,s);if(!o.success){throw new i.ZodError([makeReturnsIssue(n,o.error)])}return o.data}))}}parameters(){return this._def.args}returnType(){return this._def.returns}args(...e){return new ZodFunction({...this._def,args:ZodTuple.create(e).rest(ZodUnknown.create())})}returns(e){return new ZodFunction({...this._def,returns:e})}implement(e){const t=this.parse(e);return t}strictImplement(e){const t=this.parse(e);return t}static create(e,t,s){return new ZodFunction({args:e?e:ZodTuple.create([]).rest(ZodUnknown.create()),returns:t||ZodUnknown.create(),typeName:y.ZodFunction,...processCreateParams(s)})}}t.ZodFunction=ZodFunction;class ZodLazy extends ZodType{get schema(){return this._def.getter()}_parse(e){const{ctx:t}=this._processInputParams(e);const s=this._def.getter();return s._parse({data:t.data,path:t.path,parent:t})}}t.ZodLazy=ZodLazy;ZodLazy.create=(e,t)=>new ZodLazy({getter:e,typeName:y.ZodLazy,...processCreateParams(t)});class ZodLiteral extends ZodType{_parse(e){if(e.data!==this._def.value){const t=this._getOrReturnCtx(e);(0,n.addIssueToContext)(t,{received:t.data,code:i.ZodIssueCode.invalid_literal,expected:this._def.value});return n.INVALID}return{status:"valid",value:e.data}}get value(){return this._def.value}}t.ZodLiteral=ZodLiteral;ZodLiteral.create=(e,t)=>new ZodLiteral({value:e,typeName:y.ZodLiteral,...processCreateParams(t)});function createZodEnum(e,t){return new ZodEnum({values:e,typeName:y.ZodEnum,...processCreateParams(t)})}class ZodEnum extends ZodType{_parse(e){if(typeof e.data!=="string"){const t=this._getOrReturnCtx(e);const s=this._def.values;(0,n.addIssueToContext)(t,{expected:o.util.joinValues(s),received:t.parsedType,code:i.ZodIssueCode.invalid_type});return n.INVALID}if(this._def.values.indexOf(e.data)===-1){const t=this._getOrReturnCtx(e);const s=this._def.values;(0,n.addIssueToContext)(t,{received:t.data,code:i.ZodIssueCode.invalid_enum_value,options:s});return n.INVALID}return(0,n.OK)(e.data)}get options(){return this._def.values}get enum(){const e={};for(const t of this._def.values){e[t]=t}return e}get Values(){const e={};for(const t of this._def.values){e[t]=t}return e}get Enum(){const e={};for(const t of this._def.values){e[t]=t}return e}extract(e){return ZodEnum.create(e)}exclude(e){return ZodEnum.create(this.options.filter((t=>!e.includes(t))))}}t.ZodEnum=ZodEnum;ZodEnum.create=createZodEnum;class ZodNativeEnum extends ZodType{_parse(e){const t=o.util.getValidEnumValues(this._def.values);const s=this._getOrReturnCtx(e);if(s.parsedType!==o.ZodParsedType.string&&s.parsedType!==o.ZodParsedType.number){const e=o.util.objectValues(t);(0,n.addIssueToContext)(s,{expected:o.util.joinValues(e),received:s.parsedType,code:i.ZodIssueCode.invalid_type});return n.INVALID}if(t.indexOf(e.data)===-1){const e=o.util.objectValues(t);(0,n.addIssueToContext)(s,{received:s.data,code:i.ZodIssueCode.invalid_enum_value,options:e});return n.INVALID}return(0,n.OK)(e.data)}get enum(){return this._def.values}}t.ZodNativeEnum=ZodNativeEnum;ZodNativeEnum.create=(e,t)=>new ZodNativeEnum({values:e,typeName:y.ZodNativeEnum,...processCreateParams(t)});class ZodPromise extends ZodType{unwrap(){return this._def.type}_parse(e){const{ctx:t}=this._processInputParams(e);if(t.parsedType!==o.ZodParsedType.promise&&t.common.async===false){(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.promise,received:t.parsedType});return n.INVALID}const s=t.parsedType===o.ZodParsedType.promise?t.data:Promise.resolve(t.data);return(0,n.OK)(s.then((e=>this._def.type.parseAsync(e,{path:t.path,errorMap:t.common.contextualErrorMap}))))}}t.ZodPromise=ZodPromise;ZodPromise.create=(e,t)=>new ZodPromise({type:e,typeName:y.ZodPromise,...processCreateParams(t)});class ZodEffects extends ZodType{innerType(){return this._def.schema}sourceType(){return this._def.schema._def.typeName===y.ZodEffects?this._def.schema.sourceType():this._def.schema}_parse(e){const{status:t,ctx:s}=this._processInputParams(e);const r=this._def.effect||null;const a={addIssue:e=>{(0,n.addIssueToContext)(s,e);if(e.fatal){t.abort()}else{t.dirty()}},get path(){return s.path}};a.addIssue=a.addIssue.bind(a);if(r.type==="preprocess"){const e=r.transform(s.data,a);if(s.common.issues.length){return{status:"dirty",value:s.data}}if(s.common.async){return Promise.resolve(e).then((e=>this._def.schema._parseAsync({data:e,path:s.path,parent:s})))}else{return this._def.schema._parseSync({data:e,path:s.path,parent:s})}}if(r.type==="refinement"){const executeRefinement=e=>{const t=r.refinement(e,a);if(s.common.async){return Promise.resolve(t)}if(t instanceof Promise){throw new Error("Async refinement encountered during synchronous parse operation. Use .parseAsync instead.")}return e};if(s.common.async===false){const e=this._def.schema._parseSync({data:s.data,path:s.path,parent:s});if(e.status==="aborted")return n.INVALID;if(e.status==="dirty")t.dirty();executeRefinement(e.value);return{status:t.value,value:e.value}}else{return this._def.schema._parseAsync({data:s.data,path:s.path,parent:s}).then((e=>{if(e.status==="aborted")return n.INVALID;if(e.status==="dirty")t.dirty();return executeRefinement(e.value).then((()=>({status:t.value,value:e.value})))}))}}if(r.type==="transform"){if(s.common.async===false){const e=this._def.schema._parseSync({data:s.data,path:s.path,parent:s});if(!(0,n.isValid)(e))return e;const o=r.transform(e.value,a);if(o instanceof Promise){throw new Error(`Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.`)}return{status:t.value,value:o}}else{return this._def.schema._parseAsync({data:s.data,path:s.path,parent:s}).then((e=>{if(!(0,n.isValid)(e))return e;return Promise.resolve(r.transform(e.value,a)).then((e=>({status:t.value,value:e})))}))}}o.util.assertNever(r)}}t.ZodEffects=ZodEffects;t.ZodTransformer=ZodEffects;ZodEffects.create=(e,t,s)=>new ZodEffects({schema:e,typeName:y.ZodEffects,effect:t,...processCreateParams(s)});ZodEffects.createWithPreprocess=(e,t,s)=>new ZodEffects({schema:t,effect:{type:"preprocess",transform:e},typeName:y.ZodEffects,...processCreateParams(s)});class ZodOptional extends ZodType{_parse(e){const t=this._getType(e);if(t===o.ZodParsedType.undefined){return(0,n.OK)(undefined)}return this._def.innerType._parse(e)}unwrap(){return this._def.innerType}}t.ZodOptional=ZodOptional;ZodOptional.create=(e,t)=>new ZodOptional({innerType:e,typeName:y.ZodOptional,...processCreateParams(t)});class ZodNullable extends ZodType{_parse(e){const t=this._getType(e);if(t===o.ZodParsedType.null){return(0,n.OK)(null)}return this._def.innerType._parse(e)}unwrap(){return this._def.innerType}}t.ZodNullable=ZodNullable;ZodNullable.create=(e,t)=>new ZodNullable({innerType:e,typeName:y.ZodNullable,...processCreateParams(t)});class ZodDefault extends ZodType{_parse(e){const{ctx:t}=this._processInputParams(e);let s=t.data;if(t.parsedType===o.ZodParsedType.undefined){s=this._def.defaultValue()}return this._def.innerType._parse({data:s,path:t.path,parent:t})}removeDefault(){return this._def.innerType}}t.ZodDefault=ZodDefault;ZodDefault.create=(e,t)=>new ZodDefault({innerType:e,typeName:y.ZodDefault,defaultValue:typeof t.default==="function"?t.default:()=>t.default,...processCreateParams(t)});class ZodCatch extends ZodType{_parse(e){const{ctx:t}=this._processInputParams(e);const s={...t,common:{...t.common,issues:[]}};const r=this._def.innerType._parse({data:s.data,path:s.path,parent:{...s}});if((0,n.isAsync)(r)){return r.then((e=>({status:"valid",value:e.status==="valid"?e.value:this._def.catchValue({get error(){return new i.ZodError(s.common.issues)},input:s.data})})))}else{return{status:"valid",value:r.status==="valid"?r.value:this._def.catchValue({get error(){return new i.ZodError(s.common.issues)},input:s.data})}}}removeCatch(){return this._def.innerType}}t.ZodCatch=ZodCatch;ZodCatch.create=(e,t)=>new ZodCatch({innerType:e,typeName:y.ZodCatch,catchValue:typeof t.catch==="function"?t.catch:()=>t.catch,...processCreateParams(t)});class ZodNaN extends ZodType{_parse(e){const t=this._getType(e);if(t!==o.ZodParsedType.nan){const t=this._getOrReturnCtx(e);(0,n.addIssueToContext)(t,{code:i.ZodIssueCode.invalid_type,expected:o.ZodParsedType.nan,received:t.parsedType});return n.INVALID}return{status:"valid",value:e.data}}}t.ZodNaN=ZodNaN;ZodNaN.create=e=>new ZodNaN({typeName:y.ZodNaN,...processCreateParams(e)});t.BRAND=Symbol("zod_brand");class ZodBranded extends ZodType{_parse(e){const{ctx:t}=this._processInputParams(e);const s=t.data;return this._def.type._parse({data:s,path:t.path,parent:t})}unwrap(){return this._def.type}}t.ZodBranded=ZodBranded;class ZodPipeline extends ZodType{_parse(e){const{status:t,ctx:s}=this._processInputParams(e);if(s.common.async){const handleAsync=async()=>{const e=await this._def.in._parseAsync({data:s.data,path:s.path,parent:s});if(e.status==="aborted")return n.INVALID;if(e.status==="dirty"){t.dirty();return(0,n.DIRTY)(e.value)}else{return this._def.out._parseAsync({data:e.value,path:s.path,parent:s})}};return handleAsync()}else{const e=this._def.in._parseSync({data:s.data,path:s.path,parent:s});if(e.status==="aborted")return n.INVALID;if(e.status==="dirty"){t.dirty();return{status:"dirty",value:e.value}}else{return this._def.out._parseSync({data:e.value,path:s.path,parent:s})}}}static create(e,t){return new ZodPipeline({in:e,out:t,typeName:y.ZodPipeline})}}t.ZodPipeline=ZodPipeline;class ZodReadonly extends ZodType{_parse(e){const t=this._def.innerType._parse(e);if((0,n.isValid)(t)){t.value=Object.freeze(t.value)}return t}}t.ZodReadonly=ZodReadonly;ZodReadonly.create=(e,t)=>new ZodReadonly({innerType:e,typeName:y.ZodReadonly,...processCreateParams(t)});const custom=(e,t={},s)=>{if(e)return ZodAny.create().superRefine(((r,a)=>{var n,o;if(!e(r)){const e=typeof t==="function"?t(r):typeof t==="string"?{message:t}:t;const i=(o=(n=e.fatal)!==null&&n!==void 0?n:s)!==null&&o!==void 0?o:true;const d=typeof e==="string"?{message:e}:e;a.addIssue({code:"custom",...d,fatal:i})}}));return ZodAny.create()};t.custom=custom;t.late={object:ZodObject.lazycreate};var y;(function(e){e["ZodString"]="ZodString";e["ZodNumber"]="ZodNumber";e["ZodNaN"]="ZodNaN";e["ZodBigInt"]="ZodBigInt";e["ZodBoolean"]="ZodBoolean";e["ZodDate"]="ZodDate";e["ZodSymbol"]="ZodSymbol";e["ZodUndefined"]="ZodUndefined";e["ZodNull"]="ZodNull";e["ZodAny"]="ZodAny";e["ZodUnknown"]="ZodUnknown";e["ZodNever"]="ZodNever";e["ZodVoid"]="ZodVoid";e["ZodArray"]="ZodArray";e["ZodObject"]="ZodObject";e["ZodUnion"]="ZodUnion";e["ZodDiscriminatedUnion"]="ZodDiscriminatedUnion";e["ZodIntersection"]="ZodIntersection";e["ZodTuple"]="ZodTuple";e["ZodRecord"]="ZodRecord";e["ZodMap"]="ZodMap";e["ZodSet"]="ZodSet";e["ZodFunction"]="ZodFunction";e["ZodLazy"]="ZodLazy";e["ZodLiteral"]="ZodLiteral";e["ZodEnum"]="ZodEnum";e["ZodEffects"]="ZodEffects";e["ZodNativeEnum"]="ZodNativeEnum";e["ZodOptional"]="ZodOptional";e["ZodNullable"]="ZodNullable";e["ZodDefault"]="ZodDefault";e["ZodCatch"]="ZodCatch";e["ZodPromise"]="ZodPromise";e["ZodBranded"]="ZodBranded";e["ZodPipeline"]="ZodPipeline";e["ZodReadonly"]="ZodReadonly"})(y=t.ZodFirstPartyTypeKind||(t.ZodFirstPartyTypeKind={}));class Class{constructor(...e){}}const instanceOfType=(e,s={message:`Input not instance of ${e.name}`})=>(0,t.custom)((t=>t instanceof e),s);t["instanceof"]=instanceOfType;const Z=ZodString.create;t.string=Z;const _=ZodNumber.create;t.number=_;const v=ZodNaN.create;t.nan=v;const g=ZodBigInt.create;t.bigint=g;const I=ZodBoolean.create;t.boolean=I;const T=ZodDate.create;t.date=T;const x=ZodSymbol.create;t.symbol=x;const b=ZodUndefined.create;t.undefined=b;const C=ZodNull.create;t["null"]=C;const P=ZodAny.create;t.any=P;const k=ZodUnknown.create;t.unknown=k;const w=ZodNever.create;t.never=w;const N=ZodVoid.create;t["void"]=N;const O=ZodArray.create;t.array=O;const S=ZodObject.create;t.object=S;const E=ZodObject.strictCreate;t.strictObject=E;const A=ZodUnion.create;t.union=A;const j=ZodDiscriminatedUnion.create;t.discriminatedUnion=j;const L=ZodIntersection.create;t.intersection=L;const U=ZodTuple.create;t.tuple=U;const D=ZodRecord.create;t.record=D;const R=ZodMap.create;t.map=R;const V=ZodSet.create;t.set=V;const M=ZodFunction.create;t["function"]=M;const z=ZodLazy.create;t.lazy=z;const $=ZodLiteral.create;t.literal=$;const B=ZodEnum.create;t["enum"]=B;const K=ZodNativeEnum.create;t.nativeEnum=K;const F=ZodPromise.create;t.promise=F;const q=ZodEffects.create;t.effect=q;t.transformer=q;const W=ZodOptional.create;t.optional=W;const J=ZodNullable.create;t.nullable=J;const Y=ZodEffects.createWithPreprocess;t.preprocess=Y;const H=ZodPipeline.create;t.pipeline=H;const ostring=()=>Z().optional();t.ostring=ostring;const onumber=()=>_().optional();t.onumber=onumber;const oboolean=()=>I().optional();t.oboolean=oboolean;t.coerce={string:e=>ZodString.create({...e,coerce:true}),number:e=>ZodNumber.create({...e,coerce:true}),boolean:e=>ZodBoolean.create({...e,coerce:true}),bigint:e=>ZodBigInt.create({...e,coerce:true}),date:e=>ZodDate.create({...e,coerce:true})};t.NEVER=n.INVALID}};var t={};function __nccwpck_require__(s){var r=t[s];if(r!==undefined){return r.exports}var a=t[s]={exports:{}};var n=true;try{e[s].call(a.exports,a,a.exports,__nccwpck_require__);n=false}finally{if(n)delete t[s]}return a.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var s=__nccwpck_require__(773);module.exports=s})(); \ No newline at end of file diff --git a/packages/next/src/compiled/zod/package.json b/packages/next/src/compiled/zod/package.json new file mode 100644 index 000000000000..23793495cb36 --- /dev/null +++ b/packages/next/src/compiled/zod/package.json @@ -0,0 +1 @@ +{"name":"zod","main":"index.js","author":"Colin McDonnell ","license":"MIT"} diff --git a/packages/next/src/server/app-render/app-render.tsx b/packages/next/src/server/app-render/app-render.tsx index 7245a38e788c..fcc5089e693c 100644 --- a/packages/next/src/server/app-render/app-render.tsx +++ b/packages/next/src/server/app-render/app-render.tsx @@ -10,9 +10,6 @@ import type { RenderOpts, Segment, } from './types' -import type { StaticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage.external' -import type { StaticGenerationBailout } from '../../client/components/static-generation-bailout' -import type { RequestAsyncStorage } from '../../client/components/request-async-storage.external' import React from 'react' import { createServerComponentRenderer } from './create-server-components-renderer' @@ -237,6 +234,7 @@ export const renderToHTMLOrFlight: AppPageRender = ( }) patchFetch(ComponentMod) + /** * Rules of Static & Dynamic HTML: * @@ -252,12 +250,25 @@ export const renderToHTMLOrFlight: AppPageRender = ( */ const generateStaticHTML = supportsDynamicHTML !== true - const staticGenerationAsyncStorage: StaticGenerationAsyncStorage = - ComponentMod.staticGenerationAsyncStorage - const requestAsyncStorage: RequestAsyncStorage = - ComponentMod.requestAsyncStorage - const staticGenerationBailout: StaticGenerationBailout = - ComponentMod.staticGenerationBailout + // Pull out the hooks/references from the component. + const { + staticGenerationAsyncStorage, + requestAsyncStorage, + staticGenerationBailout, + LayoutRouter, + RenderFromTemplateContext, + createSearchParamsBailoutProxy, + StaticGenerationSearchParamsBailoutProvider, + serverHooks: { DynamicServerError }, + NotFoundBoundary, + renderToReadableStream, + AppRouter, + GlobalError, + tree: loaderTree, + preloadFont, + preconnect, + preloadStyle, + } = ComponentMod // we wrap the render in an AsyncLocalStorage context const wrappedRender = async () => { @@ -294,11 +305,6 @@ export const renderToHTMLOrFlight: AppPageRender = ( ) : undefined - /** - * The tree created in next-app-loader that holds component segments and modules - */ - const loaderTree: LoaderTree = ComponentMod.tree - /** * The metadata items array created in next-app-loader with all relevant information * that we need to resolve the final metadata. @@ -312,15 +318,6 @@ export const renderToHTMLOrFlight: AppPageRender = ( requestId = require('next/dist/compiled/nanoid').nanoid() } - const LayoutRouter = - ComponentMod.LayoutRouter as typeof import('../../client/components/layout-router').default - const RenderFromTemplateContext = - ComponentMod.RenderFromTemplateContext as typeof import('../../client/components/render-from-template-context').default - const createSearchParamsBailoutProxy = - ComponentMod.createSearchParamsBailoutProxy as typeof import('../../client/components/searchparams-bailout-proxy').createSearchParamsBailoutProxy - const StaticGenerationSearchParamsBailoutProvider = - ComponentMod.StaticGenerationSearchParamsBailoutProvider as typeof import('../../client/components/static-generation-searchparams-bailout-provider').default - const isStaticGeneration = staticGenerationStore.isStaticGeneration // During static generation we need to call the static generation bailout when reading searchParams const providedSearchParams = isStaticGeneration @@ -511,16 +508,16 @@ export const renderToHTMLOrFlight: AppPageRender = ( const ext = /\.(woff|woff2|eot|ttf|otf)$/.exec(fontFilename)![1] const type = `font/${ext}` const href = `${assetPrefix}/_next/${fontFilename}` - ComponentMod.preloadFont(href, type, renderOpts.crossOrigin) + preloadFont(href, type, renderOpts.crossOrigin) } } else { try { let url = new URL(assetPrefix) - ComponentMod.preconnect(url.origin, 'anonymous') + preconnect(url.origin, 'anonymous') } catch (error) { // assetPrefix must not be a fully qualified domain name. We assume // we should preconnect to same origin instead - ComponentMod.preconnect('/', 'anonymous') + preconnect('/', 'anonymous') } } } @@ -546,7 +543,7 @@ export const renderToHTMLOrFlight: AppPageRender = ( const precedence = process.env.NODE_ENV === 'development' ? 'next_' + href : 'next' - ComponentMod.preloadStyle(fullHref, renderOpts.crossOrigin) + preloadStyle(fullHref, renderOpts.crossOrigin) return ( 1 if (hasSlotKey && rootLayoutAtThisLevel) { - const NotFoundBoundary = - ComponentMod.NotFoundBoundary as typeof import('../../client/components/not-found-boundary').NotFoundBoundary Component = (componentProps: any) => { const NotFoundComponent = NotFound const RootLayoutComponent = LayoutOrPage @@ -1287,7 +1279,7 @@ export const renderToHTMLOrFlight: AppPageRender = ( // For app dir, use the bundled version of Flight server renderer (renderToReadableStream) // which contains the subset React. - const flightReadableStream = ComponentMod.renderToReadableStream( + const flightReadableStream = renderToReadableStream( options ? [options.actionResult, buildIdFlightDataPair] : buildIdFlightDataPair, @@ -1305,16 +1297,6 @@ export const renderToHTMLOrFlight: AppPageRender = ( return generateFlight() } - // Below this line is handling for rendering to HTML. - - // AppRouter is provided by next-app-loader - const AppRouter = - ComponentMod.AppRouter as typeof import('../../client/components/app-router').default - - const GlobalError = - /** GlobalError can be either the default error boundary or the overwritten app/global-error.js **/ - ComponentMod.GlobalError as typeof import('../../client/components/error-boundary').GlobalError - // Get the nonce from the incoming request if it has one. const csp = req.headers['content-security-policy'] let nonce: string | undefined diff --git a/packages/next/src/server/app-render/create-server-components-renderer.tsx b/packages/next/src/server/app-render/create-server-components-renderer.tsx index 2b4321cfbf24..d88f5492c61d 100644 --- a/packages/next/src/server/app-render/create-server-components-renderer.tsx +++ b/packages/next/src/server/app-render/create-server-components-renderer.tsx @@ -1,5 +1,6 @@ import type { RenderOpts } from './types' import type { FlightResponseRef } from './flight-response-ref' +import type { AppPageModule } from '../future/route-modules/app-page/module' import React, { use } from 'react' import { createErrorHandler } from './create-error-handler' @@ -11,13 +12,7 @@ import { useFlightResponse } from './use-flight-response' */ export function createServerComponentRenderer( ComponentToRender: (props: Props) => any, - ComponentMod: { - renderToReadableStream: any - __next_app__?: { - require: any - loadChunk: any - } - }, + ComponentMod: AppPageModule, { inlinedDataTransformStream, clientReferenceManifest, diff --git a/packages/next/src/server/app-render/entry-base.ts b/packages/next/src/server/app-render/entry-base.ts index aeb65ba62125..ae7e186764a4 100644 --- a/packages/next/src/server/app-render/entry-base.ts +++ b/packages/next/src/server/app-render/entry-base.ts @@ -1,10 +1,10 @@ -const { +export { renderToReadableStream, decodeReply, decodeAction, decodeFormState, // eslint-disable-next-line import/no-extraneous-dependencies -} = require('react-server-dom-webpack/server.edge') +} from 'react-server-dom-webpack/server.edge' import AppRouter from '../../client/components/app-router' import LayoutRouter from '../../client/components/layout-router' @@ -36,10 +36,6 @@ export { staticGenerationBailout, createSearchParamsBailoutProxy, serverHooks, - renderToReadableStream, - decodeReply, - decodeAction, - decodeFormState, preloadStyle, preloadFont, preconnect, diff --git a/packages/next/src/server/app-render/types.ts b/packages/next/src/server/app-render/types.ts index 085b63629b4c..59d23ef98243 100644 --- a/packages/next/src/server/app-render/types.ts +++ b/packages/next/src/server/app-render/types.ts @@ -1,9 +1,10 @@ import type { LoadComponentsReturnType } from '../load-components' import type { ServerRuntime, SizeLimit } from '../../../types' -import { NextConfigComplete } from '../../server/config-shared' +import type { NextConfigComplete } from '../../server/config-shared' import type { ClientReferenceManifest } from '../../build/webpack/plugins/flight-manifest-plugin' import type { NextFontManifest } from '../../build/webpack/plugins/next-font-manifest-plugin' import type { ParsedUrlQuery } from 'querystring' +import type { AppPageModule } from '../future/route-modules/app-page/module' import s from 'next/dist/compiled/superstruct' @@ -135,4 +136,5 @@ export interface RenderOptsPartial { isPrefetch?: boolean } -export type RenderOpts = LoadComponentsReturnType & RenderOptsPartial +export type RenderOpts = LoadComponentsReturnType & + RenderOptsPartial diff --git a/packages/next/src/server/config-schema.ts b/packages/next/src/server/config-schema.ts index 565bfd4d6535..0437a2fb4550 100644 --- a/packages/next/src/server/config-schema.ts +++ b/packages/next/src/server/config-schema.ts @@ -1,481 +1,345 @@ import { NextConfig } from './config' -import type { JSONSchemaType } from 'ajv' import { VALID_LOADERS } from '../shared/lib/image-config' -const configSchema = { - type: 'object', - additionalProperties: false, - properties: { - amp: { - additionalProperties: false, - properties: { - canonicalBase: { - nullable: true, - type: 'string', - }, - }, - type: 'object', - }, - analyticsId: { - type: 'string', - }, - assetPrefix: { - nullable: true, - type: 'string', - }, - basePath: { - type: 'string', - }, - cleanDistDir: { - type: 'boolean', - }, - compiler: { - additionalProperties: false, - properties: { - emotion: { - oneOf: [ - { - type: 'boolean', - }, - { - type: 'object', - additionalProperties: false, - properties: { - sourceMap: { - type: 'boolean', - }, - autoLabel: { - type: 'string', - enum: ['always', 'dev-only', 'never'], - }, - labelFormat: { - type: 'string', - minLength: 1, - }, - importMap: { - type: 'object', - }, - }, - }, - ] as any, - }, - reactRemoveProperties: { - oneOf: [ - { - type: 'boolean', - }, - { - type: 'object', - additionalProperties: false, - properties: { - properties: { - type: 'array', - items: { - type: 'string', - }, - }, - }, - }, - ] as any, - }, - relay: { - type: 'object', - }, - removeConsole: { - oneOf: [ - { - type: 'boolean', - }, - { - type: 'object', - additionalProperties: false, - properties: { - exclude: { - type: 'array', - items: { - type: 'string', - minLength: 1, - }, - }, - }, - }, - ] as any, - }, - styledComponents: { - oneOf: [ - { - type: 'boolean', - }, - { - type: 'object', - additionalProperties: false, - properties: { - displayName: { - type: 'boolean', - }, - topLevelImportPaths: { - oneOf: [ - { type: 'boolean' }, - { - type: 'array', - items: { - type: 'string', - minLength: 1, - }, - }, - ], - }, - ssr: { - type: 'boolean', - }, - fileName: { - type: 'boolean', - }, - meaninglessFileNames: { - oneOf: [ - { type: 'boolean' }, - { - type: 'array', - items: { - type: 'string', - minLength: 1, - }, - }, - ], - }, - minify: { - type: 'boolean', - }, - transpileTemplateLiterals: { - type: 'boolean', - }, - namespace: { - type: 'string', - minLength: 1, - }, - pure: { - type: 'boolean', - }, - cssProp: { - type: 'boolean', - }, - }, - }, - ] as any, - }, - }, - type: 'object', - }, - compress: { - type: 'boolean', - }, - configOrigin: { - type: 'string', - }, - crossOrigin: { - oneOf: [ - false, - { - enum: ['anonymous', 'use-credentials'], - type: 'string', - }, - ], // automatic typing does not like enum - } as any, - devIndicators: { - additionalProperties: false, - properties: { - buildActivity: { - type: 'boolean', - }, - buildActivityPosition: { - // automatic typing does not like enum - enum: ['bottom-left', 'bottom-right', 'top-left', 'top-right'] as any, - type: 'string', - }, - }, - type: 'object', - }, - distDir: { - minLength: 1, - type: 'string', - nullable: true, - }, - env: { - type: 'object', - }, - eslint: { - additionalProperties: false, - properties: { - dirs: { - items: { - minLength: 1, - type: 'string', - }, - type: 'array', - }, - ignoreDuringBuilds: { - type: 'boolean', - }, - }, - type: 'object', - }, - excludeDefaultMomentLocales: { - type: 'boolean', - }, - experimental: { - additionalProperties: false, - properties: { - appDocumentPreloading: { - type: 'boolean', - }, - adjustFontFallbacks: { - type: 'boolean', - }, - adjustFontFallbacksWithSizeAdjust: { - type: 'boolean', - }, - allowedRevalidateHeaderKeys: { - type: 'array', - }, - amp: { - additionalProperties: false, - properties: { - optimizer: { - type: 'object', - }, - skipValidation: { - type: 'boolean', - }, - validator: { - type: 'string', - }, - }, - type: 'object', - }, - clientRouterFilter: { - type: 'boolean', - }, - clientRouterFilterRedirects: { - type: 'boolean', - }, - clientRouterFilterAllowedRate: { - type: 'number', - }, - cpus: { - type: 'number', - }, - memoryBasedWorkersCount: { - type: 'boolean', - }, - craCompat: { - type: 'boolean', - }, - caseSensitiveRoutes: { - type: 'boolean', - }, - useDeploymentId: { - type: 'boolean', - }, - useDeploymentIdServerActions: { - type: 'boolean', - }, - deploymentId: { - type: 'string', - }, - disableOptimizedLoading: { - type: 'boolean', - }, - disablePostcssPresetEnv: { - type: 'boolean', - }, - esmExternals: { - oneOf: [ - { - type: 'boolean', - }, - { - const: 'loose', - }, - ] as any, - }, - serverActions: { - type: 'boolean', - }, - serverActionsBodySizeLimit: { - oneOf: [ - { - type: 'number', - }, - { - type: 'string', - }, - ] as any, - }, - extensionAlias: { - type: 'object', - }, - externalDir: { - type: 'boolean', - }, - externalMiddlewareRewritesResolve: { - type: 'boolean', - }, - fallbackNodePolyfills: { - type: 'boolean', - }, - fetchCacheKeyPrefix: { - type: 'string', - }, - forceSwcTransforms: { - type: 'boolean', - }, - fullySpecified: { - type: 'boolean', - }, - gzipSize: { - type: 'boolean', - }, - incrementalCacheHandlerPath: { - type: 'string', - }, - isrFlushToDisk: { - type: 'boolean', - }, - isrMemoryCacheSize: { - type: 'number', - }, - largePageDataBytes: { - type: 'number', - }, - manualClientBasePath: { - type: 'boolean', - }, - middlewarePrefetch: { - // automatic typing doesn't like enum - enum: ['strict', 'flexible'] as any, - type: 'string', - }, - nextScriptWorkers: { - type: 'boolean', - }, - optimizeCss: { - oneOf: [ - { - type: 'boolean', - }, - { - type: 'object', - }, - ] as any, - }, - optimisticClientCache: { - type: 'boolean', - }, - outputFileTracingRoot: { - nullable: true, - type: 'string', - }, - outputFileTracingExcludes: { - type: 'object', - }, - outputFileTracingIgnores: { - type: 'array', - }, - outputFileTracingIncludes: { - type: 'object', - }, - ppr: { - type: 'boolean', - }, - proxyTimeout: { - minimum: 0, - type: 'number', - }, - serverComponentsExternalPackages: { - items: { - type: 'string', - }, - type: 'array', - }, - scrollRestoration: { - type: 'boolean', - }, - sri: { - properties: { - algorithm: { - enum: ['sha256', 'sha384', 'sha512'] as any, - type: 'string', - }, - }, - type: 'object', - }, - strictNextHead: { - type: 'boolean', - }, - swcMinify: { - type: 'boolean', - }, - swcPlugins: { - type: 'array', - }, - swcTraceProfiling: { - type: 'boolean', - }, - urlImports: { - items: { - type: 'string', - }, - type: 'array', - }, - workerThreads: { - type: 'boolean', - }, - webVitalsAttribution: { - type: 'array', - items: { - type: 'string', - enum: ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'], - } as any, - }, - mdxRs: { - type: 'boolean', - }, - typedRoutes: { - type: 'boolean', - }, - webpackBuildWorker: { - type: 'boolean', - }, - turbo: { - type: 'object', - additionalProperties: false, - properties: { - loaders: { - type: 'object', - }, - rules: { - type: 'object', - }, - resolveAlias: { - type: 'object', - }, - }, - }, - optimizePackageImports: { - type: 'array', - }, - optimizeServerReact: { - type: 'boolean', - }, - instrumentationHook: { - type: 'boolean', - }, - turbotrace: { - type: 'object', - properties: { - logLevel: { - type: 'string', - enum: [ +import { z } from 'next/dist/compiled/zod' +import type zod from 'next/dist/compiled/zod' + +import type { SizeLimit } from '../../types' +import type { ExportPathMap, TurboLoaderItem, TurboRule } from './config-shared' +import type { + Header, + Rewrite, + RouteHas, + Redirect, +} from '../lib/load-custom-routes' + +// A custom zod schema for the SizeLimit type +const zSizeLimit = z.custom((val) => { + if (typeof val === 'number' || typeof val === 'string') { + return true + } + return false +}) + +const zExportMap: zod.ZodType = z.record( + z.string(), + z.object({ + page: z.string(), + query: z.any(), // NextParsedUrlQuery + // private optional properties + _isAppDir: z.boolean().optional(), + _isAppPrefetch: z.boolean().optional(), + _isDynamicError: z.boolean().optional(), + }) +) + +const zRouteHas: zod.ZodType = z.union([ + z.object({ + type: z.enum(['header', 'query', 'cookie']), + key: z.string(), + value: z.string().optional(), + }), + z.object({ + type: z.literal('host'), + key: z.undefined().optional(), + value: z.string(), + }), +]) + +const zRewrite: zod.ZodType = z.object({ + source: z.string(), + destination: z.string(), + basePath: z.literal(false).optional(), + locale: z.literal(false).optional(), + has: z.array(zRouteHas).optional(), + missing: z.array(zRouteHas).optional(), + internal: z.boolean().optional(), +}) + +const zRedirect: zod.ZodType = z + .object({ + source: z.string(), + destination: z.string(), + basePath: z.literal(false).optional(), + locale: z.literal(false).optional(), + has: z.array(zRouteHas).optional(), + missing: z.array(zRouteHas).optional(), + internal: z.boolean().optional(), + }) + .and( + z.union([ + z.object({ + statusCode: z.never().optional(), + permanent: z.boolean(), + }), + z.object({ + statusCode: z.number(), + permanent: z.never().optional(), + }), + ]) + ) + +const zHeader: zod.ZodType
= z.object({ + source: z.string(), + basePath: z.literal(false).optional(), + locale: z.literal(false).optional(), + headers: z.array(z.object({ key: z.string(), value: z.string() })), + has: z.array(zRouteHas).optional(), + missing: z.array(zRouteHas).optional(), + + internal: z.boolean().optional(), +}) + +const zTurboLoaderItem: zod.ZodType = z.union([ + z.string(), + z.object({ + loader: z.string(), + // Any JSON value can be used as turbo loader options, so use z.any() here + options: z.record(z.string(), z.any()), + }), +]) + +const zTurboRule: zod.ZodType = z.union([ + z.array(zTurboLoaderItem), + z.object({ + loaders: z.array(zTurboLoaderItem), + as: z.string(), + }), +]) + +export const configSchema: zod.ZodType = z.lazy(() => + z.strictObject({ + amp: z + .object({ + canonicalBase: z.string().optional(), + }) + .optional(), + analyticsId: z.string().optional(), + assetPrefix: z.string().optional(), + basePath: z.string().optional(), + cleanDistDir: z.boolean().optional(), + compiler: z + .strictObject({ + emotion: z + .union([ + z.boolean(), + z.object({ + sourceMap: z.boolean().optional(), + autoLabel: z + .union([ + z.literal('always'), + z.literal('dev-only'), + z.literal('never'), + ]) + .optional(), + labelFormat: z.string().min(1).optional(), + importMap: z + .record( + z.string(), + z.record( + z.string(), + z.object({ + canonicalImport: z + .tuple([z.string(), z.string()]) + .optional(), + styledBaseImport: z + .tuple([z.string(), z.string()]) + .optional(), + }) + ) + ) + .optional(), + }), + ]) + .optional(), + reactRemoveProperties: z + .union([ + z.boolean().optional(), + z.object({ + properties: z.array(z.string()).optional(), + }), + ]) + .optional(), + relay: z + .object({ + src: z.string(), + artifactDirectory: z.string().optional(), + language: z.enum(['javascript', 'typescript', 'flow']).optional(), + eagerEsModules: z.boolean().optional(), + }) + .optional(), + removeConsole: z + .union([ + z.boolean().optional(), + z.object({ + exclude: z.array(z.string()).min(1).optional(), + }), + ]) + .optional(), + styledComponents: z.union([ + z.boolean().optional(), + z.object({ + displayName: z.boolean().optional(), + topLevelImportPaths: z.array(z.string()).min(1).optional(), + ssr: z.boolean().optional(), + fileName: z.boolean().optional(), + meaninglessFileNames: z.array(z.string()).min(1).optional(), + minify: z.boolean().optional(), + transpileTemplateLiterals: z.boolean().optional(), + namespace: z.string().min(1).optional(), + pure: z.boolean().optional(), + cssProp: z.boolean().optional(), + }), + ]), + }) + .optional(), + compress: z.boolean().optional(), + configOrigin: z.string().optional(), + crossOrigin: z + .union([ + z.literal(false), + z.literal('anonymous'), + z.literal('use-credentials'), + ]) + .optional(), + devIndicators: z + .object({ + buildActivity: z.boolean().optional(), + buildActivityPosition: z + .union([ + z.literal('bottom-left'), + z.literal('bottom-right'), + z.literal('top-left'), + z.literal('top-right'), + ]) + .optional(), + }) + .optional(), + distDir: z.string().min(1).optional(), + env: z.record(z.string(), z.string()).optional(), + eslint: z + .strictObject({ + dirs: z.array(z.string().min(1)).optional(), + ignoreDuringBuilds: z.boolean().optional(), + }) + .optional(), + excludeDefaultMomentLocales: z.boolean().optional(), + experimental: z + .strictObject({ + appDocumentPreloading: z.boolean().optional(), + adjustFontFallbacks: z.boolean().optional(), + adjustFontFallbacksWithSizeAdjust: z.boolean().optional(), + allowedRevalidateHeaderKeys: z.array(z.string()).optional(), + amp: z + .object({ + // AMP optimizer option is unknown, use z.any() here + optimizer: z.any().optional(), + skipValidation: z.boolean().optional(), + validator: z.string().optional(), + }) + .optional(), + clientRouterFilter: z.boolean().optional(), + clientRouterFilterRedirects: z.boolean().optional(), + clientRouterFilterAllowedRate: z.number().optional(), + cpus: z.number().optional(), + memoryBasedWorkersCount: z.boolean().optional(), + craCompat: z.boolean().optional(), + caseSensitiveRoutes: z.boolean().optional(), + useDeploymentId: z.boolean().optional(), + useDeploymentIdServerActions: z.boolean().optional(), + deploymentId: z.string().optional(), + disableOptimizedLoading: z.boolean().optional(), + disablePostcssPresetEnv: z.boolean().optional(), + esmExternals: z.union([z.boolean(), z.literal('loose')]).optional(), + serverActions: z.boolean().optional(), + serverActionsBodySizeLimit: zSizeLimit.optional(), + // The original type was Record + extensionAlias: z.record(z.string(), z.any()).optional(), + externalDir: z.boolean().optional(), + externalMiddlewareRewritesResolve: z.boolean().optional(), + fallbackNodePolyfills: z.literal(false).optional(), + fetchCacheKeyPrefix: z.string().optional(), + forceSwcTransforms: z.boolean().optional(), + fullySpecified: z.boolean().optional(), + gzipSize: z.boolean().optional(), + incrementalCacheHandlerPath: z.string().optional(), + isrFlushToDisk: z.boolean().optional(), + isrMemoryCacheSize: z.number().optional(), + largePageDataBytes: z.number().optional(), + manualClientBasePath: z.boolean().optional(), + middlewarePrefetch: z.enum(['strict', 'flexible']).optional(), + nextScriptWorkers: z.boolean().optional(), + // The critter option is unknown, use z.any() here + optimizeCss: z.union([z.boolean(), z.any()]).optional(), + optimisticClientCache: z.boolean().optional(), + outputFileTracingRoot: z.string().optional(), + outputFileTracingExcludes: z + .record(z.string(), z.array(z.string())) + .optional(), + outputFileTracingIgnores: z.array(z.string()).optional(), + outputFileTracingIncludes: z + .record(z.string(), z.array(z.string())) + .optional(), + ppr: z.boolean().optional(), + proxyTimeout: z.number().gte(0).optional(), + serverComponentsExternalPackages: z.array(z.string()).optional(), + scrollRestoration: z.boolean().optional(), + sri: z + .object({ + algorithm: z.enum(['sha256', 'sha384', 'sha512']).optional(), + }) + .optional(), + strictNextHead: z.boolean().optional(), + swcMinify: z.boolean().optional(), + swcPlugins: z + // The specific swc plugin's option is unknown, use z.any() here + .array(z.tuple([z.string(), z.record(z.string(), z.any())])) + .optional(), + swcTraceProfiling: z.boolean().optional(), + // NonNullable['buildHttp'] + urlImports: z.any().optional(), + workerThreads: z.boolean().optional(), + webVitalsAttribution: z + .array( + z.union([ + z.literal('CLS'), + z.literal('FCP'), + z.literal('FID'), + z.literal('INP'), + z.literal('LCP'), + z.literal('TTFB'), + ]) + ) + .optional(), + mdxRs: z.boolean().optional(), + typedRoutes: z.boolean().optional(), + webpackBuildWorker: z.boolean().optional(), + turbo: z + .object({ + loaders: z.record(z.string(), z.array(zTurboLoaderItem)).optional(), + rules: z.record(z.string(), zTurboRule).optional(), + resolveAlias: z + .record( + z.string(), + z.union([ + z.string(), + z.array(z.string()), + z.record( + z.string(), + z.union([z.string(), z.array(z.string())]) + ), + ]) + ) + .optional(), + }) + .optional(), + optimizePackageImports: z.array(z.string()).optional(), + optimizeServerReact: z.boolean().optional(), + instrumentationHook: z.boolean().optional(), + turbotrace: z + .object({ + logLevel: z + .enum([ 'bug', 'fatal', 'error', @@ -484,341 +348,180 @@ const configSchema = { 'note', 'suggestions', 'info', - ], - } as any, - logAll: { - type: 'boolean', - }, - logDetail: { - type: 'boolean', - }, - contextDirectory: { - type: 'string', - }, - processCwd: { - type: 'string', - }, - memoryLimit: { - type: 'integer', - }, - }, - }, - logging: { - type: 'object', - properties: { - level: { - type: 'string', - }, - fullUrl: { - type: 'boolean', - }, - }, - }, - serverMinification: { - type: 'boolean', - }, - serverSourceMaps: { - type: 'boolean', - }, - bundlePagesExternals: { - type: 'boolean', - }, - }, - type: 'object', - }, - exportPathMap: { - isFunction: true, - errorMessage: 'must be a function that returns a Promise', - } as any, - generateBuildId: { - isFunction: true, - errorMessage: 'must be a function that returns a Promise', - } as any, - generateEtags: { - type: 'boolean', - }, - headers: { - isFunction: true, - errorMessage: 'must be a function that returns a Promise', - } as any, - httpAgentOptions: { - additionalProperties: false, - properties: { - keepAlive: { - type: 'boolean', - }, - }, - type: 'object', - }, - i18n: { - additionalProperties: false, - nullable: true, - properties: { - defaultLocale: { - minLength: 1, - type: 'string', - }, - domains: { - items: { - additionalProperties: false, - properties: { - defaultLocale: { - minLength: 1, - type: 'string', - }, - domain: { - minLength: 1, - type: 'string', - }, - http: { - type: 'boolean', - }, - locales: { - items: { - minLength: 1, - type: 'string', - }, - type: 'array', - }, - }, - type: 'object', - }, - type: 'array', - }, - localeDetection: { - type: 'boolean', - }, - locales: { - items: { - minLength: 1, - type: 'string', - }, - type: 'array', - }, - }, - type: 'object', - }, - images: { - additionalProperties: false, - nullable: true, - properties: { - remotePatterns: { - nullable: true, - items: { - additionalProperties: false, - properties: { - hostname: { - type: 'string', - }, - pathname: { - type: 'string', - }, - port: { - maxLength: 5, - type: 'string', - }, - protocol: { - // automatic typing doesn't like enum - enum: ['http', 'https'] as any, - type: 'string', - }, - }, - required: ['hostname'] as any, - type: 'object', - }, - maxItems: 50, - type: 'array', - }, - unoptimized: { - type: 'boolean', - }, - contentSecurityPolicy: { - type: 'string', - nullable: true, - }, - contentDispositionType: { - enum: ['inline', 'attachment'] as any, // automatic typing does not like enum - type: 'string', - nullable: true, - }, - dangerouslyAllowSVG: { - type: 'boolean', - nullable: true, - }, - deviceSizes: { - items: { - type: 'integer', - minimum: 1, - maximum: 10000, - }, - maxItems: 25, - type: 'array', - nullable: true, - }, - disableStaticImages: { - type: 'boolean', - nullable: true, - }, - domains: { - items: { - type: 'string', - }, - maxItems: 50, - type: 'array', - nullable: true, - }, - formats: { - items: { - enum: ['image/avif', 'image/webp'], // automatic typing does not like enum - type: 'string', - } as any, - maxItems: 4, - type: 'array', - nullable: true, - }, - imageSizes: { - items: { - type: 'integer', - minimum: 1, - maximum: 10000, - }, - minItems: 0, - maxItems: 25, - type: 'array', - nullable: true, - }, - loader: { - // automatic typing does not like enum - enum: VALID_LOADERS as any, - type: 'string', - nullable: true, - }, - loaderFile: { - type: 'string', - nullable: true, - }, - minimumCacheTTL: { - type: 'integer', - minimum: 0, - nullable: true, - }, - path: { - type: 'string', - nullable: true, - }, - }, - type: 'object', - }, - modularizeImports: { - type: 'object', - }, - onDemandEntries: { - additionalProperties: false, - properties: { - maxInactiveAge: { - type: 'number', - }, - pagesBufferLength: { - type: 'number', - }, - }, - type: 'object', - }, - optimizeFonts: { - type: 'boolean', - }, - output: { - // automatic typing doesn't like enum - enum: ['standalone', 'export'] as any, - type: 'string', - }, - outputFileTracing: { - type: 'boolean', - }, - pageExtensions: { - minItems: 1, - type: 'array', - }, - poweredByHeader: { - type: 'boolean', - }, - productionBrowserSourceMaps: { - type: 'boolean', - }, - publicRuntimeConfig: { - type: 'object', - }, - reactProductionProfiling: { - type: 'boolean', - }, - reactStrictMode: { - type: 'boolean', - nullable: true, - }, - redirects: { - isFunction: true, - errorMessage: 'must be a function that returns a Promise', - } as any, - rewrites: { - isFunction: true, - errorMessage: 'must be a function that returns a Promise', - } as any, - sassOptions: { - type: 'object', - }, - serverRuntimeConfig: { - type: 'object', - }, - skipMiddlewareUrlNormalize: { - type: 'boolean', - }, - skipTrailingSlashRedirect: { - type: 'boolean', - }, - staticPageGenerationTimeout: { - type: 'number', - }, - swcMinify: { - type: 'boolean', - }, - target: { - type: 'string', - }, - trailingSlash: { - type: 'boolean', - }, - transpilePackages: { - items: { - type: 'string', - }, - type: 'array', - }, - typescript: { - additionalProperties: false, - properties: { - ignoreBuildErrors: { - type: 'boolean', - }, - tsconfigPath: { - minLength: 1, - type: 'string', - }, - }, - type: 'object', - }, - useFileSystemPublicRoutes: { - type: 'boolean', - }, - webpack: { - isFunction: true, - errorMessage: - 'must be a function that returns a webpack configuration object', - } as any, - }, -} as JSONSchemaType - -// module.exports is used to get around an export bug with TypeScript -// and the Ajv automatic typing -module.exports = { - configSchema, -} + ]) + .optional(), + logAll: z.boolean().optional(), + logDetail: z.boolean().optional(), + contextDirectory: z.string().optional(), + processCwd: z.string().optional(), + memoryLimit: z.number().int().optional(), + }) + .optional(), + logging: z + .object({ + level: z.literal('verbose').optional(), + fullUrl: z.boolean().optional(), + }) + .optional(), + serverMinification: z.boolean().optional(), + serverSourceMaps: z.boolean().optional(), + bundlePagesExternals: z.boolean().optional(), + }) + .optional(), + exportPathMap: z + .function() + .args( + zExportMap, + z.object({ + dev: z.boolean(), + dir: z.string(), + outDir: z.string().nullable(), + distDir: z.string(), + buildId: z.string(), + }) + ) + .returns(z.union([zExportMap, z.promise(zExportMap)])) + .optional(), + generateBuildId: z + .function() + .args() + .returns( + z.union([ + z.string(), + z.null(), + z.promise(z.union([z.string(), z.null()])), + ]) + ) + .optional(), + generateEtags: z.boolean().optional(), + headers: z + .function() + .args() + .returns(z.promise(z.array(zHeader))) + .optional(), + httpAgentOptions: z + .strictObject({ keepAlive: z.boolean().optional() }) + .optional(), + i18n: z + .strictObject({ + defaultLocale: z.string().min(1), + domains: z + .array( + z.strictObject({ + defaultLocale: z.string().min(1), + domain: z.string().min(1), + http: z.literal(true).optional(), + locales: z.array(z.string().min(1)).optional(), + }) + ) + .optional(), + localeDetection: z.literal(false).optional(), + locales: z.array(z.string().min(1)), + }) + .nullable() + .optional(), + images: z + .strictObject({ + remotePatterns: z + .array( + z.strictObject({ + hostname: z.string(), + pathname: z.string().optional(), + port: z.string().max(5).optional(), + protocol: z.enum(['http', 'https']).optional(), + }) + ) + .max(50) + .optional(), + unoptimized: z.boolean().optional(), + contentSecurityPolicy: z.string().optional(), + contentDispositionType: z.enum(['inline', 'attachment']).optional(), + dangerouslyAllowSVG: z.boolean().optional(), + deviceSizes: z + .array(z.number().int().gte(1).lte(10000)) + .max(25) + .optional(), + disableStaticImages: z.boolean().optional(), + domains: z.array(z.string()).max(50).optional(), + formats: z + .array(z.enum(['image/avif', 'image/webp'])) + .max(4) + .optional(), + imageSizes: z + .array(z.number().int().gte(1).lte(10000)) + .min(0) + .max(25) + .optional(), + loader: z.enum(VALID_LOADERS).optional(), + loaderFile: z.string().optional(), + minimumCacheTTL: z.number().int().gte(0).optional(), + path: z.string().optional(), + }) + .optional(), + modularizeImports: z + .record( + z.string(), + z.object({ + transform: z.union([z.string(), z.record(z.string(), z.string())]), + preventFullImport: z.boolean().optional(), + skipDefaultConversion: z.boolean().optional(), + }) + ) + .optional(), + onDemandEntries: z + .strictObject({ + maxInactiveAge: z.number().optional(), + pagesBufferLength: z.number().optional(), + }) + .optional(), + optimizeFonts: z.boolean().optional(), + output: z.enum(['standalone', 'export']).optional(), + outputFileTracing: z.boolean().optional(), + pageExtensions: z.array(z.string()).min(1).optional(), + poweredByHeader: z.boolean().optional(), + productionBrowserSourceMaps: z.boolean().optional(), + publicRuntimeConfig: z.record(z.string(), z.any()).optional(), + reactProductionProfiling: z.boolean().optional(), + reactStrictMode: z.boolean().nullable().optional(), + redirects: z + .function() + .args() + .returns(z.promise(z.array(zRedirect))) + .optional(), + rewrites: z + .function() + .args() + .returns( + z.promise( + z.union([ + z.array(zRewrite), + z.object({ + beforeFiles: z.array(zRewrite), + afterFiles: z.array(zRewrite), + fallback: z.array(zRewrite), + }), + ]) + ) + ) + .optional(), + // saas option is unknown, use z.any() here + sassOptions: z.record(z.string(), z.any()).optional(), + serverRuntimeConfig: z.record(z.string(), z.any()).optional(), + skipMiddlewareUrlNormalize: z.boolean().optional(), + skipTrailingSlashRedirect: z.boolean().optional(), + staticPageGenerationTimeout: z.number().optional(), + swcMinify: z.boolean().optional(), + target: z.string().optional(), + trailingSlash: z.boolean().optional(), + transpilePackages: z.array(z.string()).optional(), + typescript: z + .strictObject({ + ignoreBuildErrors: z.boolean().optional(), + tsconfigPath: z.string().min(1).optional(), + }) + .optional(), + useFileSystemPublicRoutes: z.boolean().optional(), + // The webpack config type is unknown, use z.any() here + webpack: z.any().nullable().optional(), + }) +) diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index d8108f4158be..c03928b177cf 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -780,19 +780,3 @@ export async function normalizeConfig(phase: string, config: any) { // Support `new Promise` and `async () =>` as return values of the config export return await config } - -export function validateConfig(userConfig: NextConfig): { - errors?: Array | null -} { - if (process.env.NEXT_MINIMAL) { - return { - errors: [], - } - } else { - const configValidator = require('next/dist/next-config-validate.js') - configValidator(userConfig) - return { - errors: configValidator.errors, - } - } -} diff --git a/packages/next/src/server/config.ts b/packages/next/src/server/config.ts index 3937011f9c92..6d224c57a2d6 100644 --- a/packages/next/src/server/config.ts +++ b/packages/next/src/server/config.ts @@ -9,7 +9,6 @@ import { normalizeConfig, ExperimentalConfig, NextConfigComplete, - validateConfig, NextConfig, TurboLoaderItem, } from './config-shared' @@ -21,8 +20,88 @@ import { findRootDir } from '../lib/find-root' import { setHttpClientAndAgentOptions } from './setup-http-agent-env' import { pathHasPrefix } from '../shared/lib/router/utils/path-has-prefix' +import { ZodParsedType, util as ZodUtil } from 'next/dist/compiled/zod' +import type { ZodError, ZodIssue } from 'next/dist/compiled/zod' + export { DomainLocale, NextConfig, normalizeConfig } from './config-shared' +function processZodErrorMessage(issue: ZodIssue) { + let message = issue.message + + let path = '' + + if (issue.path.length > 0) { + if (issue.path.length === 1) { + const identifier = issue.path[0] + if (typeof identifier === 'number') { + // The first identifier inside path is a number + path = `index ${identifier}` + } else { + path = `"${identifier}"` + } + } else { + // joined path to be shown in the error message + path = `"${issue.path.reduce((acc, cur) => { + if (typeof cur === 'number') { + // array index + return `${acc}[${cur}]` + } + if (cur.includes('"')) { + // escape quotes + return `${acc}["${cur.replaceAll('"', '\\"')}"]` + } + // dot notation + const separator = acc.length === 0 ? '' : '.' + return acc + separator + cur + }, '')}"` + } + } + + if ( + issue.code === 'invalid_type' && + issue.received === ZodParsedType.undefined + ) { + // missing key in object + return `${path} is missing, expected ${issue.expected}` + } + if (issue.code === 'invalid_enum_value') { + // Remove "Invalid enum value" prefix from zod default error message + return `Expected ${ZodUtil.joinValues(issue.options)}, received '${ + issue.received + }' at ${path}` + } + + return message + (path ? ` at ${path}` : '') +} + +function normalizeZodErrors( + error: ZodError +): [errorMessages: string[], shouldExit: boolean] { + let shouldExit = false + return [ + error.issues.flatMap((issue) => { + const messages = [processZodErrorMessage(issue)] + if (issue.path[0] === 'images') { + // We exit the build when encountering an error in the images config + shouldExit = true + } + + if ('unionErrors' in issue) { + issue.unionErrors + .map(normalizeZodErrors) + .forEach(([unionMessages, unionShouldExit]) => { + messages.push(...unionMessages) + // If any of the union results shows exit the build, we exit the build + shouldExit = shouldExit || unionShouldExit + }) + } + + return messages + }), + shouldExit, + ] +} + export function warnOptionHasBeenDeprecated( config: NextConfig, nestedPropertyKey: string, @@ -875,38 +954,36 @@ export default async function loadConfig( userConfigModule.default || userConfigModule ) - const validateResult = validateConfig(userConfig) - - if (validateResult.errors) { - // Only load @segment/ajv-human-errors when invalid config is detected - const { AggregateAjvError } = - require('next/dist/compiled/@segment/ajv-human-errors') as typeof import('next/dist/compiled/@segment/ajv-human-errors') - const aggregatedAjvErrors = new AggregateAjvError(validateResult.errors, { - fieldLabels: 'js', - }) + if (!process.env.NEXT_MINIMAL) { + // We only validate the config against schema in non minimal mode + const { configSchema } = + require('./config-schema') as typeof import('./config-schema') + const state = configSchema.safeParse(userConfig) - let shouldExit = false - const messages = [`Invalid ${configFileName} options detected: `] + if (!state.success) { + // error message header + const messages = [`Invalid ${configFileName} options detected: `] - for (const error of aggregatedAjvErrors) { - messages.push(` ${error.message}`) - if (error.message.startsWith('The value at .images.')) { - shouldExit = true + const [errorMessages, shouldExit] = normalizeZodErrors(state.error) + // ident list item + for (const error of errorMessages) { + messages.push(` ${error}`) } - } - messages.push( - 'See more info here: https://nextjs.org/docs/messages/invalid-next-config' - ) + // error message footer + messages.push( + 'See more info here: https://nextjs.org/docs/messages/invalid-next-config' + ) - if (shouldExit) { - for (const message of messages) { - console.error(message) - } - await flushAndExit(1) - } else { - for (const message of messages) { - curLog.warn(message) + if (shouldExit) { + for (const message of messages) { + console.error(message) + } + await flushAndExit(1) + } else { + for (const message of messages) { + curLog.warn(message) + } } } } diff --git a/packages/next/src/server/dev/hot-reloader-types.ts b/packages/next/src/server/dev/hot-reloader-types.ts index 191e4570697d..922dc95452e0 100644 --- a/packages/next/src/server/dev/hot-reloader-types.ts +++ b/packages/next/src/server/dev/hot-reloader-types.ts @@ -3,7 +3,7 @@ import type { UrlObject } from 'url' import type { Duplex } from 'stream' import type { webpack } from 'next/dist/compiled/webpack/webpack' import type getBaseWebpackConfig from '../../build/webpack-config' -import type { RouteMatch } from '../future/route-matches/route-match' +import type { RouteDefinition } from '../future/route-definitions/route-definition' import type { Project, Update as TurbopackUpdate } from '../../build/swc' import type { VersionInfo } from './parse-version-info' @@ -134,13 +134,13 @@ export interface NextJsHotReloaderInterface { page, clientOnly, appPaths, - match, + definition, isApp, }: { page: string clientOnly: boolean appPaths?: ReadonlyArray | null isApp?: boolean - match?: RouteMatch + definition: RouteDefinition | undefined }): Promise } diff --git a/packages/next/src/server/dev/hot-reloader-webpack.ts b/packages/next/src/server/dev/hot-reloader-webpack.ts index 20fa94826f3a..48187503b399 100644 --- a/packages/next/src/server/dev/hot-reloader-webpack.ts +++ b/packages/next/src/server/dev/hot-reloader-webpack.ts @@ -4,6 +4,7 @@ import type { Duplex } from 'stream' import type { Telemetry } from '../../telemetry/storage' import type { IncomingMessage, ServerResponse } from 'http' import type { UrlObject } from 'url' +import type { RouteDefinition } from '../future/route-definitions/route-definition' import { webpack, StringXor } from 'next/dist/compiled/webpack/webpack' import { getOverlayMiddleware } from 'next/dist/compiled/@next/react-dev-overlay/dist/middleware' @@ -60,7 +61,6 @@ import ws from 'next/dist/compiled/ws' import { existsSync, promises as fs } from 'fs' import { UnwrapPromise } from '../../lib/coalesced-function' import { getRegistry } from '../../lib/helpers/get-registry' -import { RouteMatch } from '../future/route-matches/route-match' import { parseVersionInfo, VersionInfo } from './parse-version-info' import { isAPIRoute } from '../../lib/is-api-route' import { getRouteLoaderEntry } from '../../build/webpack/loaders/next-route-loader' @@ -1466,14 +1466,14 @@ export default class HotReloader implements NextJsHotReloaderInterface { page, clientOnly, appPaths, - match, + definition, isApp, }: { page: string clientOnly: boolean appPaths?: ReadonlyArray | null isApp?: boolean - match?: RouteMatch + definition?: RouteDefinition }): Promise { // Make sure we don't re-build or dispose prebuilt pages if (page !== '/_error' && BLOCKED_PAGES.indexOf(page) !== -1) { @@ -1490,7 +1490,7 @@ export default class HotReloader implements NextJsHotReloaderInterface { page, clientOnly, appPaths, - match, + definition, isApp, }) } diff --git a/packages/next/src/server/dev/next-dev-server.ts b/packages/next/src/server/dev/next-dev-server.ts index 937e303461db..561f6958ce54 100644 --- a/packages/next/src/server/dev/next-dev-server.ts +++ b/packages/next/src/server/dev/next-dev-server.ts @@ -8,12 +8,13 @@ import type { UrlWithParsedQuery } from 'url' import type { BaseNextRequest, BaseNextResponse } from '../base-http' import type { FallbackMode, MiddlewareRoutingItem } from '../base-server' import type { FunctionComponent } from 'react' -import type { RouteMatch } from '../future/route-matches/route-match' +import type { RouteDefinition } from '../future/route-definitions/route-definition' import type { RouteMatcherManager } from '../future/route-matcher-managers/route-matcher-manager' import type { NextParsedUrlQuery, NextUrlWithParsedQuery, } from '../request-meta' +import type { DevBundlerService } from '../lib/dev-bundler-service' import fs from 'fs' import { Worker } from 'next/dist/compiled/jest-worker' @@ -80,6 +81,11 @@ export interface Options extends ServerOptions { * Tells of Next.js is running from the `next dev` command */ isNextDevCommand?: boolean + + /** + * Interface to the development bundler. + */ + bundlerService: DevBundlerService } export default class DevServer extends Server { @@ -92,15 +98,12 @@ export default class DevServer extends Server { private actualInstrumentationHookFile?: string private middleware?: MiddlewareRoutingItem private originalFetch: typeof fetch + private readonly bundlerService: DevBundlerService private staticPathsCache: LRUCache< string, UnwrapPromise> > - private invokeDevMethod({ method, args }: { method: string; args: any[] }) { - return (global as any)._nextDevHandlers[method](this.dir, ...args) - } - protected staticPathsWorker?: { [key: string]: any } & { loadStaticPaths: typeof import('./static-paths-worker').loadStaticPaths } @@ -140,6 +143,7 @@ export default class DevServer extends Server { Error.stackTraceLimit = 50 } catch {} super({ ...options, dev: true }) + this.bundlerService = options.bundlerService this.originalFetch = global.fetch this.renderOpts.dev = true this.renderOpts.appDirDevErrorLogger = (err: any) => @@ -190,7 +194,7 @@ export default class DevServer extends Server { const ensurer: RouteEnsurer = { ensure: async (match) => { await this.ensurePage({ - match, + definition: match.definition, page: match.definition.page, clientOnly: false, }) @@ -487,10 +491,7 @@ export default class DevServer extends Server { err?: unknown, type?: 'unhandledRejection' | 'uncaughtException' | 'warning' | 'app-dir' ): Promise { - await this.invokeDevMethod({ - method: 'logErrorWithOriginalStack', - args: [err, type], - }) + await this.bundlerService.logErrorWithOriginalStack(err, type) } protected getPagesManifest(): PagesManifest | undefined { @@ -534,6 +535,7 @@ export default class DevServer extends Server { return this.ensurePage({ page: this.actualMiddlewareFile!, clientOnly: false, + definition: undefined, }) } @@ -543,6 +545,7 @@ export default class DevServer extends Server { (await this.ensurePage({ page: this.actualInstrumentationHookFile!, clientOnly: false, + definition: undefined, }) .then(() => true) .catch(() => false)) @@ -570,7 +573,12 @@ export default class DevServer extends Server { page: string appPaths: string[] | null }) { - return this.ensurePage({ page, appPaths, clientOnly: false }) + return this.ensurePage({ + page, + appPaths, + clientOnly: false, + definition: undefined, + }) } generateRoutes(_dev?: boolean) { @@ -723,12 +731,9 @@ export default class DevServer extends Server { page: string clientOnly: boolean appPaths?: ReadonlyArray | null - match?: RouteMatch + definition: RouteDefinition | undefined }): Promise { - await this.invokeDevMethod({ - method: 'ensurePage', - args: [opts], - }) + await this.bundlerService.ensurePage(opts) } protected async findPageComponents({ @@ -759,6 +764,7 @@ export default class DevServer extends Server { page, appPaths, clientOnly: false, + definition: undefined, }) } @@ -785,17 +791,11 @@ export default class DevServer extends Server { } protected async getFallbackErrorComponents(): Promise { - await this.invokeDevMethod({ - method: 'getFallbackErrorComponents', - args: [], - }) + await this.bundlerService.getFallbackErrorComponents() return await loadDefaultErrorComponents(this.distDir) } async getCompilationError(page: string): Promise { - return await this.invokeDevMethod({ - method: 'getCompilationError', - args: [page], - }) + return await this.bundlerService.getCompilationError(page) } } diff --git a/packages/next/src/server/dev/on-demand-entry-handler.ts b/packages/next/src/server/dev/on-demand-entry-handler.ts index c5ef3a5802ce..0529aeb9d56f 100644 --- a/packages/next/src/server/dev/on-demand-entry-handler.ts +++ b/packages/next/src/server/dev/on-demand-entry-handler.ts @@ -33,7 +33,6 @@ import { COMPILER_NAMES, RSC_MODULE_TYPES, } from '../../shared/lib/constants' -import { RouteMatch } from '../future/route-matches/route-match' import { HMR_ACTIONS_SENT_TO_BROWSER } from './hot-reloader-types' import HotReloader from './hot-reloader-webpack' import { isAppPageRouteDefinition } from '../future/route-definitions/app-page-route-definition' @@ -677,13 +676,13 @@ export function onDemandEntryHandler({ page, clientOnly, appPaths, - match, + definition, isApp, }: { page: string clientOnly: boolean appPaths: ReadonlyArray | null - match: Pick | undefined + definition: RouteDefinition | undefined isApp: boolean | undefined }): Promise { const stalledTime = 60 @@ -694,11 +693,11 @@ export function onDemandEntryHandler({ }, stalledTime * 1000) try { - let definition: Pick - if (match?.definition) { - definition = match.definition + let route: Pick + if (definition) { + route = definition } else { - definition = await findPagePathData( + route = await findPagePathData( rootDir, page, nextConfig.pageExtensions, @@ -707,18 +706,18 @@ export function onDemandEntryHandler({ ) } - const isInsideAppDir = !!appDir && definition.filename.startsWith(appDir) + const isInsideAppDir = !!appDir && route.filename.startsWith(appDir) if (typeof isApp === 'boolean' && isApp !== isInsideAppDir) { Error.stackTraceLimit = 15 throw new Error( `Ensure bailed, found path "${ - definition.page + route.page }" does not match ensure type (${isApp ? 'app' : 'pages'})` ) } - const pageBundleType = getPageBundleType(definition.bundlePath) + const pageBundleType = getPageBundleType(route.bundlePath) const addEntry = ( compilerType: CompilerNameValues ): { @@ -726,11 +725,7 @@ export function onDemandEntryHandler({ newEntry: boolean shouldInvalidate: boolean } => { - const entryKey = getEntryKey( - compilerType, - pageBundleType, - definition.page - ) + const entryKey = getEntryKey(compilerType, pageBundleType, route.page) if ( curEntries[entryKey] && // there can be an overlap in the entryKey for the instrumentation hook file and a page named the same @@ -758,9 +753,9 @@ export function onDemandEntryHandler({ curEntries[entryKey] = { type: EntryTypes.ENTRY, appPaths, - absolutePagePath: definition.filename, - request: definition.filename, - bundlePath: definition.bundlePath, + absolutePagePath: route.filename, + request: route.filename, + bundlePath: route.bundlePath, dispose: false, lastActiveTime: Date.now(), status: ADDED, @@ -774,7 +769,7 @@ export function onDemandEntryHandler({ const staticInfo = await getStaticInfoIncludingLayouts({ page, - pageFilePath: definition.filename, + pageFilePath: route.filename, isInsideAppDir, pageExtensions: nextConfig.pageExtensions, isDev: true, @@ -787,7 +782,7 @@ export function onDemandEntryHandler({ isInsideAppDir && staticInfo.rsc !== RSC_MODULE_TYPES.client runDependingOnPageType({ - page: definition.page, + page: route.page, pageRuntime: staticInfo.runtime, pageType: pageBundleType, onClient: () => { @@ -802,11 +797,11 @@ export function onDemandEntryHandler({ const edgeServerEntry = getEntryKey( COMPILER_NAMES.edgeServer, pageBundleType, - definition.page + route.page ) if ( curEntries[edgeServerEntry] && - !isInstrumentationHookFile(definition.page) + !isInstrumentationHookFile(route.page) ) { // Runtime switched from edge to server delete curEntries[edgeServerEntry] @@ -820,11 +815,11 @@ export function onDemandEntryHandler({ const serverEntry = getEntryKey( COMPILER_NAMES.server, pageBundleType, - definition.page + route.page ) if ( curEntries[serverEntry] && - !isInstrumentationHookFile(definition.page) + !isInstrumentationHookFile(route.page) ) { // Runtime switched from server to edge delete curEntries[serverEntry] @@ -839,9 +834,7 @@ export function onDemandEntryHandler({ const hasNewEntry = addedValues.some((entry) => entry.newEntry) if (hasNewEntry) { - reportTrigger( - !clientOnly && hasNewEntry ? `${definition.page}` : definition.page - ) + reportTrigger(!clientOnly && hasNewEntry ? `${route.page}` : route.page) } if (entriesThatShouldBeInvalidated.length > 0) { @@ -883,18 +876,12 @@ export function onDemandEntryHandler({ page: string clientOnly: boolean appPaths?: ReadonlyArray | null - match?: RouteMatch + definition?: RouteDefinition isApp?: boolean } // Make sure that we won't have multiple invalidations ongoing concurrently. - const batcher = Batcher.create< - Omit & { - definition?: RouteDefinition - }, - void, - string - >({ + const batcher = Batcher.create({ // The cache key here is composed of the elements that affect the // compilation, namely, the page, whether it's client only, and whether // it's an app page. This ensures that we don't have multiple compilations @@ -913,26 +900,28 @@ export function onDemandEntryHandler({ page, clientOnly, appPaths = null, - match, + definition, isApp, }: EnsurePageOptions) { // If the route is actually an app page route, then we should have access - // to the app route match, and therefore, the appPaths from it. - if ( - !appPaths && - match?.definition && - isAppPageRouteDefinition(match.definition) - ) { - appPaths = match.definition.appPaths + // to the app route definition, and therefore, the appPaths from it. + if (!appPaths && definition && isAppPageRouteDefinition(definition)) { + appPaths = definition.appPaths } // Wrap the invocation of the ensurePageImpl function in the pending // wrapper, which will ensure that we don't have multiple compilations // for the same page happening concurrently. return batcher.batch( - { page, clientOnly, appPaths, definition: match?.definition, isApp }, + { page, clientOnly, appPaths, definition, isApp }, async () => { - await ensurePageImpl({ page, clientOnly, appPaths, match, isApp }) + await ensurePageImpl({ + page, + clientOnly, + appPaths, + definition, + isApp, + }) } ) }, diff --git a/packages/next/src/server/future/route-modules/app-page/module.compiled.d.ts b/packages/next/src/server/future/route-modules/app-page/module.compiled.d.ts new file mode 100644 index 000000000000..5401340695ab --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/module.compiled.d.ts @@ -0,0 +1 @@ +export * from './module' diff --git a/packages/next/src/server/future/route-modules/app-page/module.compiled.ts b/packages/next/src/server/future/route-modules/app-page/module.compiled.js similarity index 100% rename from packages/next/src/server/future/route-modules/app-page/module.compiled.ts rename to packages/next/src/server/future/route-modules/app-page/module.compiled.js diff --git a/packages/next/src/server/future/route-modules/app-page/module.ts b/packages/next/src/server/future/route-modules/app-page/module.ts index 5a34be6759ad..0c5e7cbcb17d 100644 --- a/packages/next/src/server/future/route-modules/app-page/module.ts +++ b/packages/next/src/server/future/route-modules/app-page/module.ts @@ -22,6 +22,13 @@ if (process.env.NEXT_RUNTIME !== 'edge') { vendoredReactSSR = require('./vendored/ssr/entrypoints') } +/** + * The AppPageModule is the type of the module exported by the bundled app page + * module. + */ +export type AppPageModule = + typeof import('../../../../build/templates/app-page') + type AppPageUserlandModule = { /** * The tree created in next-app-loader that holds component segments and modules diff --git a/packages/next/src/server/future/route-modules/app-route/module.compiled.d.ts b/packages/next/src/server/future/route-modules/app-route/module.compiled.d.ts new file mode 100644 index 000000000000..5401340695ab --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-route/module.compiled.d.ts @@ -0,0 +1 @@ +export * from './module' diff --git a/packages/next/src/server/future/route-modules/app-route/module.compiled.ts b/packages/next/src/server/future/route-modules/app-route/module.compiled.js similarity index 100% rename from packages/next/src/server/future/route-modules/app-route/module.compiled.ts rename to packages/next/src/server/future/route-modules/app-route/module.compiled.js diff --git a/packages/next/src/server/future/route-modules/app-route/module.ts b/packages/next/src/server/future/route-modules/app-route/module.ts index 41ea0ea87f06..4caf96f791a5 100644 --- a/packages/next/src/server/future/route-modules/app-route/module.ts +++ b/packages/next/src/server/future/route-modules/app-route/module.ts @@ -44,6 +44,13 @@ import { staticGenerationAsyncStorage } from '../../../../client/components/stat import { actionAsyncStorage } from '../../../../client/components/action-async-storage.external' import * as sharedModules from './shared-modules' +/** + * The AppRouteModule is the type of the module exported by the bundled App + * Route module. + */ +export type AppRouteModule = + typeof import('../../../../build/templates/app-route') + /** * AppRouteRouteHandlerContext is the context that is passed to the route * handler for app routes. diff --git a/packages/next/src/server/future/route-modules/pages-api/module.compiled.d.ts b/packages/next/src/server/future/route-modules/pages-api/module.compiled.d.ts new file mode 100644 index 000000000000..5401340695ab --- /dev/null +++ b/packages/next/src/server/future/route-modules/pages-api/module.compiled.d.ts @@ -0,0 +1 @@ +export * from './module' diff --git a/packages/next/src/server/future/route-modules/pages-api/module.compiled.ts b/packages/next/src/server/future/route-modules/pages-api/module.compiled.js similarity index 100% rename from packages/next/src/server/future/route-modules/pages-api/module.compiled.ts rename to packages/next/src/server/future/route-modules/pages-api/module.compiled.js diff --git a/packages/next/src/server/future/route-modules/pages-api/module.ts b/packages/next/src/server/future/route-modules/pages-api/module.ts index 4f9c4fe5749c..70940f443172 100644 --- a/packages/next/src/server/future/route-modules/pages-api/module.ts +++ b/packages/next/src/server/future/route-modules/pages-api/module.ts @@ -16,6 +16,13 @@ type PagesAPIHandleFn = ( res: ServerResponse ) => Promise +/** + * The PagesAPIModule is the type of the module exported by the bundled Pages + * API module. + */ +export type PagesAPIModule = + typeof import('../../../../build/templates/pages-api') + type PagesAPIUserlandModule = { /** * The exported handler method. diff --git a/packages/next/src/server/future/route-modules/pages/module.compiled.d.ts b/packages/next/src/server/future/route-modules/pages/module.compiled.d.ts new file mode 100644 index 000000000000..5401340695ab --- /dev/null +++ b/packages/next/src/server/future/route-modules/pages/module.compiled.d.ts @@ -0,0 +1 @@ +export * from './module' diff --git a/packages/next/src/server/future/route-modules/pages/module.compiled.ts b/packages/next/src/server/future/route-modules/pages/module.compiled.js similarity index 100% rename from packages/next/src/server/future/route-modules/pages/module.compiled.ts rename to packages/next/src/server/future/route-modules/pages/module.compiled.js diff --git a/packages/next/src/server/future/route-modules/pages/module.ts b/packages/next/src/server/future/route-modules/pages/module.ts index 3abbe1da064e..c50b9c3eb718 100644 --- a/packages/next/src/server/future/route-modules/pages/module.ts +++ b/packages/next/src/server/future/route-modules/pages/module.ts @@ -20,6 +20,12 @@ import { import { renderToHTMLImpl, renderToHTML } from '../../../render' import * as vendoredContexts from './vendored/contexts/entrypoints' +/** + * The PagesModule is the type of the module exported by the bundled pages + * module. + */ +export type PagesModule = typeof import('../../../../build/templates/pages') + /** * The userland module for a page. This is the module that is exported from the * page file that contains the page component, page config, and any page data diff --git a/packages/next/src/server/lib/dev-bundler-service.ts b/packages/next/src/server/lib/dev-bundler-service.ts new file mode 100644 index 000000000000..99ca47415bcf --- /dev/null +++ b/packages/next/src/server/lib/dev-bundler-service.ts @@ -0,0 +1,74 @@ +import type { IncomingMessage } from 'http' +import type { DevBundler } from './router-utils/setup-dev-bundler' +import type { WorkerRequestHandler } from './types' + +import { createRequestResponseMocks } from './mock-request' + +/** + * The DevBundlerService provides an interface to perform tasks with the + * bundler while in development. + */ +export class DevBundlerService { + constructor( + private readonly bundler: DevBundler, + private readonly handler: WorkerRequestHandler + ) {} + + public ensurePage: typeof this.bundler.hotReloader.ensurePage = async ( + definition + ) => { + // TODO: remove after ensure is pulled out of server + return await this.bundler.hotReloader.ensurePage(definition) + } + + public logErrorWithOriginalStack: typeof this.bundler.logErrorWithOriginalStack = + async (...args) => { + return await this.bundler.logErrorWithOriginalStack(...args) + } + + public async getFallbackErrorComponents() { + await this.bundler.hotReloader.buildFallbackError() + // Build the error page to ensure the fallback is built too. + // TODO: See if this can be moved into hotReloader or removed. + await this.bundler.hotReloader.ensurePage({ + page: '/_error', + clientOnly: false, + definition: undefined, + }) + } + + public async getCompilationError(page: string) { + const errors = await this.bundler.hotReloader.getCompilationErrors(page) + if (!errors) return + + // Return the very first error we found. + return errors[0] + } + + public async revalidate({ + urlPath, + revalidateHeaders, + opts: revalidateOpts, + }: { + urlPath: string + revalidateHeaders: IncomingMessage['headers'] + opts: any + }) { + const mocked = createRequestResponseMocks({ + url: urlPath, + headers: revalidateHeaders, + }) + + await this.handler(mocked.req, mocked.res) + await mocked.res.hasStreamed + + if ( + mocked.res.getHeader('x-nextjs-cache') !== 'REVALIDATED' && + !(mocked.res.statusCode === 404 && revalidateOpts.unstable_onlyGenerated) + ) { + throw new Error(`Invalid response ${mocked.res.statusCode}`) + } + + return {} + } +} diff --git a/packages/next/src/server/lib/patch-fetch.ts b/packages/next/src/server/lib/patch-fetch.ts index 7f250860f51f..2e1b23a24172 100644 --- a/packages/next/src/server/lib/patch-fetch.ts +++ b/packages/next/src/server/lib/patch-fetch.ts @@ -141,15 +141,17 @@ function trackFetchMetric( }) } +interface PatchableModule { + serverHooks: typeof ServerHooks + staticGenerationAsyncStorage: StaticGenerationAsyncStorage +} + // we patch fetch to collect cache information used for // determining if a page is static or not export function patchFetch({ serverHooks, staticGenerationAsyncStorage, -}: { - serverHooks: typeof ServerHooks - staticGenerationAsyncStorage: StaticGenerationAsyncStorage -}) { +}: PatchableModule) { if (!(globalThis as any)._nextOriginalFetch) { ;(globalThis as any)._nextOriginalFetch = globalThis.fetch } diff --git a/packages/next/src/server/lib/render-server.ts b/packages/next/src/server/lib/render-server.ts index 85845f774056..21c2a6ae9f6f 100644 --- a/packages/next/src/server/lib/render-server.ts +++ b/packages/next/src/server/lib/render-server.ts @@ -1,4 +1,5 @@ import type { NextServer, RequestHandler } from '../next' +import type { DevBundlerService } from './dev-bundler-service' import next from '../next' import { PropagateToWorkersField } from './router-utils/types' @@ -79,6 +80,7 @@ async function initializeImpl(opts: { experimentalHttpsServer: boolean _ipcPort?: string _ipcKey?: string + bundlerService: DevBundlerService | undefined }) { const type = process.env.__NEXT_PRIVATE_RENDER_WORKER if (type) { diff --git a/packages/next/src/server/lib/router-server.ts b/packages/next/src/server/lib/router-server.ts index b16858a50645..b1e8e7487fe2 100644 --- a/packages/next/src/server/lib/router-server.ts +++ b/packages/next/src/server/lib/router-server.ts @@ -1,7 +1,6 @@ -import type { IncomingMessage } from 'http' - // this must come first as it includes require hooks import type { WorkerRequestHandler, WorkerUpgradeHandler } from './types' +import type { DevBundler } from './router-utils/setup-dev-bundler' // This is required before other imports to ensure the require hook is setup. import '../node-polyfill-fetch' @@ -20,8 +19,6 @@ import { findPagesDir } from '../../lib/find-pages-dir' import { setupFsCheck } from './router-utils/filesystem' import { proxyRequest } from './router-utils/proxy-request' import { isAbortError, pipeReadable } from '../pipe-readable' -import { createRequestResponseMocks } from './mock-request' -import { UnwrapPromise } from '../../lib/coalesced-function' import { getResolveRoutes } from './router-utils/resolve-routes' import { NextUrlWithParsedQuery, getRequestMeta } from '../request-meta' import { pathHasPrefix } from '../../shared/lib/router/utils/path-has-prefix' @@ -35,7 +32,7 @@ import { PHASE_DEVELOPMENT_SERVER, PERMANENT_REDIRECT_STATUS, } from '../../shared/lib/constants' -import type { NextJsHotReloaderInterface } from '../dev/hot-reloader-types' +import { DevBundlerService } from './dev-bundler-service' const debug = setupDebug('next:router-server:main') @@ -48,11 +45,6 @@ export type RenderServer = Pick< | 'propagateServerField' > -const devInstances: Record< - string, - UnwrapPromise> -> = {} - export interface LazyRenderServerInstance { instance?: RenderServer } @@ -100,11 +92,9 @@ export async function initialize(opts: { const renderServer: LazyRenderServerInstance = {} - let devInstance: - | UnwrapPromise< - ReturnType - > - | undefined + let developmentBundler: DevBundler | undefined + + let devBundlerService: DevBundlerService | undefined if (opts.dev) { const telemetry = new Telemetry({ @@ -112,10 +102,10 @@ export async function initialize(opts: { }) const { pagesDir, appDir } = findPagesDir(opts.dir) - const { setupDev } = - (await require('./router-utils/setup-dev')) as typeof import('./router-utils/setup-dev') + const { setupDevBundler } = + require('./router-utils/setup-dev-bundler') as typeof import('./router-utils/setup-dev-bundler') - devInstance = await setupDev({ + developmentBundler = await setupDevBundler({ // Passed here but the initialization of this object happens below, doing the initialization before the setupDev call breaks. renderServer, appDir, @@ -128,74 +118,15 @@ export async function initialize(opts: { turbo: !!process.env.TURBOPACK, port: opts.port, }) - devInstances[opts.dir] = devInstance - ;(global as any)._nextDevHandlers = { - async ensurePage( - dir: string, - match: Parameters[0] - ) { - const curDevInstance = devInstances[dir] - // TODO: remove after ensure is pulled out of server - return await curDevInstance?.hotReloader.ensurePage(match) - }, - async logErrorWithOriginalStack(dir: string, ...args: any[]) { - const curDevInstance = devInstances[dir] - // @ts-ignore - return await curDevInstance?.logErrorWithOriginalStack(...args) - }, - async getFallbackErrorComponents(dir: string) { - const curDevInstance = devInstances[dir] - await curDevInstance.hotReloader.buildFallbackError() - // Build the error page to ensure the fallback is built too. - // TODO: See if this can be moved into hotReloader or removed. - await curDevInstance.hotReloader.ensurePage({ - page: '/_error', - clientOnly: false, - }) - }, - async getCompilationError(dir: string, page: string) { - const curDevInstance = devInstances[dir] - const errors = await curDevInstance?.hotReloader?.getCompilationErrors( - page - ) - if (!errors) return - - // Return the very first error we found. - return errors[0] - }, - async revalidate( - dir: string, - { - urlPath, - revalidateHeaders, - opts: revalidateOpts, - }: { - urlPath: string - revalidateHeaders: IncomingMessage['headers'] - opts: any - } - ) { - const mocked = createRequestResponseMocks({ - url: urlPath, - headers: revalidateHeaders, - }) - const curRequestHandler = requestHandlers[dir] - // eslint-disable-next-line @typescript-eslint/no-use-before-define - await curRequestHandler(mocked.req, mocked.res) - await mocked.res.hasStreamed - if ( - mocked.res.getHeader('x-nextjs-cache') !== 'REVALIDATED' && - !( - mocked.res.statusCode === 404 && - revalidateOpts.unstable_onlyGenerated - ) - ) { - throw new Error(`Invalid response ${mocked.res.statusCode}`) - } - return {} - }, - } as any + devBundlerService = new DevBundlerService( + developmentBundler, + // The request handler is assigned below, this allows us to create a lazy + // reference to it. + (req, res) => { + return requestHandlers[opts.dir](req, res) + } + ) } renderServer.instance = @@ -209,9 +140,10 @@ export async function initialize(opts: { dev: !!opts.dev, server: opts.server, isNodeDebugging: !!opts.isNodeDebugging, - serverFields: devInstance?.serverFields || {}, + serverFields: developmentBundler?.serverFields || {}, experimentalTestProxy: !!opts.experimentalTestProxy, experimentalHttpsServer: !!opts.experimentalHttpsServer, + bundlerService: devBundlerService, } // pre-initialize workers @@ -221,7 +153,7 @@ export async function initialize(opts: { type: 'uncaughtException' | 'unhandledRejection', err: Error | undefined ) => { - await devInstance?.logErrorWithOriginalStack(err, type) + await developmentBundler?.logErrorWithOriginalStack(err, type) } process.on('uncaughtException', logError.bind(null, 'uncaughtException')) @@ -233,7 +165,7 @@ export async function initialize(opts: { opts, renderServer.instance, renderServerOpts, - devInstance?.ensureMiddleware + developmentBundler?.ensureMiddleware ) const requestHandlerImpl: WorkerRequestHandler = async (req, res) => { @@ -328,7 +260,7 @@ export async function initialize(opts: { } // handle hot-reloader first - if (devInstance) { + if (developmentBundler) { const origUrl = req.url || '/' if (config.basePath && pathHasPrefix(origUrl, config.basePath)) { @@ -336,7 +268,7 @@ export async function initialize(opts: { } const parsedUrl = url.parse(req.url || '/') - const hotReloaderResult = await devInstance.hotReloader.run( + const hotReloaderResult = await developmentBundler.hotReloader.run( req, res, parsedUrl @@ -367,7 +299,7 @@ export async function initialize(opts: { return } - if (devInstance && matchedOutput?.type === 'devVirtualFsItem') { + if (developmentBundler && matchedOutput?.type === 'devVirtualFsItem') { const origUrl = req.url || '/' if (config.basePath && pathHasPrefix(origUrl, config.basePath)) { @@ -379,7 +311,7 @@ export async function initialize(opts: { res.setHeader(key, resHeaders[key]) } } - const result = await devInstance.requestHandler(req, res) + const result = await developmentBundler.requestHandler(req, res) if (result.finished) { return @@ -571,7 +503,7 @@ export async function initialize(opts: { } const appNotFound = opts.dev - ? devInstance?.serverFields.hasAppNotFound + ? developmentBundler?.serverFields.hasAppNotFound : await fsChecker.getItem('/_not-found') res.statusCode = 404 @@ -640,9 +572,9 @@ export async function initialize(opts: { // console.error(_err); }) - if (opts.dev && devInstance) { + if (opts.dev && developmentBundler) { if (req.url?.includes(`/_next/webpack-hmr`)) { - return devInstance.hotReloader.onHMR(req, socket, head) + return developmentBundler.hotReloader.onHMR(req, socket, head) } } diff --git a/packages/next/src/server/lib/router-utils/setup-dev.ts b/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts similarity index 99% rename from packages/next/src/server/lib/router-utils/setup-dev.ts rename to packages/next/src/server/lib/router-utils/setup-dev-bundler.ts index f97e14c15178..5ba81e901a10 100644 --- a/packages/next/src/server/lib/router-utils/setup-dev.ts +++ b/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts @@ -1065,6 +1065,7 @@ async function startWatcher(opts: SetupOpts) { .ensurePage({ page: decodedPagePath, clientOnly: false, + definition: undefined, }) .catch(console.error) } @@ -1166,10 +1167,10 @@ async function startWatcher(opts: SetupOpts) { // Unused parameters // clientOnly, // appPaths, - match, + definition, isApp, }) { - let page = match?.definition?.pathname ?? inputPage + let page = definition?.pathname ?? inputPage if (page === '/_error') { if (globalEntries.app) { @@ -1218,7 +1219,7 @@ async function startWatcher(opts: SetupOpts) { curEntries.get(page) ?? curEntries.get( normalizeAppPath( - normalizeMetadataRoute(match?.definition?.page ?? inputPage) + normalizeMetadataRoute(definition?.page ?? inputPage) ) ) @@ -1457,6 +1458,7 @@ async function startWatcher(opts: SetupOpts) { clientOnly: false, page: item.itemPath, isApp: item.type === 'appFile', + definition: undefined, }) } }) @@ -2236,12 +2238,13 @@ async function startWatcher(opts: SetupOpts) { return hotReloader.ensurePage({ page: serverFields.actualMiddlewareFile, clientOnly: false, + definition: undefined, }) }, } } -export async function setupDev(opts: SetupOpts) { +export async function setupDevBundler(opts: SetupOpts) { const isSrcDir = path .relative(opts.dir, opts.pagesDir || opts.appDir || '') .startsWith('src') @@ -2266,3 +2269,5 @@ export async function setupDev(opts: SetupOpts) { ) return result } + +export type DevBundler = Awaited> diff --git a/packages/next/src/server/load-components.ts b/packages/next/src/server/load-components.ts index eb53b2736db6..042b3788e989 100644 --- a/packages/next/src/server/load-components.ts +++ b/packages/next/src/server/load-components.ts @@ -33,7 +33,7 @@ export type ManifestItem = { export type ReactLoadableManifest = { [moduleId: string]: ManifestItem } -export type LoadComponentsReturnType = { +export type LoadComponentsReturnType = { Component: NextComponentType pageConfig: PageConfig buildManifest: BuildManifest @@ -46,7 +46,7 @@ export type LoadComponentsReturnType = { getStaticProps?: GetStaticProps getStaticPaths?: GetStaticPaths getServerSideProps?: GetServerSideProps - ComponentMod: any + ComponentMod: NextModule routeModule?: RouteModule isAppPath?: boolean page: string @@ -88,7 +88,7 @@ async function loadClientReferenceManifest( } } -async function loadComponentsImpl({ +async function loadComponentsImpl({ distDir, page, isAppPath, @@ -96,7 +96,7 @@ async function loadComponentsImpl({ distDir: string page: string isAppPath: boolean -}): Promise { +}): Promise> { let DocumentMod = {} let AppMod = {} if (!isAppPath) { diff --git a/packages/next/src/server/next.ts b/packages/next/src/server/next.ts index fd987b9c8b26..061b7cfa255f 100644 --- a/packages/next/src/server/next.ts +++ b/packages/next/src/server/next.ts @@ -1,5 +1,8 @@ import type { Options as DevServerOptions } from './dev/next-dev-server' -import type { NodeRequestHandler } from './next-server' +import type { + NodeRequestHandler, + Options as ServerOptions, +} from './next-server' import type { UrlWithParsedQuery } from 'url' import type { NextConfigComplete } from './config-shared' import type { IncomingMessage, ServerResponse } from 'http' @@ -34,10 +37,15 @@ const getServerImpl = async () => { return ServerImpl } -export type NextServerOptions = Partial & { - preloadedConfig?: NextConfigComplete - internal_setStandaloneConfig?: boolean -} +export type NextServerOptions = Omit< + ServerOptions | DevServerOptions, + // This is assigned in this server abstraction. + 'conf' +> & + Partial> & { + preloadedConfig?: NextConfigComplete + internal_setStandaloneConfig?: boolean + } export interface RequestHandler { ( @@ -153,7 +161,9 @@ export class NextServer { return (server as any).close() } - private async createServer(options: DevServerOptions): Promise { + private async createServer( + options: ServerOptions | DevServerOptions + ): Promise { let ServerImplementation: typeof Server if (options.dev) { ServerImplementation = require('./dev/next-dev-server').default diff --git a/packages/next/src/server/render.tsx b/packages/next/src/server/render.tsx index f23df5d7cf84..a67ba29583d5 100644 --- a/packages/next/src/server/render.tsx +++ b/packages/next/src/server/render.tsx @@ -34,6 +34,7 @@ import type { UnwrapPromise } from '../lib/coalesced-function' import type { ReactReadableStream } from './stream-utils/node-web-streams-helper' import type { ClientReferenceManifest } from '../build/webpack/plugins/flight-manifest-plugin' import type { NextFontManifest } from '../build/webpack/plugins/next-font-manifest-plugin' +import type { PagesModule } from './future/route-modules/pages/module' import React from 'react' import ReactDOMServer from 'react-dom/server.browser' @@ -286,7 +287,8 @@ export type RenderOptsPartial = { isPrefetch?: boolean } -export type RenderOpts = LoadComponentsReturnType & RenderOptsPartial +export type RenderOpts = LoadComponentsReturnType & + RenderOptsPartial /** * RenderOptsExtra is being used to split away functionality that's within the diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index dd6858d28958..ba2614d05855 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -2,7 +2,7 @@ const { relative, basename, resolve, join, dirname } = require('path') // eslint-disable-next-line import/no-extraneous-dependencies const glob = require('glob') // eslint-disable-next-line import/no-extraneous-dependencies -const fs = require('fs-extra') +const fs = require('fs/promises') // eslint-disable-next-line import/no-extraneous-dependencies const resolveFrom = require('resolve-from') const execa = require('execa') @@ -44,7 +44,7 @@ export async function copy_styled_jsx_assets(task, opts) { // Separate type files into different folders to avoid conflicts between // dev dep `styled-jsx` and `next/dist/styled-jsx` for duplicated declare modules const typesDir = join(outputDir, 'types') - await fs.ensureDir(typesDir) + await fs.mkdir(typesDir, { recursive: true }) for (const file of typeFiles) { const content = await fs.readFile(join(styledJsxPath, file), 'utf8') @@ -118,7 +118,7 @@ export async function capsize_metrics() { 'dist/server/capsize-font-metrics.json' ) - await fs.outputJson(outputPathDist, entireMetricsCollection, { spaces: 2 }) + await writeJson(outputPathDist, entireMetricsCollection, { spaces: 2 }) } // eslint-disable-next-line camelcase @@ -135,10 +135,10 @@ export async function copy_babel_runtime(task, opts) { const inputPath = join(runtimeDir, file) const outputPath = join(outputDir, file) - if (!fs.statSync(inputPath).isFile()) { + if (!(await fs.stat(inputPath)).isFile()) { continue } - let contents = fs.readFileSync(inputPath, 'utf8') + let contents = await fs.readFile(inputPath, 'utf8') if (inputPath.endsWith('.js')) { contents = contents @@ -156,8 +156,8 @@ export async function copy_babel_runtime(task, opts) { }) } - fs.mkdirSync(dirname(outputPath), { recursive: true }) - fs.writeFileSync(outputPath, contents) + await fs.mkdir(dirname(outputPath), { recursive: true }) + await fs.writeFile(outputPath, contents) } } @@ -224,26 +224,23 @@ export async function copy_vercel_og(task, opts) { }) .target('src/compiled/@vercel/og') - await fs.writeFile( + await writeJson( join(__dirname, 'src/compiled/@vercel/og/package.json'), - JSON.stringify( - { - name: '@vercel/og', - LICENSE: 'MLP-2.0', - type: 'module', - main: './index.node.js', - exports: { - '.': { - 'edge-light': './index.edge.js', - import: './index.node.js', - node: './index.node.js', - default: './index.node.js', - }, + { + name: '@vercel/og', + LICENSE: 'MLP-2.0', + type: 'module', + main: './index.node.js', + exports: { + '.': { + 'edge-light': './index.edge.js', + import: './index.node.js', + node: './index.node.js', + default: './index.node.js', }, }, - null, - 2 - ) + }, + { spaces: 2 } ) } @@ -304,10 +301,10 @@ export async function ncc_node_platform(task, opts) { .target('src/compiled/platform') const clientFile = join(__dirname, 'src/compiled/platform/platform.js') - const content = fs.readFileSync(clientFile, 'utf8') + const content = await fs.readFile(clientFile, 'utf8') // remove AMD define branch as this forces the module to not // be treated as commonjs - fs.writeFileSync( + await fs.writeFile( clientFile, content.replace( new RegExp( @@ -338,55 +335,6 @@ export async function ncc_undici(task, opts) { ) } -// eslint-disable-next-line camelcase -export async function compile_config_schema(task, opts) { - const { configSchema } = require('./dist/server/config-schema') - // eslint-disable-next-line - const Ajv = require('ajv') - // eslint-disable-next-line - const standaloneCode = require('ajv/dist/standalone').default - // eslint-disable-next-line - const ajv = new Ajv({ - code: { source: true }, - allErrors: true, - verbose: true, - }) - - // errorMessage keyword will be consumed by @segment/ajv-human-errors to provide a custom error message - ajv.addKeyword('errorMessage') - - ajv.addKeyword({ - keyword: 'isFunction', - schemaType: 'boolean', - compile() { - return (data) => data == null || data instanceof Function - }, - code(ctx) { - const { data } = ctx - ctx.fail(Ajv._`!(${data} == null || ${data} instanceof Function)`) - }, - metaSchema: { - anyOf: [{ type: 'boolean' }], - }, - }) - - const compiled = ajv.compile(configSchema) - const validateCode = standaloneCode(ajv, compiled) - const preNccFilename = join(__dirname, 'dist', 'next-config-validate.js') - await fs.writeFile(preNccFilename, validateCode) - await task - .source('./dist/next-config-validate.js') - .ncc({}) - .target('dist/next-config-validate') - - await fs.unlink(preNccFilename) - await fs.rename( - join(__dirname, 'dist/next-config-validate/next-config-validate.js'), - join(__dirname, 'dist/next-config-validate.js') - ) - await fs.rmdir(join(__dirname, 'dist/next-config-validate')) -} - // eslint-disable-next-line camelcase externals['acorn'] = 'next/dist/compiled/acorn' export async function ncc_acorn(task, opts) { @@ -403,23 +351,24 @@ export async function ncc_edge_runtime_cookies() { // `@edge-runtime/cookies` is precompiled and pre-bundled // so we vendor the package as it is. const dest = 'src/compiled/@edge-runtime/cookies' - const pkg = await fs.readJson( + const pkg = await readJson( require.resolve('@edge-runtime/cookies/package.json') ) - await fs.remove(dest) + await rmrf(dest) + await fs.mkdir(dest, { recursive: true }) - await fs.outputJson(join(dest, 'package.json'), { + await writeJson(join(dest, 'package.json'), { name: '@edge-runtime/cookies', version: pkg.version, main: './index.js', license: pkg.license, }) - await fs.copy( + await fs.cp( require.resolve('@edge-runtime/cookies/dist/index.js'), join(dest, 'index.js') ) - await fs.copy( + await fs.cp( require.resolve('@edge-runtime/cookies/dist/index.d.ts'), join(dest, 'index.d.ts') ) @@ -433,34 +382,34 @@ export async function ncc_edge_runtime_primitives() { // `@edge-runtime/primitives` is precompiled and pre-bundled // so we vendor the package as it is. const dest = 'src/compiled/@edge-runtime/primitives' - await fs.mkdirp(dest) + await fs.mkdir(dest, { recursive: true }) const primitivesPath = dirname( require.resolve('@edge-runtime/primitives/package.json') ) - const pkg = await fs.readJson( + const pkg = await readJson( require.resolve('@edge-runtime/primitives/package.json') ) - await fs.remove(dest) + await rmrf(dest) for (const file of await fs.readdir(join(primitivesPath, 'types'))) { - await fs.copy(join(primitivesPath, 'types', file), join(dest, file)) + await fs.cp(join(primitivesPath, 'types', file), join(dest, file)) } for (const file of await fs.readdir(join(primitivesPath, 'dist'))) { - await fs.copy(join(primitivesPath, 'dist', file), join(dest, file)) + await fs.cp(join(primitivesPath, 'dist', file), join(dest, file)) } - await fs.outputJson(join(dest, 'package.json'), { + await writeJson(join(dest, 'package.json'), { name: '@edge-runtime/primitives', version: pkg.version, main: './index.js', license: pkg.license, }) - await fs.copy( + await fs.cp( require.resolve('@edge-runtime/primitives'), join(dest, 'index.js') ) - await fs.copy( + await fs.cp( require.resolve('@edge-runtime/primitives/types/index.d.ts'), join(dest, 'index.d.ts') ) @@ -474,23 +423,25 @@ export async function ncc_edge_runtime_ponyfill(task, opts) { require.resolve('@edge-runtime/ponyfill/src/index.js'), 'utf8' ) - await fs.outputFile( - 'src/compiled/@edge-runtime/ponyfill/index.js', + const dest = 'src/compiled/@edge-runtime/ponyfill' + await fs.mkdir(dest, { recursive: true }) + await fs.writeFile( + join(dest, 'index.js'), indexFile.replace( `require('@edge-runtime/primitives')`, `require(${JSON.stringify(externals['@edge-runtime/primitives'])})` ) ) - await fs.copy( + await fs.cp( require.resolve('@edge-runtime/ponyfill/src/index.d.ts'), - 'src/compiled/@edge-runtime/ponyfill/index.d.ts' + join(dest, 'index.d.ts') ) - const pkg = await fs.readJson( + const pkg = await readJson( require.resolve('@edge-runtime/ponyfill/package.json') ) - await fs.outputJson('src/compiled/@edge-runtime/ponyfill/package.json', { + await writeJson(join(dest, 'package.json'), { name: '@edge-runtime/ponyfill', version: pkg.version, main: './index.js', @@ -578,10 +529,10 @@ export async function ncc_next__react_dev_overlay(task, opts) { __dirname, 'dist/compiled/@next/react-dev-overlay/dist/client.js' ) - const content = fs.readFileSync(clientFile, 'utf8') + const content = await fs.readFile(clientFile, 'utf8') // remove AMD define branch as this forces the module to not // be treated as commonjs - fs.writeFileSync( + await fs.writeFile( clientFile, content.replace( new RegExp( @@ -601,10 +552,10 @@ export async function ncc_next_font(task, opts) { // `@next/font` can be copied as is, its only dependency is already NCCed const destDir = join(__dirname, 'dist/compiled/@next/font') const pkgPath = require.resolve('@next/font/package.json') - const pkg = await fs.readJson(pkgPath) + const pkg = await readJson(pkgPath) const srcDir = dirname(pkgPath) - await fs.remove(destDir) - await fs.ensureDir(destDir) + await rmrf(destDir) + await fs.mkdir(destDir, { recursive: true }) const files = glob.sync('{dist,google,local}/**/*.{js,json,d.ts}', { cwd: srcDir, @@ -612,11 +563,11 @@ export async function ncc_next_font(task, opts) { for (const file of files) { const outputFile = join(destDir, file) - await fs.ensureDir(dirname(outputFile)) - await fs.copyFile(join(srcDir, file), outputFile) + await fs.mkdir(dirname(outputFile), { recursive: true }) + await fs.cp(join(srcDir, file), outputFile) } - await fs.outputJson(join(destDir, 'package.json'), { + await writeJson(join(destDir, 'package.json'), { name: '@next/font', license: pkg.license, types: pkg.types, @@ -629,8 +580,10 @@ externals['watchpack'] = 'watchpack' // eslint-disable-next-line camelcase externals['jest-worker'] = 'next/dist/compiled/jest-worker' export async function ncc_jest_worker(task, opts) { - await fs.remove(join(__dirname, 'src/compiled/jest-worker')) - await fs.ensureDir(join(__dirname, 'src/compiled/jest-worker/workers')) + await rmrf(join(__dirname, 'src/compiled/jest-worker')) + await fs.mkdir(join(__dirname, 'src/compiled/jest-worker/workers'), { + recursive: true, + }) const workers = ['processChild.js', 'threadChild.js'] @@ -670,22 +623,22 @@ export async function ncc_jest_worker(task, opts) { .ncc({ externals }) .target('src/compiled/jest-worker/out') - await fs.move( + await fs.rename( join(__dirname, 'src/compiled/jest-worker/out', worker + '.tmp.js'), - join(__dirname, 'src/compiled/jest-worker', worker), - { overwrite: true } + join(__dirname, 'src/compiled/jest-worker', worker) ) } - await fs.remove(join(__dirname, 'src/compiled/jest-worker/workers')) - await fs.remove(join(__dirname, 'src/compiled/jest-worker/out')) + await rmrf(join(__dirname, 'src/compiled/jest-worker/workers')) + await rmrf(join(__dirname, 'src/compiled/jest-worker/out')) } // eslint-disable-next-line camelcase export async function ncc_react_refresh_utils(task, opts) { - await fs.remove(join(__dirname, 'dist/compiled/react-refresh')) - await fs.copy( + await rmrf(join(__dirname, 'dist/compiled/react-refresh')) + await fs.cp( dirname(require.resolve('react-refresh/package.json')), - join(__dirname, 'dist/compiled/react-refresh') + join(__dirname, 'dist/compiled/react-refresh'), + { recursive: true, force: true } ) const srcDir = join( @@ -696,8 +649,8 @@ export async function ncc_react_refresh_utils(task, opts) { __dirname, 'dist/compiled/@next/react-refresh-utils/dist' ) - await fs.remove(destDir) - await fs.ensureDir(destDir) + await rmrf(destDir) + await fs.mkdir(destDir, { recursive: true }) const files = glob.sync('**/*.{js,json}', { cwd: srcDir }) @@ -707,7 +660,7 @@ export async function ncc_react_refresh_utils(task, opts) { const content = await fs.readFile(join(srcDir, file), 'utf8') const outputFile = join(destDir, file) - await fs.ensureDir(dirname(outputFile)) + await fs.mkdir(dirname(outputFile), { recursive: true }) await fs.writeFile( outputFile, content.replace( @@ -857,9 +810,9 @@ export async function copy_constants_browserify(task, opts) { await fs.mkdir(join(__dirname, 'src/compiled/constants-browserify'), { recursive: true, }) - await fs.writeFile( + await writeJson( join(__dirname, 'src/compiled/constants-browserify/package.json'), - JSON.stringify({ name: 'constants-browserify', main: './constants.json' }) + { name: 'constants-browserify', main: './constants.json' } ) await task .source(require.resolve('constants-browserify')) @@ -922,11 +875,11 @@ export async function ncc_stream_browserify(task, opts) { // reference breaking the browser polyfill const outputFile = join(__dirname, 'src/compiled/stream-browserify/index.js') - fs.writeFileSync( + await fs.writeFile( outputFile, - fs - .readFileSync(outputFile, 'utf8') - .replace(`require("stream")`, `require("events").EventEmitter`) + ( + await fs.readFile(outputFile, 'utf8') + ).replace(`require("stream")`, `require("events").EventEmitter`) ) } @@ -982,7 +935,7 @@ export async function ncc_path_browserify(task, opts) { .target('src/compiled/path-browserify') const filePath = join(__dirname, 'src/compiled/path-browserify/index.js') - const content = fs.readFileSync(filePath, 'utf8') + const content = await fs.readFile(filePath, 'utf8') // Remove process usage from path-browserify polyfill for edge-runtime await fs.writeFile(filePath, content.replace(/process\.cwd\(\)/g, '""')) @@ -1150,16 +1103,6 @@ export async function ncc_async_sema(task, opts) { .ncc({ packageName: 'async-sema', externals }) .target('src/compiled/async-sema') } -// eslint-disable-next-line camelcase -export async function ncc_segment_ajv_human_errors(task, opts) { - await task - .source(relative(__dirname, require.resolve('@segment/ajv-human-errors/'))) - .ncc({ - packageName: '@segment/ajv-human-errors/', - externals, - }) - .target('src/compiled/@segment/ajv-human-errors') -} externals['postcss-plugin-stub-for-cssnano-simple'] = 'next/dist/compiled/postcss-plugin-stub-for-cssnano-simple' @@ -1218,7 +1161,7 @@ export async function ncc_babel_bundle_packages(task, opts) { dirname(require.resolve('@babel/eslint-parser')), './parse.cjs' ) - const content = fs.readFileSync(eslintParseFile, 'utf-8') + const content = await fs.readFile(eslintParseFile, 'utf-8') // Let parser.cjs require @babel/parser directly const replacedContent = content .replace( @@ -1235,10 +1178,10 @@ export async function ncc_babel_bundle_packages(task, opts) { }) .target(`src/compiled/babel-packages`) - await fs.writeFile( - join(__dirname, 'src/compiled/babel-packages/package.json'), - JSON.stringify({ name: 'babel-packages', main: './packages-bundle.js' }) - ) + await writeJson(join(__dirname, 'src/compiled/babel-packages/package.json'), { + name: 'babel-packages', + main: './packages-bundle.js', + }) await task.source('src/bundles/babel/packages/*').target('src/compiled/babel') } @@ -1792,7 +1735,7 @@ export async function copy_vendor_react(task_) { 'unstable_server-external-runtime.js', ] for (const item of itemsToRemove) { - yield fs.remove(join(reactDomCompiledDir, item)) + yield rmrf(join(reactDomCompiledDir, item)) } // react-server-dom-webpack @@ -2035,7 +1978,7 @@ export async function ncc_unistore(task, opts) { } // eslint-disable-next-line camelcase -externals['unistore'] = 'next/dist/compiled/superstruct' +externals['superstruct'] = 'next/dist/compiled/superstruct' export async function ncc_superstruct(task, opts) { await task .source(relative(__dirname, require.resolve('superstruct'))) @@ -2043,6 +1986,14 @@ export async function ncc_superstruct(task, opts) { .target('src/compiled/superstruct') } +externals['zod'] = 'next/dist/compiled/zod' +export async function ncc_zod(task, opts) { + await task + .source(relative(__dirname, require.resolve('zod'))) + .ncc({ packageName: 'zod', externals }) + .target('src/compiled/zod') +} + // eslint-disable-next-line camelcase externals['web-vitals'] = 'next/dist/compiled/web-vitals' export async function ncc_web_vitals(task, opts) { @@ -2292,7 +2243,6 @@ export async function ncc(task, opts) { 'ncc_arg', 'ncc_async_retry', 'ncc_async_sema', - 'ncc_segment_ajv_human_errors', 'ncc_postcss_plugin_stub_for_cssnano_simple', 'ncc_assert', 'ncc_browser_zlib', @@ -2366,6 +2316,7 @@ export async function ncc(task, opts) { 'ncc_string_hash', 'ncc_strip_ansi', 'ncc_superstruct', + 'ncc_zod', 'ncc_nft', 'ncc_tar', 'ncc_terser', @@ -2664,10 +2615,7 @@ export async function trace(task, opts) { } export async function build(task, opts) { - await task.serial( - ['precompile', 'compile', 'compile_config_schema', 'generate_types'], - opts - ) + await task.serial(['precompile', 'compile', 'generate_types'], opts) } export async function generate_types(task, opts) { @@ -2910,3 +2858,18 @@ export async function next_bundle(task, opts) { opts ) } + +function writeJson(file, obj, { spaces = 0 } = {}) { + return fs.writeFile( + file, + JSON.stringify(obj, null, spaces) + (spaces === 0 ? '\n' : '') + ) +} + +function rmrf(path, options) { + return fs.rm(path, { recursive: true, force: true, ...options }) +} + +function readJson(path) { + return fs.readFile(path, 'utf8').then((content) => JSON.parse(content)) +} diff --git a/packages/next/types/compiled.d.ts b/packages/next/types/compiled.d.ts index e53f2a5d2657..7d6707c1e657 100644 --- a/packages/next/types/compiled.d.ts +++ b/packages/next/types/compiled.d.ts @@ -8,6 +8,8 @@ declare module 'next/dist/compiled/webpack/webpack' { export let GraphHelpers: any export let sources: any export let StringXor: any + // eslint-disable-next-line @typescript-eslint/no-unused-vars + export type LoaderDefinitionFunction = any namespace webpack { export type Compiler = any export type WebpackPluginInstance = any @@ -44,3 +46,10 @@ declare module 'next/dist/compiled/superstruct' { // eslint-disable-next-line @typescript-eslint/no-unused-vars export type Describe = any } + +declare module 'react-server-dom-webpack/server.edge' + +declare module 'VAR_MODULE_GLOBAL_ERROR' +declare module 'VAR_USERLAND' +declare module 'VAR_MODULE_DOCUMENT' +declare module 'VAR_MODULE_APP' diff --git a/packages/next/types/misc.d.ts b/packages/next/types/misc.d.ts index f3c438e780ad..e2bf73cc271b 100644 --- a/packages/next/types/misc.d.ts +++ b/packages/next/types/misc.d.ts @@ -35,6 +35,11 @@ declare module 'react-dom/server-rendering-stub' declare module 'react-dom/server.browser' declare module 'react-dom/server.edge' +declare module 'VAR_MODULE_GLOBAL_ERROR' +declare module 'VAR_USERLAND' +declare module 'VAR_MODULE_DOCUMENT' +declare module 'VAR_MODULE_APP' + declare module 'next/dist/compiled/@next/react-dev-overlay/dist/client' { export * from '@next/react-dev-overlay/dist/client' } @@ -383,11 +388,6 @@ declare module 'next/dist/compiled/@edge-runtime/primitives' { export = m } -declare module 'next/dist/compiled/@segment/ajv-human-errors' { - import * as m from '@segment/ajv-human-errors' - export = m -} - declare module 'next/dist/compiled/react' { import * as m from 'react' export = m @@ -475,3 +475,8 @@ declare module 'next/dist/compiled/@opentelemetry/api' { import * as m from '@opentelemetry/api' export = m } + +declare module 'next/dist/compiled/zod' { + import * as m from 'zod' + export = m +} diff --git a/packages/next/types/webpack.d.ts b/packages/next/types/webpack.d.ts index caba6a1b1688..64e68d48e904 100644 --- a/packages/next/types/webpack.d.ts +++ b/packages/next/types/webpack.d.ts @@ -34,6 +34,7 @@ declare module 'next/dist/compiled/webpack/webpack' { export let sources: typeof webpackSources export let StringXor: any export { + default as webpack, Compiler, Compilation, Module, @@ -43,6 +44,8 @@ declare module 'next/dist/compiled/webpack/webpack' { RuntimeGlobals, NormalModule, ResolvePluginInstance, + ModuleFilenameHelpers, + LoaderDefinitionFunction, + LoaderContext, } from 'webpack' - export { default as webpack, ModuleFilenameHelpers } from 'webpack' } diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 81edef1fd77a..69403242ad9d 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 6c648bd5fc2d..0fcf62ad96dc 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/packages/third-parties/package.json b/packages/third-parties/package.json index fbef1a4a4f25..8ab2869965ee 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "13.5.5-canary.2", + "version": "13.5.5-canary.3", "private": true, "repository": { "url": "vercel/next.js", @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "13.5.5-canary.2", + "next": "13.5.5-canary.3", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 22bfb1ffa1aa..a31c55dd5bc7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -732,7 +732,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 13.5.5-canary.2 + specifier: 13.5.5-canary.3 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -793,7 +793,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 13.5.5-canary.2 + specifier: 13.5.5-canary.3 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -917,19 +917,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 13.5.5-canary.2 + specifier: 13.5.5-canary.3 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 13.5.5-canary.2 + specifier: 13.5.5-canary.3 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 13.5.5-canary.2 + specifier: 13.5.5-canary.3 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 13.5.5-canary.2 + specifier: 13.5.5-canary.3 version: link:../react-refresh-utils '@next/swc': - specifier: 13.5.5-canary.2 + specifier: 13.5.5-canary.3 version: link:../next-swc '@opentelemetry/api': specifier: 1.4.1 @@ -937,9 +937,6 @@ importers: '@playwright/test': specifier: ^1.35.1 version: 1.35.1 - '@segment/ajv-human-errors': - specifier: 2.1.2 - version: 2.1.2(ajv@8.11.0) '@taskr/clear': specifier: 1.1.0 version: 1.1.0 @@ -1061,14 +1058,11 @@ importers: specifier: 0.22.6 version: 0.22.6 '@vercel/turbopack-ecmascript-runtime': - specifier: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231002.1 - version: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231002.1(react-refresh@0.12.0)(webpack@5.86.0)' + specifier: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231006.2 + version: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231006.2(react-refresh@0.12.0)(webpack@5.86.0)' acorn: specifier: 8.5.0 version: 8.5.0 - ajv: - specifier: 8.11.0 - version: 8.11.0 amphtml-validator: specifier: 1.0.35 version: 1.0.35 @@ -1426,6 +1420,9 @@ importers: ws: specifier: 8.2.3 version: 8.2.3 + zod: + specifier: 3.22.3 + version: 3.22.3 packages/next-bundle-analyzer: dependencies: @@ -1586,7 +1583,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 13.5.5-canary.2 + specifier: 13.5.5-canary.3 version: link:../next outdent: specifier: 0.8.0 @@ -6716,8 +6713,8 @@ packages: resolution: {integrity: sha512-XQr74QaLeMiqhStEhLn1im9EOMnkypp7MZOwQhGzqp2Weu5eQJbpPxWxixxlYRKWPOmJjsk6qYfYH9kq43yc2w==} dev: true - /@next/react-refresh-utils@13.5.3(react-refresh@0.12.0)(webpack@5.86.0): - resolution: {integrity: sha512-Y4wsqtdX+/QZ6W19N3y/YnuxAt/a79l/zYmRc2mwEplP0rIv6W3MBo3ePFUXOMVfmVesnOhfnZanaGiynZcFOg==} + /@next/react-refresh-utils@13.5.4(react-refresh@0.12.0)(webpack@5.86.0): + resolution: {integrity: sha512-Y2bFd17Gn5Wh1gT/P/xTlApmipdrD0JdTdMwhi8G2wD2qj8p7SZbci1kp7zp+utWVp8PFQD6kHAIBrJS9/iEQQ==} peerDependencies: react-refresh: 0.12.0 webpack: 5.86.0 @@ -7410,14 +7407,6 @@ packages: rxjs: 6.6.2 dev: true - /@segment/ajv-human-errors@2.1.2(ajv@8.11.0): - resolution: {integrity: sha512-d1uQndRFLRO01+xW1y5m+joxDgHf5SLJ70YCY2ArLoo2FJ50o6AoX2mEbuGvnKz/IdwnvDugm9Ti3mZQkW1OoA==} - peerDependencies: - ajv: ^8.0.0 - dependencies: - ajv: 8.11.0 - dev: true - /@shuding/opentype.js@1.4.0-beta.0: resolution: {integrity: sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==} engines: {node: '>= 8.0.0'} @@ -9093,7 +9082,7 @@ packages: fast-deep-equal: 3.1.3 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - uri-js: 4.2.2 + uri-js: 4.4.1 dev: true /alex@9.1.0: @@ -25940,12 +25929,6 @@ packages: tslib: 2.6.2 dev: true - /uri-js@4.2.2: - resolution: {integrity: sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==} - dependencies: - punycode: 2.1.1 - dev: true - /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: @@ -26763,6 +26746,10 @@ packages: resolution: {integrity: sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==} dev: true + /zod@3.22.3: + resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} + dev: true + /zwitch@1.0.5: resolution: {integrity: sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==} dev: true @@ -26770,13 +26757,13 @@ packages: /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231002.1(react-refresh@0.12.0)(webpack@5.86.0)': - resolution: {tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231002.1} - id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231002.1' + '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231006.2(react-refresh@0.12.0)(webpack@5.86.0)': + resolution: {tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231006.2} + id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231006.2' name: '@vercel/turbopack-ecmascript-runtime' version: 0.0.0 dependencies: - '@next/react-refresh-utils': 13.5.3(react-refresh@0.12.0)(webpack@5.86.0) + '@next/react-refresh-utils': 13.5.4(react-refresh@0.12.0)(webpack@5.86.0) '@types/node': 20.2.5 transitivePeerDependencies: - react-refresh diff --git a/test/development/acceptance-app/fixtures/rsc-build-errors/next.config.js b/test/development/acceptance-app/fixtures/rsc-build-errors/next.config.js deleted file mode 100644 index 4ba52ba2c8df..000000000000 --- a/test/development/acceptance-app/fixtures/rsc-build-errors/next.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {} diff --git a/test/development/acceptance-app/fixtures/rsc-runtime-errors/app/client/page.js b/test/development/acceptance-app/fixtures/rsc-runtime-errors/app/client/page.js new file mode 100644 index 000000000000..33f94c1f46b0 --- /dev/null +++ b/test/development/acceptance-app/fixtures/rsc-runtime-errors/app/client/page.js @@ -0,0 +1,4 @@ +'use client' +export default function page() { + return 'page' +} diff --git a/test/development/acceptance-app/fixtures/rsc-runtime-errors/app/layout.js b/test/development/acceptance-app/fixtures/rsc-runtime-errors/app/layout.js new file mode 100644 index 000000000000..8525f5f8c0b2 --- /dev/null +++ b/test/development/acceptance-app/fixtures/rsc-runtime-errors/app/layout.js @@ -0,0 +1,12 @@ +export const metadata = { + title: 'Next.js', + description: 'Generated by Next.js', +} + +export default function RootLayout({ children }) { + return ( + + {children} + + ) +} diff --git a/test/development/acceptance-app/fixtures/rsc-runtime-errors/app/server/page.js b/test/development/acceptance-app/fixtures/rsc-runtime-errors/app/server/page.js new file mode 100644 index 000000000000..41c1c6b78dff --- /dev/null +++ b/test/development/acceptance-app/fixtures/rsc-runtime-errors/app/server/page.js @@ -0,0 +1,3 @@ +export default function page() { + return 'page' +} diff --git a/test/development/acceptance-app/fixtures/rsc-runtime-errors/node_modules_bak/client-package/index.js b/test/development/acceptance-app/fixtures/rsc-runtime-errors/node_modules_bak/client-package/index.js new file mode 100644 index 000000000000..6e5c0b4e8820 --- /dev/null +++ b/test/development/acceptance-app/fixtures/rsc-runtime-errors/node_modules_bak/client-package/index.js @@ -0,0 +1,6 @@ +import { useState } from 'react' + +export function callClientApi() { + // eslint-disable-next-line react-hooks/rules-of-hooks + return useState(0) +} diff --git a/test/development/acceptance-app/fixtures/rsc-runtime-errors/node_modules_bak/client-package/package.json b/test/development/acceptance-app/fixtures/rsc-runtime-errors/node_modules_bak/client-package/package.json new file mode 100644 index 000000000000..5f196b3ba2bd --- /dev/null +++ b/test/development/acceptance-app/fixtures/rsc-runtime-errors/node_modules_bak/client-package/package.json @@ -0,0 +1,4 @@ +{ + "name": "client-package", + "exports": "./index.js" +} diff --git a/test/development/acceptance-app/fixtures/rsc-runtime-errors/node_modules_bak/server-package/index.js b/test/development/acceptance-app/fixtures/rsc-runtime-errors/node_modules_bak/server-package/index.js new file mode 100644 index 000000000000..a0b959e43331 --- /dev/null +++ b/test/development/acceptance-app/fixtures/rsc-runtime-errors/node_modules_bak/server-package/index.js @@ -0,0 +1,7 @@ +'use client' + +import { cookies } from 'next/headers' + +export function callServerApi() { + return cookies() +} diff --git a/test/development/acceptance-app/fixtures/rsc-runtime-errors/node_modules_bak/server-package/package.json b/test/development/acceptance-app/fixtures/rsc-runtime-errors/node_modules_bak/server-package/package.json new file mode 100644 index 000000000000..ba9bc67edc39 --- /dev/null +++ b/test/development/acceptance-app/fixtures/rsc-runtime-errors/node_modules_bak/server-package/package.json @@ -0,0 +1,4 @@ +{ + "name": "server-package", + "exports": "./index.js" +} diff --git a/test/development/acceptance-app/rsc-build-errors.test.ts b/test/development/acceptance-app/rsc-build-errors.test.ts index 1e8bbacb26e4..f65a33bc38a4 100644 --- a/test/development/acceptance-app/rsc-build-errors.test.ts +++ b/test/development/acceptance-app/rsc-build-errors.test.ts @@ -379,63 +379,4 @@ describe('Error overlay - RSC build errors', () => { await cleanup() }) - - it('should show which import caused an error in node_modules', async () => { - const { session, cleanup } = await sandbox( - next, - new Map([ - [ - 'node_modules/client-package/module2.js', - "import { useState } from 'react'", - ], - ['node_modules/client-package/module1.js', "import './module2.js'"], - ['node_modules/client-package/index.js', "import './module1.js'"], - [ - 'node_modules/client-package/package.json', - outdent` - { - "name": "client-package", - "version": "0.0.1" - } - `, - ], - ['app/Component.js', "import 'client-package'"], - [ - 'app/page.js', - outdent` - import './Component.js' - export default function Page() { - return

Hello world

- } - `, - ], - ]) - ) - - expect(await session.hasRedbox(true)).toBe(true) - expect( - next.normalizeTestDirContent(await session.getRedboxSource()) - ).toMatchInlineSnapshot( - next.normalizeSnapshot(` - "./app/Component.js - ReactServerComponentsError: - - You're importing a component that needs useState. It only works in a Client Component but none of its parents are marked with \\"use client\\", so they're Server Components by default. - Learn more: https://nextjs.org/docs/getting-started/react-essentials - - ,-[TEST_DIR/node_modules/client-package/module2.js:1:1] - 1 | import { useState } from 'react' - : ^^^^^^^^ - \`---- - - The error was caused by importing 'client-package/index.js' in './app/Component.js'. - - Maybe one of these should be marked as a client entry with \\"use client\\": - ./app/Component.js - ./app/page.js" - `) - ) - - await cleanup() - }) }) diff --git a/test/development/acceptance-app/rsc-runtime-errors.test.ts b/test/development/acceptance-app/rsc-runtime-errors.test.ts new file mode 100644 index 000000000000..41b2688f3158 --- /dev/null +++ b/test/development/acceptance-app/rsc-runtime-errors.test.ts @@ -0,0 +1,80 @@ +import path from 'path' +import { outdent } from 'outdent' +import { FileRef, createNextDescribe } from 'e2e-utils' +import { + check, + getRedboxDescription, + hasRedbox, + shouldRunTurboDevTest, +} from 'next-test-utils' + +createNextDescribe( + 'Error overlay - RSC runtime errors', + { + files: new FileRef(path.join(__dirname, 'fixtures', 'rsc-runtime-errors')), + packageJson: { + scripts: { + setup: 'cp -r ./node_modules_bak/* ./node_modules', + build: 'yarn setup && next build', + dev: `yarn setup && next ${ + shouldRunTurboDevTest() ? 'dev --turbo' : 'dev' + }`, + start: 'next start', + }, + }, + installCommand: 'yarn', + startCommand: (global as any).isNextDev ? 'yarn dev' : 'yarn start', + }, + ({ next }) => { + it('should show runtime errors if invalid client API from node_modules is executed', async () => { + await next.patchFile( + 'app/server/page.js', + outdent` + import { callClientApi } from 'client-package' + export default function Page() { + callClientApi() + return 'page' + } + ` + ) + + const browser = await next.browser('/server') + + await check( + async () => ((await hasRedbox(browser, true)) ? 'success' : 'fail'), + /success/ + ) + const errorDescription = await getRedboxDescription(browser) + + expect(errorDescription).toContain( + `Error: useState only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component` + ) + }) + + it('should show runtime errors if invalid server API from node_modules is executed', async () => { + await next.patchFile( + 'app/client/page.js', + outdent` + 'use client' + import { callServerApi } from 'server-package' + export default function Page() { + callServerApi() + return 'page' + } + ` + ) + + const browser = await next.browser('/client') + + await check( + async () => ((await hasRedbox(browser, true)) ? 'success' : 'fail'), + /success/ + ) + const errorDescription = await getRedboxDescription(browser) + + expect(errorDescription).toContain( + `Error: Invariant: cookies() expects to have requestAsyncStorage, none available.` + ) + }) + } +) diff --git a/test/e2e/app-dir/actions/next.config.js b/test/e2e/app-dir/actions/next.config.js index fcfc7dcc99ba..bec00d8d3b47 100644 --- a/test/e2e/app-dir/actions/next.config.js +++ b/test/e2e/app-dir/actions/next.config.js @@ -2,7 +2,9 @@ module.exports = { productionBrowserSourceMaps: true, experimental: { - logging: 'verbose', + logging: { + level: 'verbose', + }, serverActions: true, }, } diff --git a/test/e2e/app-dir/app-css-pageextensions/index.test.ts b/test/e2e/app-dir/app-css-pageextensions/index.test.ts index 81a13a361d05..a2cb488426ae 100644 --- a/test/e2e/app-dir/app-css-pageextensions/index.test.ts +++ b/test/e2e/app-dir/app-css-pageextensions/index.test.ts @@ -1,7 +1,7 @@ import { createNextDescribe } from 'e2e-utils' createNextDescribe( - 'app dir css with pageextensions', + 'app dir - css with pageextensions', { files: __dirname, skipDeployment: true, diff --git a/test/e2e/app-dir/app-css/index.test.ts b/test/e2e/app-dir/app-css/index.test.ts index 4b160a299c89..3d1ac7277e93 100644 --- a/test/e2e/app-dir/app-css/index.test.ts +++ b/test/e2e/app-dir/app-css/index.test.ts @@ -2,7 +2,7 @@ import { createNextDescribe } from 'e2e-utils' import { check } from 'next-test-utils' createNextDescribe( - 'app dir css', + 'app dir - css', { files: __dirname, skipDeployment: true, diff --git a/test/e2e/app-dir/app-middleware/app-middleware.test.ts b/test/e2e/app-dir/app-middleware/app-middleware.test.ts index 80f0bae676d8..661839a2aa37 100644 --- a/test/e2e/app-dir/app-middleware/app-middleware.test.ts +++ b/test/e2e/app-dir/app-middleware/app-middleware.test.ts @@ -138,7 +138,7 @@ createNextDescribe( ) createNextDescribe( - 'app dir middleware without pages dir', + 'app dir - middleware without pages dir', { files: { app: new FileRef(path.join(__dirname, 'app')), @@ -168,7 +168,7 @@ createNextDescribe( ) createNextDescribe( - 'app dir middleware with middleware in src dir', + 'app dir - middleware with middleware in src dir', { files: { 'src/app': new FileRef(path.join(__dirname, 'app')), diff --git a/test/e2e/app-dir/app-prefetch/prefetching.test.ts b/test/e2e/app-dir/app-prefetch/prefetching.test.ts index 2d9b47669089..9d14424c3c6b 100644 --- a/test/e2e/app-dir/app-prefetch/prefetching.test.ts +++ b/test/e2e/app-dir/app-prefetch/prefetching.test.ts @@ -28,7 +28,7 @@ const browserConfigWithFixedTime = { } createNextDescribe( - 'app dir prefetching', + 'app dir - prefetching', { files: __dirname, skipDeployment: true, diff --git a/test/e2e/app-dir/app-validation/validation.test.ts b/test/e2e/app-dir/app-validation/validation.test.ts index b00dde4d778e..3146ece06b95 100644 --- a/test/e2e/app-dir/app-validation/validation.test.ts +++ b/test/e2e/app-dir/app-validation/validation.test.ts @@ -1,7 +1,7 @@ import { createNextDescribe } from 'e2e-utils' createNextDescribe( - 'app dir validation', + 'app dir - validation', { files: __dirname, skipDeployment: true, diff --git a/test/e2e/app-dir/app/index.test.ts b/test/e2e/app-dir/app/index.test.ts index e082ebfe292b..c69fef660f5d 100644 --- a/test/e2e/app-dir/app/index.test.ts +++ b/test/e2e/app-dir/app/index.test.ts @@ -6,7 +6,7 @@ import { BrowserInterface } from 'test/lib/browsers/base' import { Request } from 'playwright-core' createNextDescribe( - 'app dir', + 'app dir - basic', { files: __dirname, buildCommand: process.env.NEXT_EXPERIMENTAL_COMPILE diff --git a/test/e2e/app-dir/import/import.test.ts b/test/e2e/app-dir/import/import.test.ts index 24743f773f62..55d313ba8188 100644 --- a/test/e2e/app-dir/import/import.test.ts +++ b/test/e2e/app-dir/import/import.test.ts @@ -1,7 +1,7 @@ import { createNextDescribe } from 'e2e-utils' createNextDescribe( - 'app dir imports', + 'app dir - imports', { files: __dirname, }, diff --git a/test/e2e/app-dir/next-font/next-font.test.ts b/test/e2e/app-dir/next-font/next-font.test.ts index 4320d6b556ea..77a8feeb6c7f 100644 --- a/test/e2e/app-dir/next-font/next-font.test.ts +++ b/test/e2e/app-dir/next-font/next-font.test.ts @@ -25,7 +25,7 @@ const getAttrs = (elems: Cheerio) => describe.each([['app'], ['app-old']])('%s', (fixture: string) => { createNextDescribe( - 'app dir next-font', + 'app dir - next-font', { files: { app: new FileRef(join(__dirname, fixture)), diff --git a/test/e2e/app-dir/next-image/next-image-https.test.ts b/test/e2e/app-dir/next-image/next-image-https.test.ts index fd97a867d8cb..7f45437fa791 100644 --- a/test/e2e/app-dir/next-image/next-image-https.test.ts +++ b/test/e2e/app-dir/next-image/next-image-https.test.ts @@ -1,7 +1,7 @@ import { createNextDescribe } from '../../../lib/e2e-utils' createNextDescribe( - 'app dir next-image (with https)', + 'app dir - next-image (with https)', { files: __dirname, skipDeployment: true, diff --git a/test/e2e/app-dir/next-image/next-image.test.ts b/test/e2e/app-dir/next-image/next-image.test.ts index 108dfef63edb..2640b56ed107 100644 --- a/test/e2e/app-dir/next-image/next-image.test.ts +++ b/test/e2e/app-dir/next-image/next-image.test.ts @@ -1,7 +1,7 @@ import { createNextDescribe } from 'e2e-utils' createNextDescribe( - 'app dir next-image', + 'app dir - next-image', { files: __dirname, skipDeployment: true, diff --git a/test/e2e/skip-trailing-slash-redirect/index.test.ts b/test/e2e/skip-trailing-slash-redirect/index.test.ts index d9cf1e90adbe..2b0d9ca7df64 100644 --- a/test/e2e/skip-trailing-slash-redirect/index.test.ts +++ b/test/e2e/skip-trailing-slash-redirect/index.test.ts @@ -367,7 +367,7 @@ describe('skip-trailing-slash-redirect', () => { runSharedTests('/') }) - describe('app dir', () => { + describe('app dir - skip trailing slash redirect', () => { runSharedTests('/with-app-dir/') }) }) diff --git a/test/integration/app-dir-export/test/config.test.ts b/test/integration/app-dir-export/test/config.test.ts index 79e5c8456905..1cfe54c76d3b 100644 --- a/test/integration/app-dir-export/test/config.test.ts +++ b/test/integration/app-dir-export/test/config.test.ts @@ -10,7 +10,7 @@ import { nextConfig, } from './utils' -describe('app dir with output export (next dev / next build)', () => { +describe('app dir - with output export (next dev / next build)', () => { ;(process.env.TURBOPACK ? describe.skip : describe)('production mode', () => { it('should throw when exportPathMap configured', async () => { nextConfig.replace( diff --git a/test/integration/app-dir-export/test/start.test.ts b/test/integration/app-dir-export/test/start.test.ts index b7d5241493c1..a801470efd70 100644 --- a/test/integration/app-dir-export/test/start.test.ts +++ b/test/integration/app-dir-export/test/start.test.ts @@ -17,7 +17,7 @@ const exportDir = join(appDir, 'out') const nextConfig = new File(join(appDir, 'next.config.js')) let app -describe('app dir with output export (next start)', () => { +describe('app dir - with output export (next start)', () => { ;(process.env.TURBOPACK ? describe.skip : describe)('production mode', () => { afterEach(async () => { await killApp(app) diff --git a/test/integration/config-experimental-warning/test/index.test.js b/test/integration/config-experimental-warning/test/index.test.js index 79831f282680..a4a6bed21fae 100644 --- a/test/integration/config-experimental-warning/test/index.test.js +++ b/test/integration/config-experimental-warning/test/index.test.js @@ -19,17 +19,6 @@ async function collectStdout(appDir) { return stdout } -async function collectStderr(appDir) { - let stderr = '' - const port = await findPort() - app = await launchApp(appDir, port, { - onStderr(msg) { - stderr += msg - }, - }) - return stderr -} - describe('Config Experimental Warning', () => { afterEach(() => { configFile.write('') @@ -123,19 +112,4 @@ describe('Config Experimental Warning', () => { expect(stdout).toMatch(' · workerThreads') expect(stdout).toMatch(' · scrollRestoration') }) - - it('should show warning for dropped experimental.appDir option', async () => { - configFile.write(` - module.exports = { - experimental: { - appDir: true, - } - } - `) - - const stderr = await collectStderr(appDir) - expect(stderr).toMatch( - 'App router is available by default now, `experimental.appDir` option can be safely removed.' - ) - }) }) diff --git a/test/integration/config-validation/test/index.test.ts b/test/integration/config-validation/test/index.test.ts index 6f44afe56168..74c5b8f738c1 100644 --- a/test/integration/config-validation/test/index.test.ts +++ b/test/integration/config-validation/test/index.test.ts @@ -19,9 +19,9 @@ describe('next.config.js validation', () => { } `, outputs: [ - 'The value at .images.loader must be one of', - 'The value at .rewrites must be a function that returns a Promise', - 'The value at .swcMinify must be a boolean but it was a string', + `received 'something' at "images.loader"`, + 'Expected function, received boolean at "rewrites"', + 'Expected boolean, received string at "swcMinify"', ], }, { @@ -35,8 +35,8 @@ describe('next.config.js validation', () => { } `, outputs: [ - 'The root value has an unexpected property, nonExistent,', - 'The value at .experimental has an unexpected property, anotherNonExistent', + `Unrecognized key(s) in object: 'nonExistent'`, + `Unrecognized key(s) in object: 'anotherNonExistent' at "experimental"`, ], }, ])( diff --git a/test/integration/custom-routes/test/index.test.js b/test/integration/custom-routes/test/index.test.js index 0a77ca7db82f..0ba6ce2ffbd7 100644 --- a/test/integration/custom-routes/test/index.test.js +++ b/test/integration/custom-routes/test/index.test.js @@ -38,7 +38,7 @@ let buildId let appPort let app -const runTests = (isDev = false, isTurbo = false) => { +const runTests = (isDev = false) => { it.each([ { path: '/to-ANOTHER', @@ -78,9 +78,6 @@ const runTests = (isDev = false, isTurbo = false) => { ) it('should successfully rewrite a WebSocket request', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const messages = [] const ws = await new Promise((resolve, reject) => { let socket = new WebSocket(`ws://localhost:${appPort}/to-websocket`) @@ -104,9 +101,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should successfully rewrite a WebSocket request to a page', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const messages = [] try { const ws = await new Promise((resolve, reject) => { @@ -147,9 +141,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should handle has query encoding correctly', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - for (const expected of [ { post: 'first', @@ -192,9 +183,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should handle external beforeFiles rewrite correctly', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/overridden') const html = await res.text() @@ -213,9 +201,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should handle beforeFiles rewrite to dynamic route correctly', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/nfl') const html = await res.text() @@ -242,9 +227,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should handle beforeFiles rewrite to partly dynamic route correctly', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/nfl') const html = await res.text() @@ -282,9 +264,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should resolveHref correctly navigating through history', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const browser = await webdriver(appPort, '/') await browser.eval('window.beforeNav = 1') @@ -340,9 +319,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should not hang when proxy rewrite fails', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/to-nowhere', undefined, { timeout: 5000, }) @@ -363,9 +339,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should provide params correctly for rewrite to auto-export non-dynamic page', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const browser = await webdriver( appPort, '/rewriting-to-another-auto-export/first' @@ -391,9 +364,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should handle param like headers properly', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/my-other-header/my-path') expect(res.headers.get('x-path')).toBe('my-path') expect(res.headers.get('somemy-path')).toBe('hi') @@ -412,9 +382,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should not match dynamic route immediately after applying header', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/blog/post-321') expect(res.headers.get('x-something')).toBe('applied-everywhere') @@ -581,9 +548,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should have correct encoding for params with catchall rewrite', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const html = await renderViaHTTP( appPort, '/catchall-rewrite/hello%20world%3Fw%3D24%26focalpoint%3Dcenter?a=b' @@ -606,9 +570,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should have correct header for catchall rewrite', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/catchall-header/hello/world?a=b') const headerValue = res.headers.get('x-value') expect(headerValue).toBe('hello/world') @@ -634,9 +595,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should have correctly encoded params in query for redirect', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP( appPort, '/query-redirect/hello%20world%3Fw%3D24%26focalpoint%3Dcenter/world?a=b', @@ -744,9 +702,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should work with rewrite when only specifying href', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const browser = await webdriver(appPort, '/nav') await browser.eval('window.beforeNav = 1') await browser @@ -763,9 +718,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should work with rewrite when only specifying href and ends in dynamic route', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const browser = await webdriver(appPort, '/nav') await browser.eval('window.beforeNav = 1') await browser @@ -795,9 +747,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should match /_next file after rewrite', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - await renderViaHTTP(appPort, '/hello') const data = await renderViaHTTP( appPort, @@ -816,52 +765,34 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should apply headers for exact match', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/add-header') expect(res.headers.get('x-custom-header')).toBe('hello world') expect(res.headers.get('x-another-header')).toBe('hello again') }) it('should apply headers for multi match', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/my-headers/first') expect(res.headers.get('x-first-header')).toBe('first') expect(res.headers.get('x-second-header')).toBe('second') }) it('should apply params for header key/values', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/my-other-header/first') expect(res.headers.get('x-path')).toBe('first') expect(res.headers.get('somefirst')).toBe('hi') }) it('should support URL for header key/values', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/without-params/url') expect(res.headers.get('x-origin')).toBe('https://example.com') }) it('should apply params header key/values with URL', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/with-params/url/first') expect(res.headers.get('x-url')).toBe('https://example.com/first') }) it('should apply params header key/values with URL that has port', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/with-params/url2/first') expect(res.headers.get('x-url')).toBe( 'https://example.com:8080?hello=first' @@ -869,9 +800,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should support named pattern for header key/values', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/named-pattern/hello') expect(res.headers.get('x-something')).toBe('value=hello') expect(res.headers.get('path-hello')).toBe('end') @@ -934,9 +862,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should have correctly encoded query in location and refresh headers', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP( appPort, // Query unencoded is ?テスト=あ @@ -976,9 +901,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should handle encoded value in the pathname correctly', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP( appPort, '/redirect/me/to-about/' + encodeURI('\\google.com'), @@ -1054,9 +976,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should match missing header headers correctly', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/missing-headers-1', undefined, { headers: { 'x-my-header': 'hello world!!', @@ -1072,9 +991,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should match missing query headers correctly', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/missing-headers-2', { 'my-query': 'hellooo', }) @@ -1088,9 +1004,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should match missing cookie headers correctly', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/missing-headers-3', undefined, { headers: { cookie: 'loggedIn=true', @@ -1327,9 +1240,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should match has rewrite correctly before files', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res1 = await fetchViaHTTP(appPort, '/hello') expect(res1.status).toBe(200) const $1 = cheerio.load(await res1.text()) @@ -1497,9 +1407,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should match has header for header correctly', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/has-header-1', undefined, { headers: { 'x-my-header': 'hello world!!', @@ -1516,9 +1423,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should match has query for header correctly', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP( appPort, '/has-header-2', @@ -1539,9 +1443,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should match has cookie for header correctly', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/has-header-3', undefined, { headers: { cookie: 'loggedIn=true', @@ -1558,9 +1459,6 @@ const runTests = (isDev = false, isTurbo = false) => { }) it('should match has host for header correctly', async () => { - // TODO: remove once test failure has been fixed - if (isTurbo) return - const res = await fetchViaHTTP(appPort, '/has-header-4', undefined, { headers: { host: 'example.com', diff --git a/test/integration/dist-dir/test/index.test.js b/test/integration/dist-dir/test/index.test.js index d296bc652e73..9901851d56ff 100644 --- a/test/integration/dist-dir/test/index.test.js +++ b/test/integration/dist-dir/test/index.test.js @@ -83,11 +83,11 @@ describe('distDir', () => { ) }) - it('should handle null/undefined distDir', async () => { + it('should handle undefined distDir', async () => { const origNextConfig = await fs.readFile(nextConfig, 'utf8') await fs.writeFile( nextConfig, - `module.exports = { distDir: null, eslint: { ignoreDuringBuilds: true } }` + `module.exports = { distDir: undefined, eslint: { ignoreDuringBuilds: true } }` ) const { stderr } = await nextBuild(appDir, [], { stderr: true }) await fs.writeFile(nextConfig, origNextConfig) diff --git a/test/integration/image-optimizer/test/index.test.ts b/test/integration/image-optimizer/test/index.test.ts index b0209037a313..519247edcf75 100644 --- a/test/integration/image-optimizer/test/index.test.ts +++ b/test/integration/image-optimizer/test/index.test.ts @@ -43,7 +43,7 @@ describe('Image Optimizer', () => { await nextConfig.restore() expect(stderr).toContain( - 'The value at .images.domains must have 50 or fewer items but it has 51.' + 'Array must contain at most 50 element(s) at "images.domains"' ) }) @@ -70,7 +70,7 @@ describe('Image Optimizer', () => { await nextConfig.restore() expect(stderr).toContain( - 'The value at .images.remotePatterns must have 50 or fewer items but it has 51.' + 'Array must contain at most 50 element(s) at "images.remotePatterns"' ) }) @@ -95,7 +95,7 @@ describe('Image Optimizer', () => { await nextConfig.restore() expect(stderr).toContain( - 'The value at .images.remotePatterns[0] has an unexpected property, foo, which is not in the list of allowed properties (hostname, pathname, port, protocol).' + `Unrecognized key(s) in object: 'foo' at "images.remotePatterns[0]"` ) }) @@ -120,7 +120,7 @@ describe('Image Optimizer', () => { await nextConfig.restore() expect(stderr).toContain( - "The value at .images.remotePatterns[0] is missing the required field 'hostname'." + `"images.remotePatterns[0].hostname" is missing, expected string` ) }) @@ -145,7 +145,7 @@ describe('Image Optimizer', () => { await nextConfig.restore() expect(stderr).toContain( - 'The value at .images.deviceSizes must have 25 or fewer items but it has 51.' + `Array must contain at most 25 element(s) at "images.deviceSizes"` ) }) @@ -170,10 +170,10 @@ describe('Image Optimizer', () => { await nextConfig.restore() expect(stderr).toContain( - 'The value at .images.deviceSizes[0] must be equal to or greater than 1.' + 'Number must be greater than or equal to 1 at "images.deviceSizes[0]"' ) expect(stderr).toContain( - 'The value at .images.deviceSizes[1] must be equal to or less than 10000.' + 'Number must be less than or equal to 10000 at "images.deviceSizes[1]"' ) }) @@ -198,10 +198,10 @@ describe('Image Optimizer', () => { await nextConfig.restore() expect(stderr).toContain( - 'The value at .images.imageSizes[0] must be equal to or greater than 1.' + 'Number must be greater than or equal to 1 at "images.imageSizes[0]"' ) expect(stderr).toContain( - 'The value at .images.imageSizes[3] must be equal to or less than 10000.' + 'Number must be less than or equal to 10000 at "images.imageSizes[3]"' ) }) @@ -226,7 +226,7 @@ describe('Image Optimizer', () => { await nextConfig.restore() expect(stderr).toContain( - 'The value at .images.loader must be one of: "default", "imgix", "cloudinary", "akamai", or "custom".' + `Expected 'default' | 'imgix' | 'cloudinary' | 'akamai' | 'custom', received 'notreal' at "images.loader"` ) }) @@ -251,7 +251,7 @@ describe('Image Optimizer', () => { await nextConfig.restore() expect(stderr).toContain( - `The value at .images.formats[1] must be one of: "image/avif" or "image/webp".` + `Expected 'image/avif' | 'image/webp', received 'jpeg' at "images.formats[1]"` ) }) @@ -351,7 +351,7 @@ describe('Image Optimizer', () => { await nextConfig.restore() expect(stderr).toContain( - `The value at .images.dangerouslyAllowSVG must be a boolean but it was a string.` + `Expected boolean, received string at "images.dangerouslyAllowSVG"` ) }) @@ -376,7 +376,7 @@ describe('Image Optimizer', () => { await nextConfig.restore() expect(stderr).toContain( - `The value at .images.contentSecurityPolicy must be a string but it was a number.` + `Expected string, received number at "images.contentSecurityPolicy"` ) }) @@ -401,7 +401,7 @@ describe('Image Optimizer', () => { await nextConfig.restore() expect(stderr).toContain( - `The value at .images.contentDispositionType must be one of: "inline" or "attachment".` + `Expected 'inline' | 'attachment', received 'nope' at "images.contentDispositionType"` ) }) @@ -426,7 +426,7 @@ describe('Image Optimizer', () => { await nextConfig.restore() expect(stderr).toContain( - `The value at .images.minimumCacheTTL must be equal to or greater than 0.` + `Number must be greater than or equal to 0 at "images.minimumCacheTTL"` ) }) @@ -451,7 +451,7 @@ describe('Image Optimizer', () => { await nextConfig.restore() expect(stderr).toContain( - `The value at .images.unoptimized must be a boolean but it was a string.` + `Expected boolean, received string at "images.unoptimized"` ) }) }) diff --git a/test/production/build-spinners/index.test.ts b/test/production/build-spinners/index.test.ts index 37114d18e7ce..6144eb6e6a05 100644 --- a/test/production/build-spinners/index.test.ts +++ b/test/production/build-spinners/index.test.ts @@ -66,9 +66,9 @@ describe('build-spinners', () => { }) it.each([ - { name: 'app dir', files: appDirFiles }, + { name: 'app dir - basic', files: appDirFiles }, { - name: 'app dir (compile workers)', + name: 'app dir - (compile workers)', files: [ ...appDirFiles, {