vinext 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -9
- package/dist/build/client-build-config.d.ts +10 -0
- package/dist/build/client-build-config.js +18 -2
- package/dist/build/pages-client-assets-module.d.ts +8 -0
- package/dist/build/pages-client-assets-module.js +21 -1
- package/dist/build/prerender-paths.js +5 -3
- package/dist/build/run-prerender.js +1 -1
- package/dist/build/ssr-manifest.d.ts +2 -0
- package/dist/build/ssr-manifest.js +6 -2
- package/dist/check.js +7 -6
- package/dist/cli.js +2 -1
- package/dist/client/client-redirect-matcher.d.ts +14 -0
- package/dist/client/client-redirect-matcher.js +37 -0
- package/dist/client/client-redirects.d.ts +27 -0
- package/dist/client/client-redirects.js +28 -0
- package/dist/client/client-rewrites.d.ts +2 -1
- package/dist/client/client-rewrites.js +1 -1
- package/dist/config/config-matchers.d.ts +26 -11
- package/dist/config/config-matchers.js +78 -81
- package/dist/config/destination-params.d.ts +47 -0
- package/dist/config/destination-params.js +116 -0
- package/dist/config/next-config.d.ts +7 -0
- package/dist/config/next-config.js +3 -0
- package/dist/entries/app-rsc-entry.d.ts +4 -0
- package/dist/entries/app-rsc-entry.js +20 -6
- package/dist/entries/pages-client-entry.js +3 -1
- package/dist/entries/pages-server-entry.js +13 -37
- package/dist/index.d.ts +3 -1
- package/dist/index.js +134 -43
- package/dist/init-cloudflare.d.ts +9 -0
- package/dist/init-cloudflare.js +107 -31
- package/dist/init-platform.d.ts +4 -0
- package/dist/init-platform.js +27 -2
- package/dist/init.d.ts +1 -0
- package/dist/init.js +67 -3
- package/dist/plugins/ast-scope.d.ts +7 -0
- package/dist/plugins/ast-scope.js +59 -3
- package/dist/plugins/cache-flight-codec.d.ts +1 -1
- package/dist/plugins/dynamic-preload-metadata.d.ts +1 -1
- package/dist/plugins/dynamic-preload-metadata.js +9 -8
- package/dist/plugins/ignore-dynamic-requests.d.ts +1 -1
- package/dist/plugins/ignore-dynamic-requests.js +3 -4
- package/dist/plugins/middleware-server-only.d.ts +5 -4
- package/dist/plugins/middleware-server-only.js +8 -5
- package/dist/plugins/pages-node-externals.js +1 -1
- package/dist/plugins/rsc-scan-glob-imports.d.ts +19 -0
- package/dist/plugins/rsc-scan-glob-imports.js +50 -0
- package/dist/plugins/strip-server-exports.js +262 -98
- package/dist/plugins/transform-result.d.ts +9 -5
- package/dist/plugins/transitive-externals.js +1 -1
- package/dist/plugins/typeof-window.d.ts +2 -2
- package/dist/plugins/use-cache-callable.js +8 -2
- package/dist/plugins/worker-server-only-imports.d.ts +20 -0
- package/dist/plugins/worker-server-only-imports.js +31 -0
- package/dist/plugins/worker-use-server.d.ts +25 -0
- package/dist/plugins/worker-use-server.js +129 -0
- package/dist/server/api-handler.d.ts +1 -0
- package/dist/server/api-handler.js +2 -1
- package/dist/server/app-browser-action-result.d.ts +1 -1
- package/dist/server/app-browser-action-result.js +9 -2
- package/dist/server/app-browser-navigation-controller.js +1 -1
- package/dist/server/app-browser-server-action-client.js +1 -1
- package/dist/server/app-middleware.d.ts +11 -0
- package/dist/server/app-middleware.js +17 -2
- package/dist/server/app-page-cache.d.ts +1 -1
- package/dist/server/app-page-cache.js +1 -1
- package/dist/server/app-page-dispatch.d.ts +3 -1
- package/dist/server/app-page-dispatch.js +4 -3
- package/dist/server/app-page-ppr-runtime.js +1 -1
- package/dist/server/app-page-render-observation.js +1 -1
- package/dist/server/app-page-request.js +53 -15
- package/dist/server/app-page-route-wiring.js +2 -2
- package/dist/server/app-pages-bridge.d.ts +1 -1
- package/dist/server/app-pages-bridge.js +2 -3
- package/dist/server/app-prerender-endpoints.js +9 -6
- package/dist/server/app-request-stage-dispatch.js +6 -2
- package/dist/server/app-request-stage-independent-entry.js +25 -5
- package/dist/server/app-response-stage-entry.js +10 -2
- package/dist/server/app-route-handler-cache.d.ts +1 -0
- package/dist/server/app-route-handler-cache.js +1 -0
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +5 -2
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-runtime.d.ts +4 -1
- package/dist/server/app-route-handler-runtime.js +45 -24
- package/dist/server/app-router-entry.js +24 -5
- package/dist/server/app-rsc-cache-busting.js +1 -1
- package/dist/server/app-rsc-errors.js +20 -16
- package/dist/server/app-rsc-handler.d.ts +7 -0
- package/dist/server/app-rsc-handler.js +85 -35
- package/dist/server/app-rsc-response-stage.js +4 -2
- package/dist/server/app-segment-config.d.ts +2 -1
- package/dist/server/app-server-action-execution.d.ts +2 -1
- package/dist/server/app-server-action-execution.js +61 -22
- package/dist/server/app-ssr-entry.js +2 -1
- package/dist/server/app-worker-stages.d.ts +5 -0
- package/dist/server/app-worker-stages.js +1 -1
- package/dist/server/cacheability-request.js +2 -2
- package/dist/server/client-build-files.d.ts +16 -0
- package/dist/server/client-build-files.js +36 -0
- package/dist/server/client-reuse-manifest.js +1 -1
- package/dist/server/dev-server.js +38 -27
- package/dist/server/dev-stack-sourcemap.js +18 -23
- package/dist/server/document-initial-head.d.ts +0 -11
- package/dist/server/document-initial-head.js +1 -1
- package/dist/server/forwarded-middleware-context.d.ts +5 -0
- package/dist/server/forwarded-middleware-context.js +22 -0
- package/dist/server/headers.d.ts +4 -1
- package/dist/server/headers.js +4 -1
- package/dist/server/http-conditional.d.ts +11 -0
- package/dist/server/http-conditional.js +10 -1
- package/dist/server/http-error-responses.d.ts +1 -1
- package/dist/server/image-optimization.d.ts +38 -0
- package/dist/server/image-optimization.js +93 -4
- package/dist/server/isr-cache.d.ts +10 -0
- package/dist/server/isr-cache.js +41 -6
- package/dist/server/metadata-route-response.js +9 -8
- package/dist/server/middleware-matcher.d.ts +2 -0
- package/dist/server/middleware-matcher.js +23 -2
- package/dist/server/middleware-runtime.d.ts +13 -0
- package/dist/server/middleware-runtime.js +33 -20
- package/dist/server/middleware.d.ts +1 -1
- package/dist/server/middleware.js +3 -1
- package/dist/server/multi-stage.d.ts +11 -0
- package/dist/server/normalize-path.d.ts +0 -13
- package/dist/server/normalize-path.js +1 -34
- package/dist/server/pages-api-route.d.ts +3 -2
- package/dist/server/pages-api-route.js +4 -3
- package/dist/server/pages-cache-tag.d.ts +12 -0
- package/dist/server/pages-cache-tag.js +19 -0
- package/dist/server/pages-client-assets.d.ts +2 -0
- package/dist/server/pages-data-route.d.ts +10 -0
- package/dist/server/pages-data-route.js +19 -2
- package/dist/server/pages-document-asset-props.d.ts +5 -1
- package/dist/server/pages-document-asset-props.js +13 -5
- package/dist/server/pages-document-splice.d.ts +19 -0
- package/dist/server/pages-document-splice.js +55 -0
- package/dist/server/pages-i18n.d.ts +12 -1
- package/dist/server/pages-i18n.js +18 -4
- package/dist/server/pages-node-compat.d.ts +16 -5
- package/dist/server/pages-node-compat.js +20 -12
- package/dist/server/pages-page-data.d.ts +32 -24
- package/dist/server/pages-page-data.js +50 -120
- package/dist/server/pages-page-handler.d.ts +0 -6
- package/dist/server/pages-page-handler.js +188 -126
- package/dist/server/pages-page-response.d.ts +12 -6
- package/dist/server/pages-page-response.js +41 -34
- package/dist/server/pages-request-pipeline.d.ts +10 -2
- package/dist/server/pages-request-pipeline.js +37 -18
- package/dist/server/pages-request-stage-entry.d.ts +6 -0
- package/dist/server/pages-request-stage-entry.js +71 -12
- package/dist/server/pages-response-stage-entry.js +4 -0
- package/dist/server/pages-revalidate.js +1 -1
- package/dist/server/pages-router-entry.js +4 -3
- package/dist/server/prerender-manifest.d.ts +3 -3
- package/dist/server/prerender-manifest.js +4 -3
- package/dist/server/prerender-work-unit-setup.js +4 -0
- package/dist/server/prod-server.d.ts +12 -0
- package/dist/server/prod-server.js +199 -69
- package/dist/server/proper-error.d.ts +4 -0
- package/dist/server/proper-error.js +31 -0
- package/dist/server/request-pipeline.d.ts +4 -1
- package/dist/server/request-pipeline.js +3 -2
- package/dist/server/revalidation-request.d.ts +1 -0
- package/dist/server/revalidation-request.js +1 -1
- package/dist/server/rsc-stream-hints.js +31 -2
- package/dist/server/seed-cache.d.ts +1 -0
- package/dist/server/seed-cache.js +5 -4
- package/dist/server/server-reference-loader.d.ts +4 -0
- package/dist/server/server-reference-loader.js +29 -0
- package/dist/server/socket-error-backstop.d.ts +9 -1
- package/dist/server/socket-error-backstop.js +46 -17
- package/dist/server/static-file-signal.d.ts +15 -4
- package/dist/server/static-file-signal.js +46 -12
- package/dist/server/worker-image-optimization.d.ts +34 -0
- package/dist/server/worker-image-optimization.js +86 -0
- package/dist/server/worker-stages.d.ts +1 -1
- package/dist/server/worker-stages.js +2 -2
- package/dist/server/worker-utils.d.ts +8 -3
- package/dist/server/worker-utils.js +12 -7
- package/dist/shims/app-router-scroll.js +4 -1
- package/dist/shims/app-router-tree-context.d.ts +5 -0
- package/dist/shims/app-router-tree-context.js +27 -0
- package/dist/shims/cache-callable-runtime.d.ts +4 -2
- package/dist/shims/cache-callable-runtime.js +21 -12
- package/dist/shims/cache-handler.js +1 -9
- package/dist/shims/cache-runtime.d.ts +6 -1
- package/dist/shims/cache-runtime.js +2 -1
- package/dist/shims/cache.d.ts +2 -2
- package/dist/shims/cache.js +40 -13
- package/dist/shims/cdn-cache.d.ts +8 -0
- package/dist/shims/cdn-cache.js +17 -1
- package/dist/shims/disable-smooth-scroll.d.ts +3 -0
- package/dist/shims/disable-smooth-scroll.js +36 -0
- package/dist/shims/document-placeholders.d.ts +19 -0
- package/dist/shims/document-placeholders.js +45 -0
- package/dist/shims/document.js +21 -5
- package/dist/shims/dynamic-preload-chunks.d.ts +1 -0
- package/dist/shims/dynamic-preload-chunks.js +13 -9
- package/dist/shims/dynamic.d.ts +1 -1
- package/dist/shims/dynamic.js +60 -8
- package/dist/shims/fetch-cache-state.d.ts +66 -0
- package/dist/shims/fetch-cache-state.js +92 -0
- package/dist/shims/fetch-cache.d.ts +3 -67
- package/dist/shims/fetch-cache.js +160 -125
- package/dist/shims/head.d.ts +10 -6
- package/dist/shims/head.js +15 -13
- package/dist/shims/image.js +2 -1
- package/dist/shims/internal/work-store-scope.d.ts +5 -0
- package/dist/shims/internal/work-store-scope.js +24 -0
- package/dist/shims/navigation.js +31 -5
- package/dist/shims/request-context.d.ts +2 -0
- package/dist/shims/request-state-types.d.ts +2 -1
- package/dist/shims/router.js +12 -20
- package/dist/shims/server.d.ts +16 -0
- package/dist/shims/server.js +24 -4
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/url-utils.d.ts +2 -0
- package/dist/shims/url-utils.js +3 -1
- package/dist/utils/client-runtime-metadata.js +1 -1
- package/dist/utils/hash.d.ts +7 -0
- package/dist/utils/hash.js +11 -1
- package/dist/utils/package-name.d.ts +6 -0
- package/dist/utils/package-name.js +12 -1
- package/dist/utils/plugin-rsc-version.d.ts +4 -0
- package/dist/utils/plugin-rsc-version.js +15 -0
- package/dist/utils/prerender-output-paths.js +15 -4
- package/dist/utils/public-file-path.d.ts +10 -2
- package/dist/utils/public-file-path.js +13 -9
- package/dist/utils/public-routes.js +2 -2
- package/dist/utils/react-version.d.ts +3 -0
- package/dist/utils/react-version.js +1 -1
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -147,6 +147,9 @@ Other options: `--port <port>` (default: 3001), `--skip-check`, `--force`.
|
|
|
147
147
|
Cloudflare init uses `cf` and `cloudflare.config.ts` by default. Both `vinext init`
|
|
148
148
|
and `create-vinext-app` accept `--legacy-wrangler-cloudflare-init` to retain the
|
|
149
149
|
legacy Wrangler setup. Existing Wrangler configs are not automatically migrated.
|
|
150
|
+
`vinext init --name <name>` sets the Worker name in the generated config instead of
|
|
151
|
+
deriving it from `package.json`. An existing config keeps its own Worker name, and init
|
|
152
|
+
prints a warning.
|
|
150
153
|
|
|
151
154
|
If your `next.config.*` sets `output: "standalone"`, `vite build` emits a self-hosting bundle at `dist/standalone/`. Start it with:
|
|
152
155
|
|
|
@@ -282,7 +285,7 @@ You can, with caution. vinext has known compatibility gaps and has not yet been
|
|
|
282
285
|
Yes. Next.js supports [self-hosting](https://nextjs.org/docs/app/building-your-application/deploying#self-hosting) on Node.js servers, Docker containers, and static exports. If you're happy with the Next.js toolchain and just want to run it somewhere other than Vercel, self-hosting is the simplest path.
|
|
283
286
|
|
|
284
287
|
**How are you verifying this works?**
|
|
285
|
-
The test suite has over 1,700 Vitest tests and 380 Playwright E2E tests. This includes tests ported directly from the [Next.js test suite](https://github.com/vercel/next.js/tree/canary/test) and [OpenNext's Cloudflare conformance suite](https://github.com/opennextjs/opennextjs-cloudflare), covering routing, SSR, RSC, server actions, caching, metadata, middleware, streaming, and more. Vercel's [App Router Playground](https://github.com/vercel/next-app-router-playground) also runs on vinext as an integration test. See the [Tests](#tests) section
|
|
288
|
+
The test suite has over 1,700 Vitest tests and 380 Playwright E2E tests. This includes tests ported directly from the [Next.js test suite](https://github.com/vercel/next.js/tree/canary/test) and [OpenNext's Cloudflare conformance suite](https://github.com/opennextjs/opennextjs-cloudflare), covering routing, SSR, RSC, server actions, caching, metadata, middleware, streaming, and more. Vercel's [App Router Playground](https://github.com/vercel/next-app-router-playground) also runs on vinext as an integration test. See the [Tests](#tests) section for details.
|
|
286
289
|
|
|
287
290
|
**Who is reviewing this code?**
|
|
288
291
|
A mix of humans and AI agents. Humans review PRs before they merge, focused on behavior, structure, and long-term direction. We lean heavily on agent-driven code review to catch issues at PR time and across the codebase. The test suite is the primary quality gate. Outside contributions and deeper human code review are very welcome.
|
|
@@ -437,10 +440,14 @@ export default defineConfig({
|
|
|
437
440
|
|
|
438
441
|
#### Module Federation (client-side)
|
|
439
442
|
|
|
440
|
-
|
|
443
|
+
Use [`@module-federation/vinext`](https://github.com/module-federation/vinext), a thin wrapper around `@module-federation/vite` with vinext defaults. Register `federation()` before `vinext()`:
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
npm install @module-federation/vinext
|
|
447
|
+
```
|
|
441
448
|
|
|
442
449
|
```ts
|
|
443
|
-
import { federation } from "@module-federation/
|
|
450
|
+
import { federation } from "@module-federation/vinext";
|
|
444
451
|
import { defineConfig } from "vite";
|
|
445
452
|
import vinext from "vinext";
|
|
446
453
|
|
|
@@ -448,11 +455,14 @@ export default defineConfig({
|
|
|
448
455
|
plugins: [
|
|
449
456
|
federation({
|
|
450
457
|
name: "host",
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
458
|
+
remotes: {
|
|
459
|
+
catalog: {
|
|
460
|
+
type: "module",
|
|
461
|
+
name: "catalog",
|
|
462
|
+
entry: "https://catalog.example.com/remoteEntry.js",
|
|
463
|
+
entryGlobalName: "catalog",
|
|
464
|
+
shareScope: "default",
|
|
465
|
+
},
|
|
456
466
|
},
|
|
457
467
|
}),
|
|
458
468
|
vinext(),
|
|
@@ -460,6 +470,8 @@ export default defineConfig({
|
|
|
460
470
|
});
|
|
461
471
|
```
|
|
462
472
|
|
|
473
|
+
The wrapper shares `react` and `react-dom` as singletons, defaults `filename` to `remoteEntry.js`, and injects the host's federation startup into the entry, because vinext has no conventional HTML entry. Explicit options override these defaults, and every `@module-federation/vite` option remains available. Passing your own `shared` replaces the default map, so keep `react`, `react/`, `react-dom`, and `react-dom/` as singletons in it, in both the host and remotes.
|
|
474
|
+
|
|
463
475
|
In a remote client component, use `getVinextReact()` before reading React hooks. vinext registers the host's browser React instance before application modules execute, and the first registration remains stable across remote evaluation and HMR:
|
|
464
476
|
|
|
465
477
|
```tsx
|
|
@@ -478,7 +490,7 @@ export function RemoteCounter() {
|
|
|
478
490
|
|
|
479
491
|
This bridge is browser-only. It does not provide App Router Module Federation SSR or transparently replace React imports inside third-party packages; compatible React versions remain the responsibility of the Module Federation `shared` configuration.
|
|
480
492
|
|
|
481
|
-
See the [
|
|
493
|
+
See the [Module Federation guide](https://vinext.dev/docs/guides/module-federation) for loading remote components in the host.
|
|
482
494
|
|
|
483
495
|
### Other platforms (via Nitro)
|
|
484
496
|
|
|
@@ -116,4 +116,14 @@ export declare function createMultiStageCodeSplittingConfig(existing: VinextBuil
|
|
|
116
116
|
* the host's existing output pattern (or vinext's server-assets default).
|
|
117
117
|
*/
|
|
118
118
|
export declare function createMultiStageChunkFileNames(assetsDir: string, existing: VinextBuildOutput["chunkFileNames"]): ChunkFileNameFunction;
|
|
119
|
+
/**
|
|
120
|
+
* The client environment builds after RSC and SSR, and Vite empties its
|
|
121
|
+
* output directory first. A client output directory that is, or contains, a
|
|
122
|
+
* server output directory would therefore delete the server build.
|
|
123
|
+
*/
|
|
124
|
+
export declare function assertClientOutDirIsSeparate(root: string, dirs: {
|
|
125
|
+
clientOutDir?: string;
|
|
126
|
+
rscOutDir?: string;
|
|
127
|
+
ssrOutDir?: string;
|
|
128
|
+
}): void;
|
|
119
129
|
//#endregion
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
1
|
+
import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
2
|
//#region src/build/client-build-config.ts
|
|
3
3
|
const ROUTE_OWNED_CLIENT_SHIMS = /* @__PURE__ */ new Set([
|
|
4
|
+
"app-router-tree-context",
|
|
4
5
|
"compat-router",
|
|
5
6
|
"dynamic",
|
|
6
7
|
"dynamic-preload-chunks",
|
|
@@ -266,5 +267,20 @@ function createMultiStageChunkFileNames(assetsDir, existing) {
|
|
|
266
267
|
return (existing ?? joinAssetFileNamePattern(assetsDir, "[name]-[hash].js")).replaceAll("[name]", name);
|
|
267
268
|
};
|
|
268
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* The client environment builds after RSC and SSR, and Vite empties its
|
|
272
|
+
* output directory first. A client output directory that is, or contains, a
|
|
273
|
+
* server output directory would therefore delete the server build.
|
|
274
|
+
*/
|
|
275
|
+
function assertClientOutDirIsSeparate(root, dirs) {
|
|
276
|
+
if (!dirs.clientOutDir) return;
|
|
277
|
+
const clientOutDir = path.resolve(root, dirs.clientOutDir);
|
|
278
|
+
const serverOutDirs = [["rscOutDir", dirs.rscOutDir ?? "dist/server"], ["ssrOutDir", dirs.ssrOutDir ?? "dist/server/ssr"]];
|
|
279
|
+
for (const [name, dir] of serverOutDirs) {
|
|
280
|
+
const relative = path.relative(clientOutDir, path.resolve(root, dir));
|
|
281
|
+
if (relative === ".." || relative.startsWith("../") || path.isAbsolute(relative)) continue;
|
|
282
|
+
throw new Error(`[vinext] clientOutDir "${dirs.clientOutDir}" contains ${name} "${dir}". The client build runs last and empties its output directory, which would delete the server build. Use separate output directories.`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
269
285
|
//#endregion
|
|
270
|
-
export { RSC_FRAMEWORK_CHUNK_TEST, createClientAssetFileNames, createClientCodeSplittingConfig, createClientFileNameConfig, createClientManualChunks, createMultiStageChunkFileNames, createMultiStageCodeSplittingConfig, createRscFrameworkChunkOutputConfig, getBuildBundlerOptions, getClientTreeshakeConfig, isRscFrameworkModule, sanitizeRscChunkFileName, withBuildBundlerOptions };
|
|
286
|
+
export { RSC_FRAMEWORK_CHUNK_TEST, assertClientOutDirIsSeparate, createClientAssetFileNames, createClientCodeSplittingConfig, createClientFileNameConfig, createClientManualChunks, createMultiStageChunkFileNames, createMultiStageCodeSplittingConfig, createRscFrameworkChunkOutputConfig, getBuildBundlerOptions, getClientTreeshakeConfig, isRscFrameworkModule, sanitizeRscChunkFileName, withBuildBundlerOptions };
|
|
@@ -2,5 +2,13 @@ import { PagesClientAssets } from "../server/pages-client-assets.js";
|
|
|
2
2
|
//#region src/build/pages-client-assets-module.d.ts
|
|
3
3
|
export declare const PAGES_CLIENT_ASSETS_MODULE = "vinext-client-assets.js";
|
|
4
4
|
export declare function buildPagesClientAssetsModule(assets: PagesClientAssets): string;
|
|
5
|
+
/**
|
|
6
|
+
* Select the client bundle files that live outside `_next/static`, as URL
|
|
7
|
+
* pathnames. Plugins emit these at the output root, for example a Module
|
|
8
|
+
* Federation host's `remoteEntry.js`. Public directory files are copied
|
|
9
|
+
* outside the bundle, and build metadata (vinext's and Cloudflare's
|
|
10
|
+
* `.assetsignore`) is excluded.
|
|
11
|
+
*/
|
|
12
|
+
export declare function collectClientBuildFiles(fileNames: Iterable<string>): string[];
|
|
5
13
|
export declare function writePagesClientAssetsModuleIfMissing(outputDir: string, moduleSource: string): void;
|
|
6
14
|
//#endregion
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
|
+
import "../utils/asset-prefix.js";
|
|
2
3
|
import { getSharedChunkFiles } from "../server/pages-asset-tags.js";
|
|
4
|
+
import "../utils/client-entry-manifest.js";
|
|
3
5
|
import fs from "node:fs";
|
|
4
6
|
//#region src/build/pages-client-assets-module.ts
|
|
5
7
|
const PAGES_CLIENT_ASSETS_MODULE = "vinext-client-assets.js";
|
|
@@ -10,6 +12,24 @@ function buildPagesClientAssetsModule(assets) {
|
|
|
10
12
|
} : assets;
|
|
11
13
|
return `export default ${JSON.stringify(prepared)};\n`;
|
|
12
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Select the client bundle files that live outside `_next/static`, as URL
|
|
17
|
+
* pathnames. Plugins emit these at the output root, for example a Module
|
|
18
|
+
* Federation host's `remoteEntry.js`. Public directory files are copied
|
|
19
|
+
* outside the bundle, and build metadata (vinext's and Cloudflare's
|
|
20
|
+
* `.assetsignore`) is excluded.
|
|
21
|
+
*/
|
|
22
|
+
function collectClientBuildFiles(fileNames) {
|
|
23
|
+
const files = [];
|
|
24
|
+
for (const fileName of fileNames) {
|
|
25
|
+
const pathname = `/${fileName}`;
|
|
26
|
+
if (pathname.includes(`/_next/static/`)) continue;
|
|
27
|
+
if (pathname.startsWith("/.vite/") || fileName === "vinext-client-entry-manifest.json") continue;
|
|
28
|
+
if (fileName === ".assetsignore") continue;
|
|
29
|
+
files.push(pathname);
|
|
30
|
+
}
|
|
31
|
+
return files.sort();
|
|
32
|
+
}
|
|
13
33
|
function writePagesClientAssetsModuleIfMissing(outputDir, moduleSource) {
|
|
14
34
|
const outputPath = path.join(outputDir, PAGES_CLIENT_ASSETS_MODULE);
|
|
15
35
|
if (fs.existsSync(outputPath)) return;
|
|
@@ -17,4 +37,4 @@ function writePagesClientAssetsModuleIfMissing(outputDir, moduleSource) {
|
|
|
17
37
|
fs.writeFileSync(outputPath, moduleSource);
|
|
18
38
|
}
|
|
19
39
|
//#endregion
|
|
20
|
-
export { PAGES_CLIENT_ASSETS_MODULE, buildPagesClientAssetsModule, writePagesClientAssetsModuleIfMissing };
|
|
40
|
+
export { PAGES_CLIENT_ASSETS_MODULE, buildPagesClientAssetsModule, collectClientBuildFiles, writePagesClientAssetsModuleIfMissing };
|
|
@@ -134,6 +134,7 @@ async function fetchDiscoveryEndpoint(url, headers, retryOptions = {}) {
|
|
|
134
134
|
const request = (async () => {
|
|
135
135
|
const res = await fetch(url, {
|
|
136
136
|
headers,
|
|
137
|
+
redirect: "manual",
|
|
137
138
|
signal: controller.signal
|
|
138
139
|
});
|
|
139
140
|
return {
|
|
@@ -152,10 +153,11 @@ async function fetchDiscoveryEndpoint(url, headers, retryOptions = {}) {
|
|
|
152
153
|
if (res.status === 204) return null;
|
|
153
154
|
return text;
|
|
154
155
|
}
|
|
155
|
-
const
|
|
156
|
+
const redirected = res.status >= 300 && res.status < 400;
|
|
157
|
+
const userFailure = redirected ? null : readDiscoveryUserFailure(res, text);
|
|
156
158
|
const detail = userFailure ?? (/cloudflare:|ERR_UNSUPPORTED_ESM_URL_SCHEME/i.test(text) ? text.trim() : "");
|
|
157
|
-
lastError = /* @__PURE__ */ new Error(`path discovery returned HTTP ${res.status}${detail ? `: ${detail}` : ""}`);
|
|
158
|
-
if (!(res.status === 404 || res.status >= 500 && res.status <= 599 && userFailure === null)) {
|
|
159
|
+
lastError = redirected ? /* @__PURE__ */ new Error(`path discovery returned a redirect (HTTP ${res.status}); refusing to follow it with the prerender secret`) : /* @__PURE__ */ new Error(`path discovery returned HTTP ${res.status}${detail ? `: ${detail}` : ""}`);
|
|
160
|
+
if (!(redirected || res.status === 404 || res.status >= 500 && res.status <= 599 && userFailure === null)) {
|
|
159
161
|
shouldRetry = false;
|
|
160
162
|
throw lastError;
|
|
161
163
|
}
|
|
@@ -124,7 +124,7 @@ async function runPrerender(options) {
|
|
|
124
124
|
let totalUrls = 0;
|
|
125
125
|
let completedUrls = 0;
|
|
126
126
|
const progress = new PrerenderProgress();
|
|
127
|
-
const outDir = mode === "export" ? path.
|
|
127
|
+
const outDir = mode === "export" ? path.resolve(root, options.routeRootConfig?.clientOutDir ?? path.join("dist", "client")) : path.join(manifestDir, "prerendered-routes");
|
|
128
128
|
let sharedProdServer = null;
|
|
129
129
|
let sharedPrerenderSecret;
|
|
130
130
|
const restorePrerenderPhase = enterPrerenderPhase();
|
|
@@ -14,6 +14,8 @@ export type BundleBackfillChunk = {
|
|
|
14
14
|
* `toSlash` where the result becomes a module id / manifest key.
|
|
15
15
|
*/
|
|
16
16
|
export declare function tryRealpathSync(candidate: string): string | null;
|
|
17
|
+
/** Forward-slash `path.relative(root, moduleId)`, which may escape with `../`. */
|
|
18
|
+
export declare function relativeToRoot(root: string, moduleId: string): string;
|
|
17
19
|
export declare function relativeWithinRoot(root: string, moduleId: string): string | null;
|
|
18
20
|
export declare function augmentSsrManifestFromBundle(ssrManifest: Record<string, string[]>, bundle: Record<string, BundleBackfillChunk | {
|
|
19
21
|
type: string;
|
|
@@ -16,8 +16,12 @@ function tryRealpathSync(candidate) {
|
|
|
16
16
|
function isWindowsAbsolutePath(candidate) {
|
|
17
17
|
return /^[a-zA-Z]:[\\/]/.test(candidate) || candidate.startsWith("\\\\");
|
|
18
18
|
}
|
|
19
|
+
/** Forward-slash `path.relative(root, moduleId)`, which may escape with `../`. */
|
|
20
|
+
function relativeToRoot(root, moduleId) {
|
|
21
|
+
return isWindowsAbsolutePath(root) || isWindowsAbsolutePath(moduleId) ? path.win32.relative(root, moduleId) : path.relative(root, moduleId);
|
|
22
|
+
}
|
|
19
23
|
function relativeWithinRoot(root, moduleId) {
|
|
20
|
-
const relativeId =
|
|
24
|
+
const relativeId = relativeToRoot(root, moduleId);
|
|
21
25
|
if (!relativeId || relativeId === ".." || relativeId.startsWith("../")) return null;
|
|
22
26
|
return relativeId;
|
|
23
27
|
}
|
|
@@ -70,4 +74,4 @@ function augmentSsrManifestFromBundle(ssrManifest, bundle, root, base = "/") {
|
|
|
70
74
|
return Object.fromEntries(Object.entries(nextManifest).map(([key, files]) => [key, [...files]]));
|
|
71
75
|
}
|
|
72
76
|
//#endregion
|
|
73
|
-
export { augmentSsrManifestFromBundle, relativeWithinRoot, tryRealpathSync };
|
|
77
|
+
export { augmentSsrManifestFromBundle, relativeToRoot, relativeWithinRoot, tryRealpathSync };
|
package/dist/check.js
CHANGED
|
@@ -210,7 +210,7 @@ const CONFIG_SUPPORT = {
|
|
|
210
210
|
},
|
|
211
211
|
transpilePackages: {
|
|
212
212
|
status: "supported",
|
|
213
|
-
detail: "listed packages are bundled instead of externalized on the server"
|
|
213
|
+
detail: "listed packages are bundled instead of externalized on the server, and their next/dynamic() calls get SSR preload links"
|
|
214
214
|
},
|
|
215
215
|
serverExternalPackages: {
|
|
216
216
|
status: "supported",
|
|
@@ -252,9 +252,10 @@ const CONFIG_SUPPORT = {
|
|
|
252
252
|
status: "unsupported",
|
|
253
253
|
detail: "custom cacheLife profiles are ignored; only the built-in profiles are available"
|
|
254
254
|
},
|
|
255
|
-
skipTrailingSlashRedirect: {
|
|
256
|
-
|
|
257
|
-
|
|
255
|
+
skipTrailingSlashRedirect: { status: "supported" },
|
|
256
|
+
"experimental.skipTrailingSlashRedirect": {
|
|
257
|
+
status: "supported",
|
|
258
|
+
detail: "legacy alias of skipTrailingSlashRedirect"
|
|
258
259
|
},
|
|
259
260
|
reactCompiler: {
|
|
260
261
|
status: "partial",
|
|
@@ -433,8 +434,8 @@ const LIBRARY_SUPPORT = {
|
|
|
433
434
|
detail: "renders client-side; by default events are only collected when deployed on Vercel"
|
|
434
435
|
},
|
|
435
436
|
"next-intl": {
|
|
436
|
-
status: "
|
|
437
|
-
detail: "
|
|
437
|
+
status: "supported",
|
|
438
|
+
detail: "createNextIntlPlugin is only optional with the request config at (src/)i18n/request.*; its experimental messages, precompile and extract options don't work (they need webpack/Turbopack loaders)"
|
|
438
439
|
},
|
|
439
440
|
"@clerk/nextjs": {
|
|
440
441
|
status: "supported",
|
package/dist/cli.js
CHANGED
|
@@ -4,8 +4,8 @@ import { detectPackageManager, ensureViteConfigCompatibility, findViteConfigPath
|
|
|
4
4
|
import { formatReport, runCheck } from "./check.js";
|
|
5
5
|
import { parseArgs } from "./cli-args.js";
|
|
6
6
|
import { findViteRoot, getViteCliInvocation, valueOptionName } from "./utils/vite-cli-invocation.js";
|
|
7
|
-
import { init } from "./init.js";
|
|
8
7
|
import { resolveInitOptions } from "./init-platform.js";
|
|
8
|
+
import { init } from "./init.js";
|
|
9
9
|
import { loadDotenv } from "./config/dotenv.js";
|
|
10
10
|
import { PHASE_PRODUCTION_BUILD } from "./shims/constants.js";
|
|
11
11
|
import { loadNextConfig, resolveNextConfig } from "./config/next-config.js";
|
|
@@ -275,6 +275,7 @@ function printHelp(cmd) {
|
|
|
275
275
|
--no-install Update dependency entries without installing them
|
|
276
276
|
--force Overwrite existing vite.config.ts
|
|
277
277
|
--platform <target> Deployment target: cloudflare or node
|
|
278
|
+
--name <name> Cloudflare Worker name (default: derived from package.json)
|
|
278
279
|
--prerender Configure Vite builds to pre-render static routes
|
|
279
280
|
(Cloudflare deploy won't serve them unless using Static Assets)
|
|
280
281
|
--warm-cache Add cache warming to the Cloudflare deploy script
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { RequestContext } from "../config/request-context.js";
|
|
2
|
+
import { BasePathMatchState, RedirectMatch } from "../config/config-matchers.js";
|
|
3
|
+
import { ClientRedirect } from "./client-redirects.js";
|
|
4
|
+
//#region src/client/client-redirect-matcher.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Resolve the first matching client-safe redirect. A matching server-owned
|
|
7
|
+
* rule stops client evaluation and returns null so a later client-safe rule
|
|
8
|
+
* cannot take its place. The navigation then continues as it does in Next.js,
|
|
9
|
+
* which never resolves config redirects in the browser: a document request (or
|
|
10
|
+
* a data request that falls back to one) reaches the server rule, while a page
|
|
11
|
+
* without data fetching renders without it.
|
|
12
|
+
*/
|
|
13
|
+
export declare function matchClientRedirect(pathname: string, redirects: ClientRedirect[], context: RequestContext, basePathState: BasePathMatchState): RedirectMatch | null;
|
|
14
|
+
//#endregion
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { matchRedirect } from "../config/config-matchers.js";
|
|
2
|
+
//#region src/client/client-redirect-matcher.ts
|
|
3
|
+
const matcherRules = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
function getMatcherRule(redirect) {
|
|
5
|
+
let rule = matcherRules.get(redirect);
|
|
6
|
+
if (!rule) {
|
|
7
|
+
rule = [{
|
|
8
|
+
source: redirect.source,
|
|
9
|
+
destination: redirect.destination ?? "/",
|
|
10
|
+
permanent: redirect.permanent ?? false,
|
|
11
|
+
has: redirect.has,
|
|
12
|
+
missing: redirect.missing,
|
|
13
|
+
locale: redirect.locale,
|
|
14
|
+
basePath: redirect.basePath
|
|
15
|
+
}];
|
|
16
|
+
matcherRules.set(redirect, rule);
|
|
17
|
+
}
|
|
18
|
+
return rule;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the first matching client-safe redirect. A matching server-owned
|
|
22
|
+
* rule stops client evaluation and returns null so a later client-safe rule
|
|
23
|
+
* cannot take its place. The navigation then continues as it does in Next.js,
|
|
24
|
+
* which never resolves config redirects in the browser: a document request (or
|
|
25
|
+
* a data request that falls back to one) reaches the server rule, while a page
|
|
26
|
+
* without data fetching renders without it.
|
|
27
|
+
*/
|
|
28
|
+
function matchClientRedirect(pathname, redirects, context, basePathState) {
|
|
29
|
+
for (const redirect of redirects) {
|
|
30
|
+
const match = matchRedirect(pathname, getMatcherRule(redirect), context, basePathState);
|
|
31
|
+
if (match === null) continue;
|
|
32
|
+
return redirect.requiresServerEvaluation ? null : match;
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { matchClientRedirect };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { NextRedirect, ResolvedNextConfig } from "../config/next-config.js";
|
|
2
|
+
import { ClientHasCondition } from "./client-rewrites.js";
|
|
3
|
+
//#region src/client/client-redirects.d.ts
|
|
4
|
+
type ClientRedirectFields = Pick<NextRedirect, "basePath" | "locale" | "source"> & {
|
|
5
|
+
has?: ClientHasCondition[];
|
|
6
|
+
missing?: ClientHasCondition[];
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Redirect data that is safe to publish in a browser bundle.
|
|
10
|
+
*
|
|
11
|
+
* Next.js keeps redirects in the server routes manifest only. Vinext resolves
|
|
12
|
+
* browser-authoritative redirects during Pages Router navigation, but rules
|
|
13
|
+
* with header or cookie conditions are server-owned: their condition values
|
|
14
|
+
* can be private, so the rule keeps only its source and client-safe
|
|
15
|
+
* conditions to preserve first-match ordering, and drops its destination.
|
|
16
|
+
*/
|
|
17
|
+
export type ClientRedirect = (ClientRedirectFields & {
|
|
18
|
+
destination: string;
|
|
19
|
+
permanent: boolean;
|
|
20
|
+
requiresServerEvaluation?: never;
|
|
21
|
+
}) | (ClientRedirectFields & {
|
|
22
|
+
destination?: never;
|
|
23
|
+
permanent?: never;
|
|
24
|
+
requiresServerEvaluation: true;
|
|
25
|
+
});
|
|
26
|
+
export declare function toClientRedirects(redirects: ResolvedNextConfig["redirects"]): ClientRedirect[];
|
|
27
|
+
//#endregion
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { isClientHasCondition } from "./client-rewrites.js";
|
|
2
|
+
//#region src/client/client-redirects.ts
|
|
3
|
+
function toClientRedirect(redirect) {
|
|
4
|
+
const hasServerOnlyCondition = (redirect.has?.some((condition) => !isClientHasCondition(condition)) ?? false) || (redirect.missing?.some((condition) => !isClientHasCondition(condition)) ?? false);
|
|
5
|
+
const clientHas = redirect.has?.filter(isClientHasCondition);
|
|
6
|
+
const clientMissing = redirect.missing?.filter(isClientHasCondition);
|
|
7
|
+
const common = {
|
|
8
|
+
source: redirect.source,
|
|
9
|
+
has: clientHas?.length ? clientHas : void 0,
|
|
10
|
+
missing: clientMissing?.length ? clientMissing : void 0,
|
|
11
|
+
locale: redirect.locale,
|
|
12
|
+
basePath: redirect.basePath
|
|
13
|
+
};
|
|
14
|
+
if (hasServerOnlyCondition) return {
|
|
15
|
+
...common,
|
|
16
|
+
requiresServerEvaluation: true
|
|
17
|
+
};
|
|
18
|
+
return {
|
|
19
|
+
...common,
|
|
20
|
+
destination: redirect.destination,
|
|
21
|
+
permanent: redirect.permanent
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function toClientRedirects(redirects) {
|
|
25
|
+
return redirects.map(toClientRedirect);
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { toClientRedirects };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HasCondition, NextRewrite, ResolvedNextConfig } from "../config/next-config.js";
|
|
2
2
|
//#region src/client/client-rewrites.d.ts
|
|
3
|
-
type ClientHasCondition = Omit<HasCondition, "type"> & {
|
|
3
|
+
export type ClientHasCondition = Omit<HasCondition, "type"> & {
|
|
4
4
|
type: "host" | "query";
|
|
5
5
|
};
|
|
6
6
|
type ClientRewriteFields = Pick<NextRewrite, "basePath" | "locale" | "source"> & {
|
|
@@ -26,5 +26,6 @@ export type ClientRewrites = {
|
|
|
26
26
|
beforeFiles: ClientRewrite[];
|
|
27
27
|
fallback: ClientRewrite[];
|
|
28
28
|
};
|
|
29
|
+
export declare function isClientHasCondition(condition: HasCondition): condition is ClientHasCondition;
|
|
29
30
|
export declare function toClientRewrites(rewrites: ResolvedNextConfig["rewrites"]): ClientRewrites;
|
|
30
31
|
//#endregion
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HasCondition, NextHeader, NextI18nConfig, NextRedirect, NextRewrite } from "./next-config.js";
|
|
2
2
|
import { RequestContext, normalizeHost, parseCookies, requestContextFromRequest } from "./request-context.js";
|
|
3
|
+
import { RedirectDestinationQueryPart } from "./destination-params.js";
|
|
3
4
|
import { isExternalUrl } from "../utils/external-url.js";
|
|
4
5
|
//#region src/config/config-matchers.d.ts
|
|
5
6
|
/**
|
|
@@ -75,6 +76,15 @@ export declare function applyMiddlewareRequestHeaders(middlewareHeaders: Record<
|
|
|
75
76
|
};
|
|
76
77
|
export declare function checkHasConditions(has: HasCondition[] | undefined, missing: HasCondition[] | undefined, ctx: RequestContext): boolean;
|
|
77
78
|
export declare function matchConfigPattern(pathname: string, pattern: string): Record<string, string> | null;
|
|
79
|
+
/**
|
|
80
|
+
* A matched config redirect. `destinationQuery` holds the destination query's
|
|
81
|
+
* parts, split before params were substituted, for merging the request query.
|
|
82
|
+
*/
|
|
83
|
+
export type RedirectMatch = {
|
|
84
|
+
destination: string;
|
|
85
|
+
permanent: boolean;
|
|
86
|
+
destinationQuery: RedirectDestinationQueryPart[];
|
|
87
|
+
};
|
|
78
88
|
/**
|
|
79
89
|
* Apply redirect rules from next.config.js.
|
|
80
90
|
* Returns the redirect info if a redirect was matched, or null.
|
|
@@ -110,10 +120,7 @@ export declare function matchConfigPattern(pathname: string, pattern: string): R
|
|
|
110
120
|
* an original index < N are checked via matchConfigPattern first — they are
|
|
111
121
|
* few in practice (typically zero) so this is not a hot-path concern.
|
|
112
122
|
*/
|
|
113
|
-
export declare function matchRedirect(pathname: string, redirects: NextRedirect[], ctx: RequestContext, basePathState?: BasePathMatchState, onRuleSourceMatch?: (rule: NextRedirect) => void):
|
|
114
|
-
destination: string;
|
|
115
|
-
permanent: boolean;
|
|
116
|
-
} | null;
|
|
123
|
+
export declare function matchRedirect(pathname: string, redirects: NextRedirect[], ctx: RequestContext, basePathState?: BasePathMatchState, onRuleSourceMatch?: (rule: NextRedirect) => void): RedirectMatch | null;
|
|
117
124
|
/**
|
|
118
125
|
* Apply rewrite rules from next.config.js.
|
|
119
126
|
* Returns the rewritten URL or null if no rewrite matched.
|
|
@@ -142,7 +149,8 @@ export declare function matchesRewriteSource(pathname: string, rewrite: NextRewr
|
|
|
142
149
|
* users off-site.
|
|
143
150
|
*
|
|
144
151
|
* This function collapses any leading double (or more) slashes to a single
|
|
145
|
-
* slash for non-external (relative) destinations
|
|
152
|
+
* slash for non-external (relative) destinations, including tab/newline and
|
|
153
|
+
* leading C0 control characters that browsers ignore while parsing.
|
|
146
154
|
*/
|
|
147
155
|
export declare function sanitizeDestination(dest: string): string;
|
|
148
156
|
/**
|
|
@@ -162,13 +170,20 @@ export declare function sanitizeDestination(dest: string): string;
|
|
|
162
170
|
* still treated as an RSC fetch. Dropping it breaks RSC fetch semantics
|
|
163
171
|
* (issue #1529).
|
|
164
172
|
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
173
|
+
* Ported from Next.js's `{ ...requestQuery, ...destinationQuery }` merge and
|
|
174
|
+
* `stringifyQuery`: request keys keep their order (integer-like keys first, as
|
|
175
|
+
* in a JS object), a destination key overrides the request value in place,
|
|
176
|
+
* and destination-only keys follow. Request keys and values are re-encoded;
|
|
177
|
+
* destination query text is emitted verbatim, except that, like Next.js,
|
|
178
|
+
* destination strings equal to a request key or value are re-encoded too.
|
|
179
|
+
* Pass the match's
|
|
180
|
+
* `destinationQuery` so substituted params keep their value boundaries;
|
|
181
|
+
* without it the destination's own query is split. External destinations are returned untouched (a config redirect to another
|
|
182
|
+
* origin should not leak the original request's query).
|
|
183
|
+
*
|
|
184
|
+
* https://github.com/vercel/next.js/blob/canary/packages/next/src/server/server-route-utils.ts
|
|
170
185
|
*/
|
|
171
|
-
export declare function preserveRedirectDestinationQuery(destination: string, requestSearch: string): string;
|
|
186
|
+
export declare function preserveRedirectDestinationQuery(destination: string, requestSearch: string, destinationQuery?: RedirectDestinationQueryPart[]): string;
|
|
172
187
|
/**
|
|
173
188
|
* Proxy an incoming request to an external URL and return the upstream response.
|
|
174
189
|
*
|