Skip to content

Migrate to VineXT: Auth + API Routes Verification#1048

Open
eser wants to merge 1 commit intof:mainfrom
eser:worktree-agent-a8c8a738
Open

Migrate to VineXT: Auth + API Routes Verification#1048
eser wants to merge 1 commit intof:mainfrom
eser:worktree-agent-a8c8a738

Conversation

@eser
Copy link

@eser eser commented Feb 28, 2026

Summary

  • Add vite.config.ts with VineXT plugin and a custom vinextFontPatch Vite plugin that rewrites ESM named imports for Google Fonts not in VineXT's pre-exported set to use the Proxy default export
  • Simplify next.config.ts by removing Sentry, MDX, and next-intl wrappers (handled natively by VineXT)
  • Update package.json scripts to use vinext CLI (dev/build/start), add "type": "module", and add VineXT + Vite 7 dependencies
  • Convert MCP endpoint from Pages Router (src/pages/api/mcp.ts) to App Router (src/app/api/mcp/route.ts) using WebStandardStreamableHTTPServerTransport
  • Remove src/pages/ directory to prevent VineXT Pages Router handler from intercepting App Router API routes
  • Add /dist and /.vinext to .gitignore

Test plan

  • Auth providers endpoint (/api/auth/providers) returns 200 OK with GitHub, Google, Apple
  • Auth CSRF endpoint (/api/auth/csrf) returns 200 OK with valid token
  • Auth session endpoint (/api/auth/session) returns 200 OK
  • Health endpoint (/api/health) returns 503 (expected without DB)
  • vinext build completes successfully
  • All 652 unit tests pass across 39 test files
  • npm run lint passes with no new issues

Summary by CodeRabbit

  • Chores
    • Migrated build system infrastructure to new development stack with updated dependencies
    • Upgraded React and React DOM to version 19.2.4
    • Removed error tracking and multi-language support framework integrations
    • Modernized internal API routing and request handling patterns

- Add vite.config.ts with VineXT plugin and custom font patch for Google Fonts not pre-exported by VineXT shim
- Simplify next.config.ts by removing Sentry, MDX, and next-intl wrappers handled natively by VineXT
- Update package.json scripts to use vinext CLI, add type:module, and add VineXT/Vite 7 dependencies
- Convert MCP endpoint from Pages Router to App Router using Web Standard transport
- Remove src/pages/ directory to prevent VineXT Pages Router handler from intercepting App Router API routes
- Add /dist and /.vinext to .gitignore

Verified: auth endpoints return 200 OK, vinext build completes, all 652 tests pass.
@coderabbitai
Copy link

coderabbitai bot commented Feb 28, 2026

📝 Walkthrough

Walkthrough

This PR migrates the project from Next.js Pages Router to App Router, removes Sentry/next-intl/MDX integrations, introduces Vite as the build system via vinext, updates React dependencies to ^19.2.4, and eliminates the custom Sentry error page. Configuration is simplified and modernized.

Changes

Cohort / File(s) Summary
Build Tooling Setup
.gitignore, vite.config.ts
Adds /dist and /.vinext ignore entries; introduces new vinextFontPatch() plugin to rewrite next/font/google imports for unlisted fonts via default Proxy exports.
Configuration Simplification
next.config.ts
Removes Sentry, next-intl, and MDX wrapper integrations; removes webpack customization and top-level serverActions; adds experimental.serverActions block; switches default export from composed wrapper to direct nextConfig.
Dependencies & Scripts
package.json
Adds "type": "module" declaration; reworks scripts to use vinext commands (dev, build, start); upgrades React to ^19.2.4; adds vite, vinext, @vitejs/plugin-rsc, @cloudflare/vite-plugin, and react-server-dom-webpack dependencies.
Router Migration & Error Handling
src/app/api/mcp/route.ts, src/pages/_error.tsx
Converts MCP API route from Pages Router to App Router with named exports (GET, POST, DELETE); switches to NextRequest/NextResponse and WebStandardStreamableHTTPServerTransport; removes custom error page with Sentry integration.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Handler as App Router<br/>Handler
    participant Transport as WebStandard<br/>Transport
    participant Server as MCP<br/>Server
    participant Response as NextResponse

    Client->>Handler: POST/GET/DELETE Request
    Handler->>Transport: Initialize & pass request
    Transport->>Server: Handle via transport
    Server->>Transport: Process & return result
    Transport->>Handler: Transform stream ready
    Handler->>Response: Create NextResponse<br/>with stream
    Response->>Client: Return streamed response
    Handler->>Transport: Cleanup on completion
    Handler->>Server: Shutdown
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 The build tools shift and configs dance,
From Pages past to App Router's prance,
Vite and vinext join the show,
Sentry bids its last adieu, don't you know?
React springs forth in modern dress—
A better toolchain, nothing less! 🚀

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the primary objective of the PR: migrating the project to VineXT with specific focus on auth and API routes verification.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/app/api/mcp/route.ts (2)

