55 Commits

Author SHA1 Message Date
Sunil Pai c4f50b616f fix: fetch cache key generation — handle all body types, include all headers minus blocklist (#111)
* fix: fetch cache key generation — handle all body types, include all headers minus blocklist

- Make buildFetchCacheKey async to support stream/blob body serialization
- Handle all BodyInit types: string, Uint8Array, ReadableStream, FormData, Blob, URLSearchParams
- Switch header strategy from allowlist (3 auth headers) to blocklist (traceparent/tracestate), matching Next.js
- Include RequestInit fields (mode, redirect, credentials, etc.) in cache key
- SHA-256 hash the cache key for compact, deterministic storage
- Fix spent stream bug: restore _ogBody in stripNextFromInit so originalFetch gets usable body
- Add 19 new tests covering body types, header inclusion, body restoration, and URLSearchParams

* Improve fetch cache key generation

Replace simple auth-header extraction with a unified header collector, add a header blocklist and cache version prefix, and introduce async cache key building. serializeBody now handles various body types (Uint8Array, streams, URLSearchParams, FormData, Blob, string), preserves the original body on init._ogBody, and body content is included in the cache key. The cache key is generated by normalizing URL, method, headers and init options and hashing them with SHA-256. buildFetchCacheKey is now async and awaited where used, and stripNextFromInit restores the preserved original body. Also add hasAuthHeaders and move auth header list into a constant.

* PR #111 approved. 52 tests pass, 3 fixes correct.

Co-authored-by: threepointone <threepointone@users.noreply.github.com>

---------

Co-authored-by: ask-bonk[bot] <ask-bonk[bot]@users.noreply.github.com>
Co-authored-by: threepointone <threepointone@users.noreply.github.com>
v0.0.12
2026-02-26 12:33:37 +00:00
Sunil Pai de9b679f24 harden CI workflows: frozen-lockfile, checksum verification (#113)
- Add --frozen-lockfile to pnpm install in ci.yml, deploy-examples.yml, benchmarks.yml, preview-release.yml
- Add SHA256 checksum verification for hyperfine .deb download in benchmarks.yml
2026-02-26 12:24:27 +00:00
Sunil Pai 12b364705a chore: rebuild pages-basic fixture dist (#110)
Syncs the checked-in build artifact with current source. Notable
changes: middleware runner now wraps decodeURIComponent in try/catch,
jsx-dev-runtime switched to jsx-runtime for production build.
2026-02-26 11:24:05 +00:00
Sunil Pai 940af6895e fix: dev sanitizeDestination now normalizes leading backslashes (#108)
The dev server's __sanitizeDestination only collapsed leading '//' but
ignored leading backslashes (e.g. '\evil.com'). The prod version in
config-matchers.ts already used /^[\/]+/ to handle both. Align the
dev codegen to match.
2026-02-26 11:10:53 +00:00
Sunil Pai 8a618af9f6 fix: handle malformed percent-encoded URLs gracefully (#107)
Wrap all decodeURIComponent calls on user-controlled URL paths in
try/catch to return 400 Bad Request instead of throwing an uncaught
URIError that crashes the Node process.

A single request with a malformed percent-encoded path (e.g. /%E0%A4%A)
could terminate the entire server process. This affected all server
entry points: prod server (App + Pages Router), dev server middleware,
Cloudflare Worker entry, and generated RSC/middleware handlers.

Fixes:
- prod-server.ts: App Router and Pages Router request handlers
- app-router-entry.ts: Cloudflare Worker entry
- app-dev-server.ts: Generated RSC entry handler
- index.ts: Dev server connect middleware + generated middleware runner
  + generated NEXT_LOCALE cookie parser
- middleware.ts: Pages Router dev middleware runner

Includes 11 regression tests across app-router, pages-router, and
features test suites.
2026-02-26 10:52:57 +00:00
Sunil Pai fd01d7d8a6 fix: close security gaps in init.ts shell exec and app-dev-server external proxy (#106)
* fix: close security gaps in init.ts shell exec and app-dev-server external proxy

Gap 1 (GHSA-w7vc-6jjg-498h): migrate init.ts from execSync to execFileSync
with argument array, matching the pattern already applied in deploy.ts and
cli.ts. Inputs are hardcoded package names so practical risk is near zero,
but this eliminates the last instance of the flagged pattern.

Gap 2 (GHSA-pf96-3m7r-pv3j): harden the inline __proxyExternalRequest in
the generated RSC entry (app-dev-server.ts) to strip Cookie, Authorization,
x-api-key, proxy-authorization, and all x-middleware-* headers before
forwarding to external rewrite targets. Also adds a 30-second
AbortSignal.timeout. This brings the dev-server code path into parity with
the already-fixed proxyExternalRequest in config-matchers.ts.

Also fixes a missed GSP redirect path in dev-server.ts where backslash
normalization was not applied (GHSA-79rw-r8hc-qg8v — the GSSP path was
already committed).

Includes an integration test that verifies credential stripping end-to-end
via a mock HTTP server and a conditional external rewrite in next.config.ts.

* fix: unify isExternalUrl to detect all URL schemes and protocol-relative URLs

All four copies of isExternalUrl (config-matchers.ts, router.ts,
navigation.ts, app-dev-server.ts inline) now use the same RFC 3986
scheme regex: /^[a-z][a-z0-9+.-]*:/i.test(url) || url.startsWith('//')

Previously:
- config-matchers.ts and app-dev-server.ts only checked http:// and
  https:// (missing // protocol-relative)
- router.ts and navigation.ts checked http://, https://, and // but
  missed exotic schemes (data:, javascript:, blob:, ftp:, etc.)

Now all copies are consistent and detect any URL scheme per RFC 3986
plus protocol-relative URLs.

Adds test cases for exotic schemes, protocol-relative, hash-only, and
bare string inputs.

* fix: add shell: true to execFileSync for Windows .cmd file compat

On Windows, package managers (pnpm, npm, yarn) are .cmd batch files.
execFileSync without shell: true cannot execute them. Adding shell: true
lets the OS shell resolve .cmd files while still using the argument array
form for safer argument passing.
2026-02-26 10:33:08 +00:00
Sunil Pai 0e750f7934 Security hardening: redirect sanitization, header stripping, ALS isolation tests, and safer command execution (#105)
* Sanitize redirects/headers and use execFileSync

Replace execSync calls with execFileSync (pass argv arrays) to avoid shell interpolation and adjust package-install logic to split package manager and args. Sanitize redirect destinations in SSR paths to prevent protocol-relative open-redirects and use sanitizeDestinationLocal for Next.js redirects. Ensure middleware receives a cleaned pathname by stripping internal .rsc suffix before creating NextRequest and add a test for this behavior. Strip sensitive headers (cookie, authorization and x-middleware-*) from proxied external requests and add a test. Document cache key hazards for auth headers in fetch-cache, add a security note for dangerouslySetInnerHTML in head SSR, and set the Draft Mode cookie to include Secure in production (with tests for production/dev behavior).

* Rename middleware header to x-custom-middleware

Change middleware header name from x-middleware-test to x-custom-middleware across fixtures and tests, and clarify server comment about stripping x-middleware-* headers from responses (reserved for internal routing signals). Files updated: packages/vinext/src/server/prod-server.ts (comment tweak), tests/fixtures/pages-basic/middleware.ts (header set), and tests/pages-router.test.ts (expectations and test titles/comments). This ensures tests reflect the new public header name while preserving internal x-middleware-* semantics.

* Normalize leading slashes and strip headers

Normalize redirect/rewrite destinations by collapsing any leading slashes or backslashes to a single "/" to avoid protocol-relative redirects and handle browser-backslash behavior. Strip additional sensitive headers (x-api-key, proxy-authorization) from proxied requests and ensure all x-middleware-* internal headers are removed from responses (broadened from x-middleware-request-*). Update dev/server sanitization logic accordingly. Update tests and fixture middleware to use shortened x-mw-* header names and add tests covering backslash normalization.
v0.0.11
2026-02-26 08:50:12 +00:00
Dane 98b243493f fix: resolve CodeQL security alerts (ReDoS, incomplete sanitization, bad code gen) (#87)
Refactor chained .replace() to single-pass tokenizers in pattern matching:
- matchConfigPattern in config-matchers.ts and index.ts
- escapeHeaderSource (new) replaces inline chained escaping in matchHeaders/applyHeaders
- matchMiddlewarePattern in prod server entry template
- matchPattern in middleware.ts

Also:
- escapeHeaderSource correctly handles :param(constraint) patterns
- Fix decodeURIComponent parity gap in index.ts matchConfigPattern
- Fix redundant dot in middleware.ts tokenizer char class
- Add lgtm suppression comments for false positives in test files
- Add unit tests for escapeHeaderSource
2026-02-26 00:18:46 -06:00
Steve Faulkner 83495447ae fix: normalize request pathname before middleware and route matching (#102)
- Add normalizePath utility that collapses consecutive slashes,
  resolves . and .. segments, and ensures a leading slash
- Apply decodeURIComponent + normalizePath before middleware matching
  and route matching in all entry points (dev server, prod server,
  Cloudflare Worker entry, codegen entries)
- Extract shared middleware codegen module (middleware-codegen.ts) as
  single source of truth for pattern matching logic, replacing
  hand-copied inline implementations in index.ts and app-dev-server.ts
- Fix default middleware matcher to return true when no matcher is
  configured, matching Next.js behavior
- Fix regex pattern corruption in middleware matcher: patterns containing
  parentheses or backslashes are now passed to RegExp directly without
  dot-escaping
v0.0.10
2026-02-26 05:39:36 +00:00
Steve Faulkner 6986e1017f fix: validate image optimization content types and width bounds (#101)
- Add Content-Security-Policy and X-Content-Type-Options headers to image responses
- Validate Content-Type allowlist (reject SVG, HTML, non-image types)
- Bound width parameter to configured deviceSizes/imageSizes with 3840px max
- Add deviceSizes and imageSizes to NextConfig type
- Apply to all image paths: Workers, Node.js prod server (App + Pages Router)
- Fix benchmarks limit param NaN handling
2026-02-26 05:08:44 +00:00
Steve Faulkner 16988a5403 fix: add request validation to dev server (#98) 2026-02-25 22:51:16 -06:00
Steve Faulkner abad2e4431 fix: use AsyncLocalStorage.run() for request context isolation (#99) 2026-02-25 22:51:05 -06:00
Steve Faulkner 75742312bb fix: sanitize error messages in production mode (#97) 2026-02-26 04:24:54 +00:00
Steve Faulkner 708d85e36d fix: enforce body size limit on App Router server actions (#96) 2026-02-26 04:23:40 +00:00
Steve Faulkner aca46417d9 fix: use Host header for server action origin check (#95) 2026-02-26 04:22:31 +00:00
Steve Faulkner af485aec24 fix: validate module paths during client-side navigation (#94) 2026-02-26 04:19:43 +00:00
Steve Faulkner dda10590d7 fix: include relevant headers in fetch cache key (#93) 2026-02-26 04:17:18 +00:00
Steve Faulkner 3ff59fa6d4 fix: sanitize redirect destinations and digest parsing (#92) 2026-02-26 04:14:56 +00:00
Steve Faulkner 3f406045aa fix: add Vary header to SSR and RSC responses (#91)
* fix: add Vary: RSC, Accept header to prevent CDN cache poisoning

Add Vary: RSC, Accept to all App Router RSC stream and HTML SSR
responses to prevent CDN cache poisoning. Without this header, a CDN
or reverse proxy may cache an RSC stream response and serve it to a
browser expecting HTML (or vice versa), breaking the page.

Affected response types in app-dev-server.ts:
- Main RSC stream responses (client-side navigation)
- HTML SSR responses (all cache control variants)
- Not-found/forbidden/unauthorized fallback pages (RSC and HTML)
- Error boundary pages (RSC and HTML)
- Server action redirect and re-render responses
- Intercepting route RSC stream responses

Fix Vary header merging in prod-server.ts:
- sendWebResponse: merge Accept-Encoding with existing Vary values
  instead of overwriting (preserves RSC, Accept from upstream)
- sendCompressed: same merge behavior for buffered responses

Scope analysis (intentionally NOT changed):
- Pages Router: no RSC/HTML content negotiation on same URL
- Route handler responses: content type is handler-controlled
- Metadata routes: serve single content type per URL
- Static assets: no content negotiation
- Error/redirect responses: not cached or content-negotiated
- Worker entry (app-router-entry.ts): passes through RSC handler
  responses which already include the Vary header

Closes GHSA-jgqv-mvrh-hv36
Related: GHSA-r2fc-ccr8-96c4 (Next.js equivalent)

* remove advisory reference from code comment

---------

Co-authored-by: ask-bonk[bot] <ask-bonk[bot]@users.noreply.github.com>
2026-02-25 22:12:55 -06:00
Steve Faulkner a151f3da6b chore: upgrade vitest from v3 to v4 (#65)
No breaking changes affect this project — config and test code
required no modifications.
2026-02-25 22:17:48 +00:00
Steve Faulkner 8dac26c0e5 fix(dotenv): load .env files with Next.js precedence (#70)
* feat(cli): load .env files with Next.js precedence

* fix(dotenv): address review feedback on .env loading

- Document Vite double-loading interaction in loadDotenv JSDoc
- Fix escaped dollar sign bug ($100 was not unescaped when $ wasn't
  followed by a valid variable name)
- Add type cast for parseEnv return value
- Expand test coverage: loadedEnv assertions, production mode
  precedence, ${VAR} expansion, escaped dollars, circular refs,
  missing files, empty result
- Add getDotenvFiles unit tests for all three modes
- Add 'Prefer Node.js Built-in APIs' guideline to AGENTS.md

Co-authored-by: liuxiaopai-ai <liuxiaopai-ai@users.noreply.github.com>

* test(dotenv): add cross-file expansion and multi-line value tests

Address review suggestions: test that .env can reference vars from
higher-priority .env.development.local, and that parseEnv handles
quoted multi-line values correctly.

---------

Co-authored-by: root <root@localhost.localdomain>
Co-authored-by: liuxiaopai-ai <liuxiaopai-ai@users.noreply.github.com>
v0.0.9
2026-02-25 14:21:48 -06:00
Steve Faulkner f1e5c31c2e Fix AI Gateway auth (use cf-aig-authorization) and show Google Chat error body (#69) 2026-02-25 13:47:39 -06:00
Steve Faulkner bc75de3548 Skip deploy previews for fork PRs that lack Cloudflare secrets (#67)
Fork PRs don't have access to repository secrets (CLOUDFLARE_API_TOKEN,
CLOUDFLARE_ACCOUNT_ID), so deploy/smoke-test/comment steps always fail.
Add a fork detection condition to skip these steps gracefully. The build
steps still run, so example builds are still validated for fork PRs.
2026-02-25 13:47:24 -06:00
Steve Faulkner 4d0a008644 Add AI-generated release summary + Google Chat notification to publish workflow (#68)
* Skip deploy previews for fork PRs that lack Cloudflare secrets

Fork PRs don't have access to repository secrets (CLOUDFLARE_API_TOKEN,
CLOUDFLARE_ACCOUNT_ID), so deploy/smoke-test/comment steps always fail.
Add a fork detection condition to skip these steps gracefully. The build
steps still run, so example builds are still validated for fork PRs.

* Add AI-generated release summary + Google Chat notification to publish workflow
v0.0.8
2026-02-25 13:09:16 -06:00
Ivan Torres 36ab8b0f18 fix: replace glob npm package with native node:fs/promises glob (#52)
* fix: replace glob npm package with native node:fs/promises glob

Migrate pagesRouter, apiRouter, and appRouter from the third-party 'glob'
package to Node.js built-in glob (node:fs/promises), available since
Node 22. This removes a dependency and fixes path handling issues on
Windows where dynamic route segments (e.g. [slug]) were incorrectly
parsed due to premature path separator normalization.

Changes:
- Use for-await with glob() from node:fs/promises
- Use exclude callbacks instead of post-filtering
- Normalize pagePath/routePath with replaceAll('\\', '/') in output
- Remove glob dependency from package.json

* fix: address review feedback on native glob migration

- Fix excludePrivate over-exclusion: the native glob exclude callback
  fires at every directory depth, not just the root. Replace with
  post-filtering on the first path segment to match the old glob
  package's root-relative ignore behavior.
- Remove redundant .replaceAll('\\', '/') normalization from
  pagePath/routePath in app-router.ts — consumers already normalize
  backslashes, and this was inconsistent with pages-router.ts.
- Add engines field (node >= 22) since fs.glob requires Node 22+.

* refactor: use glob pattern arrays instead of callbacks for exclude

- app-router: replace hasSlotSegment callback with ['**/@*'] pattern
- pages-router: replace excludePrivate callback with ['api', '**/_*'] patterns
- Simplify iteration: process glob results directly instead of collecting into intermediate arrays

---------

Co-authored-by: Steve Faulkner <sfaulkner@cloudflare.com>
2026-02-25 12:31:41 -06:00
Skywalker512 cb15a16aaa fix: link to Vite RSC plugin in README (#39)
Updated the link for the Vite RSC plugin to point to the correct repository.
2026-02-25 10:55:21 -06:00
Steve Faulkner f6ba607258 fix: make chat notification non-fatal and add charset to content-type (#62) 2026-02-25 16:21:08 +00:00
Steve Faulkner c0acaa6e57 fix: read CLI version from package.json instead of hardcoded value (#61) 2026-02-25 16:14:19 +00:00
Steve Faulkner 8558c2d68e ci: notify Google Chat on npm publish (#55) v0.0.7 2026-02-25 15:41:11 +00:00
Steve Faulkner 0866ddaa2f ci: wire up npm publishing with OIDC trusted publishing (#54)
- Add version bump input (patch/minor/major) to publish workflow
- Gate publish on full CI suite (lint, typecheck, vitest, e2e)
- Use npm OIDC trusted publishing instead of long-lived NPM_TOKEN
- Tag releases in git after publish
- Make ci.yml callable via workflow_call
- Fix repository URL format in package.json for OIDC validation
v0.0.6
2026-02-25 09:03:57 -06:00
Steve Faulkner 61554eaf37 fix: install react-server-dom-webpack during init and deploy for App Router (#31)
* fix: install react-server-dom-webpack during init and deploy for App Router

vinext init was missing react-server-dom-webpack from its dependency list,
causing 'Could not resolve react-server-dom-webpack/server.edge' errors on
fresh create-next-app projects. Additionally, react-server-dom-webpack@19.2.4
requires react@^19.2.4, but create-next-app ships react@19.2.3 -- the version
mismatch caused npm to nest rsdw inside vinext/node_modules where Vite can't
resolve it.

Fix: add react-server-dom-webpack to getInitDeps for App Router, detect when
the installed React version is too old, and upgrade react/react-dom as regular
dependencies before installing dev deps (avoiding ERESOLVE peer-dep conflicts
and keeping react in 'dependencies' rather than 'devDependencies').

Also applies the same fix to vinext deploy for parity, and adds a CI job that
scaffolds a real create-next-app project, runs vinext init, and verifies the
dev server returns HTTP 200.

Closes #22

* refactor: use createRequire for package resolution instead of direct node_modules reads

Address review feedback (PR #18 pattern): replace fs.existsSync(node_modules/...)
with createRequire-based resolution, which handles hoisting, pnpm symlinks,
monorepos, and Yarn PnP correctly.

- deploy.ts: extract isPackageResolvable() helper using createRequire, use it
  in getMissingDeps for react-server-dom-webpack detection
- init.ts: refactor getReactUpgradeDeps() to use createRequire + findPackageVersion
  walk-up pattern instead of reading node_modules/react/package.json directly
- tests: add isPackageResolvable unit tests, use dependency injection for
  getMissingDeps rsdw test (Vitest's createRequire intercepts resolution)

* ci: add Windows to create-next-app smoke test

Run the create-next-app compatibility test on both ubuntu-latest and
windows-latest. Replace bash-specific server health check (curl, kill,
backgrounding) with a cross-platform Node script using child_process
and http. Use runner.temp instead of /tmp for portable paths.

* fix: use pathToFileURL for dynamic import() calls on Windows

On Windows, Node's ESM loader requires file:// URLs for absolute paths.
Bare paths like D:\... are rejected with ERR_UNSUPPORTED_ESM_URL_SCHEME.

Wrap all dynamic import() calls that receive absolute paths from
require.resolve() or path.join() with pathToFileURL().href:

- index.ts: RSC plugin import, RSC transforms import, PostCSS config
  loading, PostCSS plugin resolution (5 call sites)
- cli.ts: Vite module import from project root

* fix: pathToFileURL for cache-runtime codegen and test imports

Additional Windows fixes found via PR #43 review:

- index.ts: use pathToFileURL for runtimeModulePath in 'use cache'
  transform code generation (2 locations) — these embed absolute paths
  into generated import() statements via JSON.stringify
- pages-router.test.ts: wrap 9 import(serverEntryPath) calls with
  pathToFileURL so tests work on Windows
2026-02-25 08:38:54 -06:00
Steve Faulkner 05ef04788c feat(deploy): add --env support with security and parsing improvements (#49)
* feat(deploy): add --env support for wrangler deploy

Adds vinext deploy --env <name> and threads it through to wrangler deploy --env <name>. Keeps --preview working as shorthand for preview environment, adds unit tests for wrangler arg construction, and updates README/help examples. Refs #33.

* fix(deploy): use execFileSync and util.parseArgs for --env support

Build on #44 by liuxiaopai-ai — adds --env flag for wrangler deploy.

Security: switch from execSync(shell string) to execFileSync(binary, args)
to eliminate command injection via unsanitized --env/--name values.

Replace hand-rolled flag parsing (parseStringFlag, parseNumericFlag,
rawArgs.includes) with Node.js built-in util.parseArgs. This gives us
strict mode (throws on unknown flags), automatic --flag=value handling,
and proper error messages for missing values.

Also: buildWranglerDeployArgs now returns { args, env } directly instead
of re-parsing the args array for the log message.

---------

Co-authored-by: root <root@localhost.localdomain>
2026-02-25 06:57:44 -06:00
Tiago Linares 0d5b42c79e fix: preserve binary API response bytes in prod-server (#30)
Updated the production server to handle binary responses correctly by using Buffer.from with arrayBuffer instead of text(). Added a test to ensure binary data integrity and created a new fixture for testing binary API responses.
2026-02-25 04:36:28 +00:00
Marcus Reinhardt 9f5550579e fix vite-rsc link (#20) 2026-02-24 22:35:25 -06:00
Steve Faulkner 388d3e6b79 ci: use --pnpm flag for pkg-pr-new publish (#36) 2026-02-24 21:44:59 -06:00
Steve Faulkner f22eb8fc9b docs: add SECURITY.md with vulnerability reporting info (#35) 2026-02-25 03:07:42 +00:00
Steve Faulkner ecdebab977 ci: add pkg.pr.new preview releases for PRs (#34) 2026-02-25 02:51:33 +00:00
Steve Faulkner 7a26409e88 chore: bump version to 0.0.5 (#29) 2026-02-24 21:56:22 +00:00
Steve Faulkner 197f42106a docs: add LICENSE, sync package README, add bug reporting guidance (#26)
* docs: update README — add blog link, lead with agent skill, fix examples, remove stale benchmarks

* docs: add LICENSE, sync package README from root, add bug reporting guidance

- Add MIT LICENSE to repo root
- Copy root README into package at prepack time instead of maintaining two copies
- Add 'Reporting bugs' section encouraging AI-assisted diagnosis

* fix: update LICENSE copyright to Cloudflare, Inc.
2026-02-24 15:40:12 -06:00
Steve Faulkner 2c732add55 docs: update README — add blog link, lead with agent skill, fix examples, remove stale benchmarks (#19) 2026-02-24 20:11:37 +00:00
Steve Faulkner 97d7e204bf v0.0.4 (#17) 2026-02-24 13:22:02 -06:00
Steve Faulkner bec45ebb3b fix: don't tell users to run vinext init when already inside vinext init (#14) 2026-02-24 19:01:08 +00:00
Steve Faulkner 6c3a8897de chore: bump version to 0.0.3 (#16) 2026-02-24 12:54:13 -06:00
Fred K. Schott 2b04681406 fix: resolve vinext init issues with missing dep, duplicate rsc plugin, and peer dep conflict (#15)
- Install vinext itself as a devDependency during init (#11)
- Remove explicit rsc() from generated configs since vinext auto-registers it (#12)
- Widen react/react-dom peer dep to >=19.2.0 for create-next-app compat (#13)

Co-authored-by: Fred K. Schott <fschott@cloudflare.com>
2026-02-24 12:29:26 -06:00
Steve Faulkner 01793e79d9 ci: disable scheduled tip workflow for now (#10) 2026-02-24 12:36:48 -05:00
Steve Faulkner 5c44676f64 chore: bump version to 0.0.2 (#8) 2026-02-24 11:32:03 -06:00
Sunil Pai acd1110b04 fix: inline source content in sourcemaps to prevent missing source warnings (#5)
When vinext is installed from npm, the .ts source files aren't in the
package but .js.map files reference them, causing Vite to log many
'points to missing source files' warnings.

Adding inlineSources: true to tsconfig embeds the original TypeScript
source content directly in the .js.map files so no separate .ts files
are needed.

Fixes #2
2026-02-24 11:13:41 -06:00
Sunil Pai 493a4c1b70 fix: add 'use client' to next/dynamic shim for App Router RSC compatibility (#7)
When a server component imports next/dynamic, the RSC serializer must
treat it as a client boundary. Without 'use client', the dynamic()
function executes inline in the RSC environment — for ssr:false, this
serializes null into the RSC payload and the client never loads the
component.

Adding 'use client' matches Next.js's App Router behavior where
next/dynamic is a client module. The RSC serializer emits a client
reference, and the client executes the full dynamic logic including
the ssr:false mount-on-client behavior.

Updated test fixtures that called dynamic() from server modules to
include 'use client' — this is required since dynamic() is now a
client export and can only be called from client modules.

Added E2E test for ssr:false from a server component page.
2026-02-24 11:13:29 -06:00
Sunil Pai 3ed38d1c4a fix: exclude vinext from optimizeDeps to prevent virtual module resolution errors (#3)
* fix: exclude vinext from optimizeDeps to prevent virtual module resolution errors

When vinext is installed from npm (not symlinked), esbuild's dependency
optimization scans vinext/dist/ and hits virtual:vinext-* imports that
only exist at Vite plugin resolution time. This causes build failures
in all three environments (client, rsc, ssr).

Adding optimizeDeps.exclude: ['vinext'] at the top level and in each
environment prevents esbuild from scanning vinext's dist files entirely.

Fixes #1

* test: verify optimizeDeps.exclude contains vinext for all environments
2026-02-24 11:13:28 -06:00
Matt Silverlock 009ace26bf add migrate-to-vinext agent skill (#6)
* add migrate-to-vinext agent skill

* Apply suggestion from @elithrar

* remove .claude/skills in favor of .agents/skills
2026-02-24 16:53:38 +00:00