@qzsy/vinext 0.1.10 → 0.1.11

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/dist/deploy.js CHANGED
@@ -378,7 +378,7 @@ import { fetchWorkerFilesystemRoute, runPagesRequest, wrapMiddlewareWithBasePath
378
378
  import type { PagesPipelineDeps } from "vinext/server/pages-request-pipeline";
379
379
  import { handleImageOptimization, DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, isImageOptimizationPath } from "vinext/server/image-optimization";
380
380
  import type { ImageConfig } from "vinext/server/image-optimization";
381
- import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, isOpenRedirectShaped } from "vinext/server/request-pipeline";
381
+ import { bufferRequestBodyForHeaderClone, cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, isOpenRedirectShaped } from "vinext/server/request-pipeline";
382
382
  import { notFoundStaticAssetResponse } from "vinext/server/http-error-responses";
383
383
  import { assetPrefixPathname, isNextStaticPath } from "vinext/utils/asset-prefix";
384
384
  import { hasBasePath, stripBasePath } from "vinext/utils/base-path";
@@ -452,6 +452,7 @@ export default {
452
452
  // forged to influence routing or impersonate internal state.
453
453
  // Request.headers is immutable in Workers, so build a clean copy.
454
454
  {
455
+ request = await bufferRequestBodyForHeaderClone(request);
455
456
  const filteredHeaders = filterInternalHeaders(request.headers);
456
457
  request = cloneRequestWithHeaders(request, filteredHeaders);
457
458
  }
@@ -3,7 +3,7 @@ import { runWithExecutionContext } from "../shims/request-context.js";
3
3
  import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER } from "./headers.js";
4
4
  import { badRequestResponse, notFoundResponse, notFoundStaticAssetResponse } from "./http-error-responses.js";
5
5
  import { isOpenRedirectShaped } from "./open-redirect.js";
6
- import { cloneRequestWithHeaders, filterInternalHeaders } from "./request-pipeline.js";
6
+ import { bufferRequestBodyForHeaderClone, cloneRequestWithHeaders, filterInternalHeaders } from "./request-pipeline.js";
7
7
  import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
8
8
  import { resolveStaticAssetSignal } from "./worker-utils.js";
9
9
  import { readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
@@ -26,6 +26,7 @@ async function handleRequest(request, env, ctx) {
26
26
  }
27
27
  if (isNextStaticPath(url.pathname, __workerBasePath, __workerAssetPathPrefix)) return notFoundStaticAssetResponse();
28
28
  {
29
+ request = await bufferRequestBodyForHeaderClone(request);
29
30
  const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(request);
30
31
  const filteredHeaders = filterInternalHeaders(request.headers);
31
32
  const prerenderRouteParamsHeader = serializePrerenderRouteParamsHeader(prerenderRouteParamsPayload);
@@ -4,7 +4,7 @@ import { getRequestExecutionContext } from "../shims/request-context.js";
4
4
  import { ACTION_REVALIDATED_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER } from "./headers.js";
5
5
  import { isExternalUrl, matchRedirect, matchRewrite, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "../config/config-matchers.js";
6
6
  import { notFoundResponse } from "./http-error-responses.js";
7
- import { applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, resolvePublicFileRoute } from "./request-pipeline.js";
7
+ import { applyConfigHeadersToResponse, bufferRequestBodyForHeaderClone, cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, resolvePublicFileRoute } from "./request-pipeline.js";
8
8
  import { headersContextFromRequest } from "../shims/headers.js";
9
9
  import { ensureFetchPatch, setCurrentFetchSoftTags } from "../shims/fetch-cache.js";
10
10
  import { mergeRewriteQuery } from "../utils/query.js";
@@ -17,8 +17,8 @@ import "./app-page-response.js";
17
17
  import { buildNextDataNotFoundResponse, normalizePagesDataRequest } from "./pages-data-route.js";
18
18
  import { matchPrerenderRouteParamsPayload, readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
19
19
  import { getRenderedConcreteUrlPathsForRoute } from "./pregenerated-concrete-paths.js";
20
- import { flattenErrorCauses } from "../utils/error-cause.js";
21
20
  import { pickRootParams, setRootParams } from "../shims/root-params.js";
21
+ import { flattenErrorCauses } from "../utils/error-cause.js";
22
22
  import { createServerActionNotFoundResponse, getServerActionNotFoundMessage } from "./server-action-not-found.js";
23
23
  import { buildPageCacheTags } from "./implicit-tags.js";
24
24
  import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
@@ -488,6 +488,7 @@ function createAppRscHandler(options) {
488
488
  return async function appRscHandler(rawRequest, ctx) {
489
489
  options.registerCacheAdapters();
490
490
  await options.ensureInstrumentation?.();
491
+ rawRequest = await bufferRequestBodyForHeaderClone(rawRequest);
491
492
  const mwCtx = rawRequest.headers.get(VINEXT_MW_CTX_HEADER);
492
493
  const hasDataRequestHeader = rawRequest.headers.get("x-nextjs-data") === "1";
493
494
  const pagesDataUrl = new URL(rawRequest.url);
@@ -161,6 +161,18 @@ declare function processMiddlewareHeaders(headers: Headers): void;
161
161
  * @returns A new Headers with internal framework headers removed
162
162
  */
163
163
  declare function filterInternalHeaders(headers: Headers): Headers;
164
+ /**
165
+ * Materialize the request body before header/url cloning.
166
+ *
167
+ * `cloneRequestWithHeaders` / `cloneRequestWithUrl` can lose a streaming body
168
+ * on Node/undici when the input is a foreign Request or when the underlying
169
+ * stream was partially consumed. Server actions and route handlers both rely on
170
+ * the body surviving internal header filtering, so we read it once up front
171
+ * and rebuild a fresh Request for the rest of the pipeline.
172
+ *
173
+ * Multipart bodies are left streaming so FormData parsing still works.
174
+ */
175
+ declare function bufferRequestBodyForHeaderClone(request: Request): Promise<Request>;
164
176
  /**
165
177
  * Clone a Request while overriding headers, preserving metadata when possible.
166
178
  *
@@ -184,4 +196,4 @@ declare function cloneRequestWithHeaders(request: Request, headers: Headers): Re
184
196
  */
185
197
  declare function cloneRequestWithUrl(request: Request, url: string): Request;
186
198
  //#endregion
187
- export { HeaderRecord, INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, applyConfigHeadersToHeaderRecord, applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
199
+ export { HeaderRecord, INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, applyConfigHeadersToHeaderRecord, applyConfigHeadersToResponse, bufferRequestBodyForHeaderClone, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
@@ -365,6 +365,56 @@ function getRequestCf(request) {
365
365
  const cf = Reflect.get(request, "cf");
366
366
  return cf === void 0 ? void 0 : cf;
367
367
  }
368
+ const METHODS_THAT_MAY_HAVE_BODY = new Set([
369
+ "POST",
370
+ "PUT",
371
+ "PATCH",
372
+ "DELETE"
373
+ ]);
374
+ /**
375
+ * Materialize the request body before header/url cloning.
376
+ *
377
+ * `cloneRequestWithHeaders` / `cloneRequestWithUrl` can lose a streaming body
378
+ * on Node/undici when the input is a foreign Request or when the underlying
379
+ * stream was partially consumed. Server actions and route handlers both rely on
380
+ * the body surviving internal header filtering, so we read it once up front
381
+ * and rebuild a fresh Request for the rest of the pipeline.
382
+ *
383
+ * Multipart bodies are left streaming so FormData parsing still works.
384
+ */
385
+ async function bufferRequestBodyForHeaderClone(request) {
386
+ if (!METHODS_THAT_MAY_HAVE_BODY.has(request.method.toUpperCase())) return request;
387
+ if (request.body === null) return request;
388
+ if ((request.headers.get("content-type") ?? "").startsWith("multipart/form-data")) return request;
389
+ try {
390
+ const bytes = await request.arrayBuffer();
391
+ const init = {
392
+ method: request.method,
393
+ headers: request.headers,
394
+ body: bytes,
395
+ redirect: request.redirect,
396
+ referrer: request.referrer,
397
+ referrerPolicy: request.referrerPolicy,
398
+ signal: request.signal,
399
+ credentials: request.credentials,
400
+ integrity: request.integrity,
401
+ keepalive: request.keepalive,
402
+ mode: request.mode,
403
+ cache: request.cache
404
+ };
405
+ if (bytes.byteLength > 0) init.duplex = "half";
406
+ const buffered = new Request(request.url, init);
407
+ const cf = getRequestCf(request);
408
+ if (cf !== void 0) Object.defineProperty(buffered, "cf", {
409
+ value: cf,
410
+ enumerable: true,
411
+ configurable: true
412
+ });
413
+ return buffered;
414
+ } catch {
415
+ return request;
416
+ }
417
+ }
368
418
  /**
369
419
  * Clone a Request while overriding headers, preserving metadata when possible.
370
420
  *
@@ -444,4 +494,4 @@ function cloneRequestWithUrl(request, url) {
444
494
  return cloned;
445
495
  }
446
496
  //#endregion
447
- export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, applyConfigHeadersToHeaderRecord, applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
497
+ export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, applyConfigHeadersToHeaderRecord, applyConfigHeadersToResponse, bufferRequestBodyForHeaderClone, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qzsy/vinext",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Run Next.js apps on Vite. Drop-in replacement for the next CLI.",
5
5
  "license": "MIT",
6
6
  "repository": {