1393-1408: ⚠️ Potential issue | 🟠 Major

Move auth/setup into the protected error path.

Line 1393 (authenticateApiKey) and Line 1406 (createServer) run before the try at Line 1408. If either throws (e.g., DB outage), this handler skips your JSON-RPC error response path.

💡 Suggested fix
 export async function POST(request: NextRequest) {
   const url = new URL(request.url);
@@
-  // Authenticate user if API key is provided
-  const authenticatedUser = await authenticateApiKey(apiKey);
-
-  const serverOptions: ServerOptions = { authenticatedUser };
-  if (categoriesParam) {
-    serverOptions.categories = categoriesParam.split(",").map((c) => c.trim());
-  }
-  if (tagsParam) {
-    serverOptions.tags = tagsParam.split(",").map((t) => t.trim());
-  }
-  if (usersParam) {
-    serverOptions.users = usersParam.split(",").map((u) => u.trim());
-  }
-
-  const server = createServer(serverOptions);
+  let server: ReturnType<typeof createServer> | null = null;
+  let transport: WebStandardStreamableHTTPServerTransport | null = null;
 
   try {
-    const transport = new WebStandardStreamableHTTPServerTransport({
+    const authenticatedUser = await authenticateApiKey(apiKey);
+    const serverOptions: ServerOptions = { authenticatedUser };
+    if (categoriesParam) serverOptions.categories = categoriesParam.split(",").map((c) => c.trim());
+    if (tagsParam) serverOptions.tags = tagsParam.split(",").map((t) => t.trim());
+    if (usersParam) serverOptions.users = usersParam.split(",").map((u) => u.trim());
+
+    server = createServer(serverOptions);
+    transport = new WebStandardStreamableHTTPServerTransport({
       sessionIdGenerator: undefined,
     });
@@
   } catch (error) {
+    transport?.close();
+    server?.close();
     console.error("MCP error:", error);
     return NextResponse.json(

Also applies to: 1447-1456

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/api/mcp/route.ts` around lines 1393 - 1408, Move the authentication
and server setup into the protected try/catch so any exceptions (e.g., DB
outage) are handled by the JSON-RPC error path: wrap the calls to
authenticateApiKey(...) and createServer(...) (and the serverOptions
construction that depends on categoriesParam/tagsParam/usersParam) inside the
existing try block (the same protected error-handling scope used for request
handling) so thrown errors are caught and converted to the JSON-RPC error
response; apply the same change to the analogous setup at the later block that
spans the code around createServer/auth there (the 1447-1456 area).

1383-1404: ⚠️ Potential issue | 🟠 Major

Add Zod schema validation with bounds for query parameters before parsing.

Lines 1383-1404 accept raw query strings without validation. Add a Zod schema that validates and bounds categories, tags, and users parameters (e.g., max array length, max item length) before the split(",") operations to prevent DoS attacks and enforce API constraints.

const querySchema = z.object({
  categories: z.string().max(1000).optional(),
  tags: z.string().max(1000).optional(),
  users: z.string().max(1000).optional(),
  api_key: z.string().optional(),
});

const queryParams = querySchema.parse(Object.fromEntries(url.searchParams));

Then validate and split:

if (queryParams.categories) {
  const categoryArray = queryParams.categories.split(",").map((c) => c.trim());
  if (categoryArray.length > 50) throw new Error("Too many categories");
  serverOptions.categories = categoryArray;
}

Per coding guidelines, src/app/api/**/route.ts requires Zod for request validation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/api/mcp/route.ts` around lines 1383 - 1404, Add Zod validation for
the incoming query params before using categoriesParam/tagsParam/usersParam:
define a z.object schema validating optional strings for categories, tags, users
and api_key with max length bounds (e.g., 1000 chars) and parse
Object.fromEntries(url.searchParams) into queryParams; replace the raw
categoriesParam/tagsParam/usersParam usage with queryParams, split and trim into
arrays, and enforce array size limits (e.g., max 50 items) before assigning to
serverOptions.categories/tags/users; keep the existing api key
extraction/authenticateApiKey flow but validate api_key via the schema as well.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@package.json`:
- Line 5: package.json sets "type":"module" but scripts/setup.js and
scripts/lint-mdx.js use CommonJS require() which will fail; fix by either
converting those two scripts to ESM (replace require/module.exports with
import/export and update any __dirname usage) or rename the files to
scripts/setup.cjs and scripts/lint-mdx.cjs so Node treats them as CommonJS;
update package.json npm script entries if you rename files to .cjs and verify
any child modules invoked by setup.js or lint-mdx.js are also ESM/CommonJS
compatible.

In `@vite.config.ts`:
- Around line 34-36: The current logic uses importRe and a single call to
code.match to capture only the first named import from "next/font/google" and
thus rewrites only one occurrence; update this to iterate over all matches (use
importRe with the global flag or use code.matchAll) and process each match so
every named import occurrence is rewritten. Specifically replace the
single-match usage of importRe/match with a loop over matches (e.g., for (const
m of code.matchAll(importRe)) { ... }) and apply the same rewriting logic used
at the rewrite site (the code that currently handles the single match around
where match is checked and where the rewrite near Line 61 happens) for each
found match. Ensure you reconstruct imports correctly for each match and return
the fully transformed code.

---

Outside diff comments:
In `@src/app/api/mcp/route.ts`:
- Around line 1393-1408: Move the authentication and server setup into the
protected try/catch so any exceptions (e.g., DB outage) are handled by the
JSON-RPC error path: wrap the calls to authenticateApiKey(...) and
createServer(...) (and the serverOptions construction that depends on
categoriesParam/tagsParam/usersParam) inside the existing try block (the same
protected error-handling scope used for request handling) so thrown errors are
caught and converted to the JSON-RPC error response; apply the same change to
the analogous setup at the later block that spans the code around
createServer/auth there (the 1447-1456 area).
- Around line 1383-1404: Add Zod validation for the incoming query params before
using categoriesParam/tagsParam/usersParam: define a z.object schema validating
optional strings for categories, tags, users and api_key with max length bounds
(e.g., 1000 chars) and parse Object.fromEntries(url.searchParams) into
queryParams; replace the raw categoriesParam/tagsParam/usersParam usage with
queryParams, split and trim into arrays, and enforce array size limits (e.g.,
max 50 items) before assigning to serverOptions.categories/tags/users; keep the
existing api key extraction/authenticateApiKey flow but validate api_key via the
schema as well.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d9370c8 and 8157f09.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • .gitignore
  • next.config.ts
  • package.json
  • src/app/api/mcp/route.ts
  • src/pages/_error.tsx
  • vite.config.ts
💤 Files with no reviewable changes (1)
  • src/pages/_error.tsx

"name": "prompts.chat-v2",
"version": "0.1.0",
"private": true,
"type": "module",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n package.json

Repository: f/prompts.chat

Length of output: 5140


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python - <<'PY'
import json, re, pathlib

pkg = json.loads(pathlib.Path("package.json").read_text())
targets = set()

for name, cmd in pkg.get("scripts", {}).items():
    for m in re.finditer(r'\bnode\s+([^\s]+\.js)\b', cmd):
        targets.add(m.group(1))

if not targets:
    print("No node-invoked .js scripts found.")
    raise SystemExit(0)

for rel in sorted(targets):
    path = pathlib.Path(rel)
    print(f"\n== {rel} ==")
    if not path.exists():
        print("MISSING FILE")
        continue
    text = path.read_text(errors="ignore").splitlines()
    found = False
    for i, line in enumerate(text, 1):
        if "require(" in line or "module.exports" in line or re.search(r'\bexports\.', line):
            found = True
            print(f"{i}: {line}")
    if not found:
        print("No CommonJS patterns found.")
PY

Repository: f/prompts.chat

Length of output: 452


Convert scripts to ESM or rename to .cjs format.

Both scripts/setup.js and scripts/lint-mdx.js use CommonJS require() syntax, which is incompatible with the "type": "module" setting in package.json. When these scripts run via npm run setup and npm run lint:mdx, Node will interpret them as ESM modules, causing runtime failures.

Migrate to ESM imports (import statements) or rename files to .cjs extension to preserve CommonJS compatibility.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` at line 5, package.json sets "type":"module" but
scripts/setup.js and scripts/lint-mdx.js use CommonJS require() which will fail;
fix by either converting those two scripts to ESM (replace
require/module.exports with import/export and update any __dirname usage) or
rename the files to scripts/setup.cjs and scripts/lint-mdx.cjs so Node treats
them as CommonJS; update package.json npm script entries if you rename files to
.cjs and verify any child modules invoked by setup.js or lint-mdx.js are also
ESM/CommonJS compatible.

Comment on lines +34 to +36
const importRe = /import\s*\{([^}]+)\}\s*from\s*['"]next\/font\/google['"]/;
const match = code.match(importRe);
if (!match) return null;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Patch currently rewrites only the first next/font/google named import.

Line 34/Line 35 uses a single match, so Line 61 rewrites only one import occurrence. Files with multiple next/font/google imports can still break for unlisted fonts.

💡 Suggested fix
-      const importRe = /import\s*\{([^}]+)\}\s*from\s*['"]next\/font\/google['"]/;
-      const match = code.match(importRe);
-      if (!match) return null;
-
-      // Parse import specifiers, handling "Name as Alias" syntax
-      const specifiers = match[1].split(",").map((s) => s.trim()).filter(Boolean);
-      const parsed = specifiers.map((spec) => {
-        const parts = spec.split(/\s+as\s+/);
-        return { name: parts[0].trim(), alias: (parts[1] || parts[0]).trim() };
-      });
-
-      const missing = parsed.filter((p) => !preExported.has(p.name));
-      if (missing.length === 0) return null;
-
-      // Keep pre-exported fonts as named imports, access others via default Proxy
-      const kept = parsed.filter((p) => preExported.has(p.name));
-      const keptClause = kept.length > 0
-        ? `{ ${kept.map((p) => p.name === p.alias ? p.name : `${p.name} as ${p.alias}`).join(", ")} }`
-        : "";
-      const defaultClause = "__googleFonts";
-      const importParts = [defaultClause, keptClause].filter(Boolean).join(", ");
-
-      let replacement = `import ${importParts} from "next/font/google";\n`;
-      for (const { name, alias } of missing) {
-        replacement += `const ${alias} = __googleFonts.${name};\n`;
-      }
-
-      return code.replace(match[0], replacement);
+      const importRe = /import\s*\{([^}]+)\}\s*from\s*['"]next\/font\/google['"];?/g;
+      let patched = false;
+      const rewritten = code.replace(importRe, (_full, rawSpecifiers: string) => {
+        const specifiers = rawSpecifiers.split(",").map((s) => s.trim()).filter(Boolean);
+        const parsed = specifiers.map((spec) => {
+          const parts = spec.split(/\s+as\s+/);
+          return { name: parts[0].trim(), alias: (parts[1] || parts[0]).trim() };
+        });
+
+        const missing = parsed.filter((p) => !preExported.has(p.name));
+        if (missing.length === 0) return _full;
+
+        patched = true;
+        const kept = parsed.filter((p) => preExported.has(p.name));
+        const keptClause = kept.length > 0
+          ? `{ ${kept.map((p) => p.name === p.alias ? p.name : `${p.name} as ${p.alias}`).join(", ")} }`
+          : "";
+        const defaultClause = "__googleFonts";
+        const importParts = [defaultClause, keptClause].filter(Boolean).join(", ");
+
+        let replacement = `import ${importParts} from "next/font/google";\n`;
+        for (const { name, alias } of missing) {
+          replacement += `const ${alias} = __googleFonts.${name};\n`;
+        }
+        return replacement;
+      });
+
+      return patched ? rewritten : null;

Also applies to: 61-61

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vite.config.ts` around lines 34 - 36, The current logic uses importRe and a
single call to code.match to capture only the first named import from
"next/font/google" and thus rewrites only one occurrence; update this to iterate
over all matches (use importRe with the global flag or use code.matchAll) and
process each match so every named import occurrence is rewritten. Specifically
replace the single-match usage of importRe/match with a loop over matches (e.g.,
for (const m of code.matchAll(importRe)) { ... }) and apply the same rewriting
logic used at the rewrite site (the code that currently handles the single match
around where match is checked and where the rewrite near Line 61 happens) for
each found match. Ensure you reconstruct imports correctly for each match and
return the fully transformed code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant