vinext 0.0.15 → 0.0.16

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.
Files changed (44) hide show
  1. package/README.md +6 -0
  2. package/dist/cli.js +21 -11
  3. package/dist/cli.js.map +1 -1
  4. package/dist/config/config-matchers.d.ts +4 -1
  5. package/dist/config/config-matchers.d.ts.map +1 -1
  6. package/dist/config/config-matchers.js +11 -1
  7. package/dist/config/config-matchers.js.map +1 -1
  8. package/dist/config/next-config.d.ts +2 -0
  9. package/dist/config/next-config.d.ts.map +1 -1
  10. package/dist/config/next-config.js.map +1 -1
  11. package/dist/deploy.d.ts.map +1 -1
  12. package/dist/deploy.js +2 -0
  13. package/dist/deploy.js.map +1 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +68 -57
  16. package/dist/index.js.map +1 -1
  17. package/dist/server/app-dev-server.d.ts.map +1 -1
  18. package/dist/server/app-dev-server.js +25 -9
  19. package/dist/server/app-dev-server.js.map +1 -1
  20. package/dist/server/middleware.d.ts +23 -1
  21. package/dist/server/middleware.d.ts.map +1 -1
  22. package/dist/server/middleware.js +42 -8
  23. package/dist/server/middleware.js.map +1 -1
  24. package/dist/server/prod-server.js +1 -1
  25. package/dist/server/prod-server.js.map +1 -1
  26. package/dist/shims/fetch-cache.d.ts.map +1 -1
  27. package/dist/shims/fetch-cache.js +73 -41
  28. package/dist/shims/fetch-cache.js.map +1 -1
  29. package/dist/shims/font-google-base.d.ts +68 -0
  30. package/dist/shims/font-google-base.d.ts.map +1 -0
  31. package/dist/shims/font-google-base.js +365 -0
  32. package/dist/shims/font-google-base.js.map +1 -0
  33. package/dist/shims/font-google.d.ts +2 -121
  34. package/dist/shims/font-google.d.ts.map +1 -1
  35. package/dist/shims/font-google.generated.d.ts +1925 -0
  36. package/dist/shims/font-google.generated.d.ts.map +1 -0
  37. package/dist/shims/font-google.generated.js +1928 -0
  38. package/dist/shims/font-google.generated.js.map +1 -0
  39. package/dist/shims/font-google.js +2 -386
  40. package/dist/shims/font-google.js.map +1 -1
  41. package/dist/utils/project.d.ts.map +1 -1
  42. package/dist/utils/project.js +4 -0
  43. package/dist/utils/project.js.map +1 -1
  44. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -5,12 +5,12 @@ import { createSSRHandler } from "./server/dev-server.js";
5
5
  import { handleApiRoute } from "./server/api-handler.js";
6
6
  import { generateRscEntry, generateSsrEntry, generateBrowserEntry, } from "./server/app-dev-server.js";
7
7
  import { loadNextConfig, resolveNextConfig, } from "./config/next-config.js";
8
- import { findMiddlewareFile, runMiddleware } from "./server/middleware.js";
8
+ import { findMiddlewareFile, isProxyFile, runMiddleware } from "./server/middleware.js";
9
9
  import { generateSafeRegExpCode, generateMiddlewareMatcherCode, generateNormalizePathCode } from "./server/middleware-codegen.js";
10
10
  import { normalizePath } from "./server/normalize-path.js";
11
11
  import { findInstrumentationFile, runInstrumentation } from "./server/instrumentation.js";
12
12
  import { validateDevRequest } from "./server/dev-origin-check.js";
13
- import { safeRegExp, escapeHeaderSource, isExternalUrl, proxyExternalRequest } from "./config/config-matchers.js";
13
+ import { safeRegExp, isExternalUrl, proxyExternalRequest, parseCookies, matchHeaders, matchRedirect, matchRewrite, } from "./config/config-matchers.js";
14
14
  import { scanMetadataFiles } from "./server/metadata-routes.js";
15
15
  import tsconfigPaths from "vite-tsconfig-paths";
16
16
  import MagicString from "magic-string";
@@ -18,6 +18,7 @@ import path from "node:path";
18
18
  import { fileURLToPath, pathToFileURL } from "node:url";
19
19
  import { createRequire } from "node:module";
20
20
  import fs from "node:fs";
21
+ import commonjs from "vite-plugin-commonjs";
21
22
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
22
23
  /**
23
24
  * Fetch Google Fonts CSS, download .woff2 files, cache locally, and return
@@ -568,8 +569,15 @@ ${generateSafeRegExpCode("es5")}
568
569
  ${generateMiddlewareMatcherCode("es5")}
569
570
 
570
571
  export async function runMiddleware(request) {
571
- var middlewareFn = middlewareModule.default || middlewareModule.middleware;
572
- if (typeof middlewareFn !== "function") return { continue: true };
572
+ var isProxy = ${middlewarePath ? JSON.stringify(isProxyFile(middlewarePath)) : "false"};
573
+ var middlewareFn = isProxy
574
+ ? (middlewareModule.proxy ?? middlewareModule.default)
575
+ : (middlewareModule.middleware ?? middlewareModule.default);
576
+ if (typeof middlewareFn !== "function") {
577
+ var fileType = isProxy ? "Proxy" : "Middleware";
578
+ var expectedExport = isProxy ? "proxy" : "middleware";
579
+ throw new Error("The " + fileType + " file must export a function named \`" + expectedExport + "\` or a \`default\` function.");
580
+ }
573
581
 
574
582
  var config = middlewareModule.config;
575
583
  var matcher = config && config.matcher;
@@ -606,9 +614,13 @@ export async function runMiddleware(request) {
606
614
  if (response.headers.get("x-middleware-next") === "1") {
607
615
  var rHeaders = new Headers();
608
616
  for (var [key, value] of response.headers) {
609
- // Strip ALL x-middleware-* headers they are internal routing signals
610
- // and must never reach clients.
611
- if (!key.startsWith("x-middleware-")) rHeaders.append(key, value);
617
+ // Keep x-middleware-request-* headers so the production server can
618
+ // apply middleware-request header overrides before stripping internals
619
+ // from the final client response.
620
+ if (
621
+ !key.startsWith("x-middleware-") ||
622
+ key.startsWith("x-middleware-request-")
623
+ ) rHeaders.append(key, value);
612
624
  }
613
625
  return { continue: true, responseHeaders: rHeaders };
614
626
  }
@@ -621,7 +633,9 @@ export async function runMiddleware(request) {
621
633
  var rewriteUrl = response.headers.get("x-middleware-rewrite");
622
634
  if (rewriteUrl) {
623
635
  var rwHeaders = new Headers();
624
- for (var [k, v] of response.headers) { if (!k.startsWith("x-middleware-")) rwHeaders.append(k, v); }
636
+ for (var [k, v] of response.headers) {
637
+ if (!k.startsWith("x-middleware-") || k.startsWith("x-middleware-request-")) rwHeaders.append(k, v);
638
+ }
625
639
  var rewritePath;
626
640
  try { var parsed = new URL(rewriteUrl, request.url); rewritePath = parsed.pathname + parsed.search; }
627
641
  catch { rewritePath = rewriteUrl; }
@@ -1534,6 +1548,9 @@ hydrate();
1534
1548
  // Resolve tsconfig paths/baseUrl aliases so real-world Next.js repos
1535
1549
  // that use @/*, #/*, or baseUrl imports work out of the box.
1536
1550
  tsconfigPaths(),
1551
+ // Transform CJS require()/module.exports to ESM before other plugins
1552
+ // analyze imports (RSC directive scanning, shim resolution, etc.)
1553
+ commonjs(),
1537
1554
  {
1538
1555
  name: "vinext:config",
1539
1556
  enforce: "pre",
@@ -1870,11 +1887,15 @@ hydrate();
1870
1887
  client: {
1871
1888
  optimizeDeps: {
1872
1889
  exclude: ["vinext"],
1873
- // react and react-dom are framework dependencies used for
1874
- // hydration. They aren't crawled from app/ source files so
1875
- // must be pre-included to prevent late discovery and page
1876
- // reloads during development.
1877
- include: ["react", "react-dom", "react-dom/client"],
1890
+ // React packages aren't crawled from app/ source files,
1891
+ // so must be pre-included to avoid late discovery (#25).
1892
+ include: [
1893
+ "react",
1894
+ "react-dom",
1895
+ "react-dom/client",
1896
+ "react/jsx-runtime",
1897
+ "react/jsx-dev-runtime",
1898
+ ],
1878
1899
  },
1879
1900
  build: {
1880
1901
  // When targeting Cloudflare Workers, enable manifest generation
@@ -2297,13 +2318,25 @@ hydrate();
2297
2318
  req.__vinextRewriteStatus = result.rewriteStatus;
2298
2319
  }
2299
2320
  }
2321
+ // Build request context once for has/missing condition checks
2322
+ // across headers, redirects, and rewrites.
2323
+ const reqUrl = new URL(url, `http://${req.headers.host || "localhost"}`);
2324
+ const reqCtxHeaders = new Headers(Object.fromEntries(Object.entries(req.headers)
2325
+ .filter(([, v]) => v !== undefined)
2326
+ .map(([k, v]) => [k, Array.isArray(v) ? v.join(", ") : String(v)])));
2327
+ const reqCtx = {
2328
+ headers: reqCtxHeaders,
2329
+ cookies: parseCookies(reqCtxHeaders.get("cookie")),
2330
+ query: reqUrl.searchParams,
2331
+ host: reqCtxHeaders.get("host") ?? reqUrl.host,
2332
+ };
2300
2333
  // Apply custom headers from next.config.js
2301
2334
  if (nextConfig?.headers.length) {
2302
- applyHeaders(pathname, res, nextConfig.headers);
2335
+ applyHeaders(pathname, res, nextConfig.headers, reqCtx);
2303
2336
  }
2304
2337
  // Apply redirects from next.config.js
2305
2338
  if (nextConfig?.redirects.length) {
2306
- const redirected = applyRedirects(pathname, res, nextConfig.redirects);
2339
+ const redirected = applyRedirects(pathname, res, nextConfig.redirects, reqCtx);
2307
2340
  if (redirected)
2308
2341
  return;
2309
2342
  }
@@ -2311,7 +2344,7 @@ hydrate();
2311
2344
  let resolvedUrl = url;
2312
2345
  if (nextConfig?.rewrites.beforeFiles.length) {
2313
2346
  resolvedUrl =
2314
- applyRewrites(pathname, nextConfig.rewrites.beforeFiles) ??
2347
+ applyRewrites(pathname, nextConfig.rewrites.beforeFiles, reqCtx) ??
2315
2348
  url;
2316
2349
  }
2317
2350
  // External rewrite from beforeFiles — proxy to external URL
@@ -2338,7 +2371,7 @@ hydrate();
2338
2371
  // *resolved* pathname. Next.js applies these when route matching succeeds
2339
2372
  // but allows overriding with rewrites.
2340
2373
  if (nextConfig?.rewrites.afterFiles.length) {
2341
- const afterRewrite = applyRewrites(resolvedUrl.split("?")[0], nextConfig.rewrites.afterFiles);
2374
+ const afterRewrite = applyRewrites(resolvedUrl.split("?")[0], nextConfig.rewrites.afterFiles, reqCtx);
2342
2375
  if (afterRewrite)
2343
2376
  resolvedUrl = afterRewrite;
2344
2377
  }
@@ -2357,7 +2390,7 @@ hydrate();
2357
2390
  }
2358
2391
  // No route matched — try fallback rewrites
2359
2392
  if (nextConfig?.rewrites.fallback.length) {
2360
- const fallbackRewrite = applyRewrites(resolvedUrl.split("?")[0], nextConfig.rewrites.fallback);
2393
+ const fallbackRewrite = applyRewrites(resolvedUrl.split("?")[0], nextConfig.rewrites.fallback, reqCtx);
2361
2394
  if (fallbackRewrite) {
2362
2395
  // External fallback rewrite — proxy to external URL
2363
2396
  if (isExternalUrl(fallbackRewrite)) {
@@ -3172,22 +3205,14 @@ function sanitizeDestinationLocal(dest) {
3172
3205
  * Apply redirect rules from next.config.js.
3173
3206
  * Returns true if a redirect was applied.
3174
3207
  */
3175
- function applyRedirects(pathname, res, redirects) {
3176
- for (const redirect of redirects) {
3177
- const params = matchConfigPattern(pathname, redirect.source);
3178
- if (params) {
3179
- let dest = redirect.destination;
3180
- for (const [key, value] of Object.entries(params)) {
3181
- dest = dest.replace(`:${key}*`, value);
3182
- dest = dest.replace(`:${key}+`, value);
3183
- dest = dest.replace(`:${key}`, value);
3184
- }
3185
- // Sanitize to prevent open redirect via protocol-relative URLs
3186
- dest = sanitizeDestinationLocal(dest);
3187
- res.writeHead(redirect.permanent ? 308 : 307, { Location: dest });
3188
- res.end();
3189
- return true;
3190
- }
3208
+ function applyRedirects(pathname, res, redirects, ctx) {
3209
+ const result = matchRedirect(pathname, redirects, ctx);
3210
+ if (result) {
3211
+ // Sanitize to prevent open redirect via protocol-relative URLs
3212
+ const dest = sanitizeDestinationLocal(result.destination);
3213
+ res.writeHead(result.permanent ? 308 : 307, { Location: dest });
3214
+ res.end();
3215
+ return true;
3191
3216
  }
3192
3217
  return false;
3193
3218
  }
@@ -3254,35 +3279,21 @@ async function proxyExternalRewriteNode(req, res, externalUrl) {
3254
3279
  * Apply rewrite rules from next.config.js.
3255
3280
  * Returns the rewritten URL or null if no rewrite matched.
3256
3281
  */
3257
- function applyRewrites(pathname, rewrites) {
3258
- for (const rewrite of rewrites) {
3259
- const params = matchConfigPattern(pathname, rewrite.source);
3260
- if (params) {
3261
- let dest = rewrite.destination;
3262
- for (const [key, value] of Object.entries(params)) {
3263
- dest = dest.replace(`:${key}*`, value);
3264
- dest = dest.replace(`:${key}+`, value);
3265
- dest = dest.replace(`:${key}`, value);
3266
- }
3267
- // Sanitize to prevent open redirect via protocol-relative URLs
3268
- dest = sanitizeDestinationLocal(dest);
3269
- return dest;
3270
- }
3282
+ function applyRewrites(pathname, rewrites, ctx) {
3283
+ const dest = matchRewrite(pathname, rewrites, ctx);
3284
+ if (dest) {
3285
+ // Sanitize to prevent open redirect via protocol-relative URLs
3286
+ return sanitizeDestinationLocal(dest);
3271
3287
  }
3272
3288
  return null;
3273
3289
  }
3274
3290
  /**
3275
3291
  * Apply custom header rules from next.config.js.
3276
3292
  */
3277
- function applyHeaders(pathname, res, headers) {
3278
- for (const rule of headers) {
3279
- const escaped = escapeHeaderSource(rule.source);
3280
- const sourceRegex = safeRegExp("^" + escaped + "$");
3281
- if (sourceRegex && sourceRegex.test(pathname)) {
3282
- for (const header of rule.headers) {
3283
- res.setHeader(header.key, header.value);
3284
- }
3285
- }
3293
+ function applyHeaders(pathname, res, headers, ctx) {
3294
+ const matched = matchHeaders(pathname, headers, ctx);
3295
+ for (const header of matched) {
3296
+ res.setHeader(header.key, header.value);
3286
3297
  }
3287
3298
  }
3288
3299
  /**