-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
test(vue-start): basic-cloudflare, basic-auth #6137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThis PR adds comprehensive e2e projects for Vue Start with both basic authentication and Cloudflare integration, while updating the existing Solid Start basic-auth project with enhanced build processes, server function bindings, and database configuration changes. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60–90 minutes Areas requiring extra attention:
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
|
View your CI Pipeline Execution ↗ for commit 6fe8ae5
☁️ Nx Cloud last updated this comment at |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 15
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
e2e/solid-start/basic-auth/src/utils/prisma.ts (1)
10-20: Critical security flaw: hardcoded salt defeats password hashing.The
hashPasswordfunction uses a static salt'salt'for all passwords. This means:
- Identical passwords produce identical hashes
- The database is vulnerable to rainbow table attacks
- Password security is significantly weakened
Each password must have a unique, randomly generated salt.
🔎 Refactor to use unique salts per password:
export function hashPassword(password: string) { return new Promise<string>((resolve, reject) => { - crypto.pbkdf2(password, 'salt', 100000, 64, 'sha256', (err, derivedKey) => { + const salt = crypto.randomBytes(16) + crypto.pbkdf2(password, salt, 100000, 64, 'sha256', (err, derivedKey) => { if (err) { reject(err) } else { - resolve(derivedKey.toString('hex')) + // Store salt + hash together, e.g., "salt:hash" + resolve(salt.toString('hex') + ':' + derivedKey.toString('hex')) } }) }) }Note: You'll also need to update the verification logic to split the stored value and extract the salt for comparison.
Alternatively, consider using a battle-tested library like
bcryptorargon2:-import crypto from 'node:crypto' +import bcrypt from 'bcrypt' -export function hashPassword(password: string) { - return new Promise<string>((resolve, reject) => { - crypto.pbkdf2(password, 'salt', 100000, 64, 'sha256', (err, derivedKey) => { - if (err) { - reject(err) - } else { - resolve(derivedKey.toString('hex')) - } - }) - }) -} +export async function hashPassword(password: string) { + return bcrypt.hash(password, 10) +}e2e/solid-start/basic-auth/src/routes/signup.tsx (1)
23-24: Misleading comment about password hashing.Line 23's comment states "Encrypt the password using Sha256 into plaintext", which is inaccurate:
- The code uses PBKDF2 (not direct SHA-256)
- Hashing produces a hash digest, not "plaintext"
- The phrase "encrypt...into plaintext" is contradictory
🔎 Update the comment for accuracy:
- // Encrypt the password using Sha256 into plaintext + // Hash the password using PBKDF2 with SHA-256 const password = await hashPassword(payload.password)
🧹 Nitpick comments (11)
e2e/vue-start/basic-auth/src/utils/session.ts (1)
1-1: Stale file path comment.The comment references
src/services/session.server.tsbut the actual file path issrc/utils/session.ts. Consider updating or removing it.Suggested fix
-// src/services/session.server.ts +// src/utils/session.tse2e/vue-start/basic-auth/prisma/migrations/20240811183753_init/migration.sql (1)
7-8: Redundant unique index on primary key.The unique index on
🔎 Consider removing the redundant index:
- --- CreateIndex -CREATE UNIQUE INDEX "User_email_key" ON "User"("email");e2e/vue-start/basic-auth/.env (1)
7-7: Consider minor formatting improvements.Static analysis suggests:
- Adding a blank line at the end of the file
- Removing quotes around the value (optional for simple paths)
🔎 Apply formatting improvements:
-DATABASE_URL="file:./dev.db" +DATABASE_URL=file:./dev.db +e2e/vue-start/basic-auth/tests/mock-db-teardown.test.ts (1)
5-5: Test name could be more descriptive.The teardown is named
'create new database'but actually resets the existing database by deleting all users and creating a fresh test user. Consider renaming to better reflect the actual behavior.🔎 Suggested improvement:
-teardown('create new database', async () => { +teardown('reset database with test user', async () => {e2e/vue-start/basic-cloudflare/src/router.tsx (1)
10-11: Consider consistent component passing.
defaultErrorComponentis passed directly whiledefaultNotFoundComponentis wrapped in an arrow function. Both are functional components, so this inconsistency is unexpected unless required by the framework.🔎 If both can be passed directly, consider:
defaultErrorComponent: DefaultCatchBoundary, -defaultNotFoundComponent: () => <NotFound />, +defaultNotFoundComponent: NotFound,Verify whether TanStack Vue Router requires the arrow function wrapper for
defaultNotFoundComponentor if both can be passed directly.e2e/vue-start/basic-auth/src/routes/login.tsx (1)
8-10: Consider removing the unnecessary wrapper function.The
LoginCompwrapper doesn't add any logic or transformation. You can simplify by using theLogincomponent directly in the route definition.🔎 Apply this diff to simplify the route:
export const Route = createFileRoute('/login')({ - component: LoginComp, + component: Login, }) - -function LoginComp() { - return <Login /> -}e2e/vue-start/basic-auth/src/components/Auth.tsx (1)
1-13: Consider consistent prop typing with React version.The Vue version uses
VNode | nullforafterSubmit, while the React version (e2e/react-start/basic-auth/src/components/Auth.tsx) usesReact.ReactNode. For Vue, consider using a more flexible type that allows both render functions and VNodes.The current typing works, but if you want to support both static VNodes and render functions consistently across the codebase, you could type it as:
afterSubmit?: (() => VNode) | VNode | nullThis would allow both patterns while maintaining type safety.
e2e/vue-start/basic-auth/src/components/DefaultCatchBoundary.tsx (1)
42-45: Consider explicit event typing for consistency.The
onClickhandler uses an implicit event type(e), while similar implementations in other Vue Start projects (e.g., e2e/vue-start/server-routes, e2e/vue-start/custom-basepath) explicitly type it as(e: MouseEvent).For consistency across the codebase:
- onClick={(e) => { + onClick={(e: MouseEvent) => { e.preventDefault() window.history.back() }}e2e/solid-start/basic-auth/src/components/Login.tsx (1)
8-25: Consider consistent server function binding pattern.Line 10 binds
loginFntologinoutside the mutation, while line 24 usesuseServerFn(signupFn)inline. For consistency and readability, consider extracting the signup binding as well:const login = useServerFn(loginFn) const signup = useServerFn(signupFn) const loginMutation = useMutation({ fn: login, // ... }) const signupMutation = useMutation({ fn: signup, })e2e/vue-start/basic-auth/src/hooks/useMutation.ts (1)
1-40: LGTM with optional enhancement.The mutation hook follows a solid pattern with proper Vue 3 reactivity using
shallowRef. Error handling and state management are correct.One optional enhancement: The
catchblock on line 26-28 doesn't return a value, somutatereturnsundefinedon error. While this may be intentional, you could explicitly document this behavior or add an explicitreturn undefinedfor clarity:🔎 Optional: Make error return explicit
} catch (err) { status.value = 'error' error.value = err as TError + return undefined }e2e/vue-start/basic-auth/src/routes/signup.tsx (1)
30-48: Optional: Unusual signup behavior when user exists.Lines 30-48 implement a pattern where if a user already exists with a matching password, the signup function logs them in and redirects. This is unconventional (signup typically fails if a user exists), but may be intentional for e2e test convenience.
If this is production code, consider whether this behavior could be a security concern (it leaks information about whether an email is registered). For e2e tests, this is likely fine.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (17)
e2e/solid-start/basic-auth/dev.dbis excluded by!**/*.dbe2e/vue-start/basic-auth/dev.dbis excluded by!**/*.dbe2e/vue-start/basic-auth/public/android-chrome-192x192.pngis excluded by!**/*.pnge2e/vue-start/basic-auth/public/android-chrome-512x512.pngis excluded by!**/*.pnge2e/vue-start/basic-auth/public/apple-touch-icon.pngis excluded by!**/*.pnge2e/vue-start/basic-auth/public/favicon-16x16.pngis excluded by!**/*.pnge2e/vue-start/basic-auth/public/favicon-32x32.pngis excluded by!**/*.pnge2e/vue-start/basic-auth/public/favicon.icois excluded by!**/*.icoe2e/vue-start/basic-auth/public/favicon.pngis excluded by!**/*.pnge2e/vue-start/basic-cloudflare/public/android-chrome-192x192.pngis excluded by!**/*.pnge2e/vue-start/basic-cloudflare/public/android-chrome-512x512.pngis excluded by!**/*.pnge2e/vue-start/basic-cloudflare/public/apple-touch-icon.pngis excluded by!**/*.pnge2e/vue-start/basic-cloudflare/public/favicon-16x16.pngis excluded by!**/*.pnge2e/vue-start/basic-cloudflare/public/favicon-32x32.pngis excluded by!**/*.pnge2e/vue-start/basic-cloudflare/public/favicon.icois excluded by!**/*.icoe2e/vue-start/basic-cloudflare/public/favicon.pngis excluded by!**/*.pngpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (78)
e2e/solid-start/basic-auth/.gitignore(1 hunks)e2e/solid-start/basic-auth/package.json(2 hunks)e2e/solid-start/basic-auth/playwright.config.ts(2 hunks)e2e/solid-start/basic-auth/src/components/Auth.tsx(2 hunks)e2e/solid-start/basic-auth/src/components/Login.tsx(2 hunks)e2e/solid-start/basic-auth/src/routes/signup.tsx(1 hunks)e2e/solid-start/basic-auth/src/utils/prisma.ts(1 hunks)e2e/solid-start/basic-auth/src/utils/session.ts(1 hunks)e2e/solid-start/basic-auth/tests/app.spec.ts(3 hunks)e2e/solid-start/basic-auth/tests/mock-db-setup.test.ts(1 hunks)e2e/solid-start/basic-auth/tests/mock-db-teardown.test.ts(1 hunks)e2e/vue-start/basic-auth/.env(1 hunks)e2e/vue-start/basic-auth/.gitignore(1 hunks)e2e/vue-start/basic-auth/.prettierignore(1 hunks)e2e/vue-start/basic-auth/package.json(1 hunks)e2e/vue-start/basic-auth/playwright.config.ts(1 hunks)e2e/vue-start/basic-auth/postcss.config.mjs(1 hunks)e2e/vue-start/basic-auth/prisma.config.ts(1 hunks)e2e/vue-start/basic-auth/prisma/migrations/20240811183753_init/migration.sql(1 hunks)e2e/vue-start/basic-auth/prisma/migrations/migration_lock.toml(1 hunks)e2e/vue-start/basic-auth/prisma/schema.prisma(1 hunks)e2e/vue-start/basic-auth/public/site.webmanifest(1 hunks)e2e/vue-start/basic-auth/src/components/Auth.tsx(1 hunks)e2e/vue-start/basic-auth/src/components/DefaultCatchBoundary.tsx(1 hunks)e2e/vue-start/basic-auth/src/components/Login.tsx(1 hunks)e2e/vue-start/basic-auth/src/components/NotFound.tsx(1 hunks)e2e/vue-start/basic-auth/src/hooks/useMutation.ts(1 hunks)e2e/vue-start/basic-auth/src/prisma-generated/browser.ts(1 hunks)e2e/vue-start/basic-auth/src/prisma-generated/client.ts(1 hunks)e2e/vue-start/basic-auth/src/prisma-generated/commonInputTypes.ts(1 hunks)e2e/vue-start/basic-auth/src/prisma-generated/enums.ts(1 hunks)e2e/vue-start/basic-auth/src/prisma-generated/internal/class.ts(1 hunks)e2e/vue-start/basic-auth/src/prisma-generated/internal/prismaNamespace.ts(1 hunks)e2e/vue-start/basic-auth/src/prisma-generated/internal/prismaNamespaceBrowser.ts(1 hunks)e2e/vue-start/basic-auth/src/prisma-generated/models.ts(1 hunks)e2e/vue-start/basic-auth/src/prisma-generated/models/User.ts(1 hunks)e2e/vue-start/basic-auth/src/routeTree.gen.ts(1 hunks)e2e/vue-start/basic-auth/src/router.tsx(1 hunks)e2e/vue-start/basic-auth/src/routes/__root.tsx(1 hunks)e2e/vue-start/basic-auth/src/routes/_authed.tsx(1 hunks)e2e/vue-start/basic-auth/src/routes/_authed/posts.$postId.tsx(1 hunks)e2e/vue-start/basic-auth/src/routes/_authed/posts.index.tsx(1 hunks)e2e/vue-start/basic-auth/src/routes/_authed/posts.tsx(1 hunks)e2e/vue-start/basic-auth/src/routes/index.tsx(1 hunks)e2e/vue-start/basic-auth/src/routes/login.tsx(1 hunks)e2e/vue-start/basic-auth/src/routes/logout.tsx(1 hunks)e2e/vue-start/basic-auth/src/routes/signup.tsx(1 hunks)e2e/vue-start/basic-auth/src/styles/app.css(1 hunks)e2e/vue-start/basic-auth/src/utils/posts.ts(1 hunks)e2e/vue-start/basic-auth/src/utils/prisma.ts(1 hunks)e2e/vue-start/basic-auth/src/utils/seo.ts(1 hunks)e2e/vue-start/basic-auth/src/utils/session.ts(1 hunks)e2e/vue-start/basic-auth/tests/app.spec.ts(1 hunks)e2e/vue-start/basic-auth/tests/mock-db-setup.test.ts(1 hunks)e2e/vue-start/basic-auth/tests/mock-db-teardown.test.ts(1 hunks)e2e/vue-start/basic-auth/tsconfig.json(1 hunks)e2e/vue-start/basic-auth/vite.config.ts(1 hunks)e2e/vue-start/basic-cloudflare/.gitignore(1 hunks)e2e/vue-start/basic-cloudflare/.prettierignore(1 hunks)e2e/vue-start/basic-cloudflare/package.json(1 hunks)e2e/vue-start/basic-cloudflare/playwright.config.ts(1 hunks)e2e/vue-start/basic-cloudflare/postcss.config.mjs(1 hunks)e2e/vue-start/basic-cloudflare/public/site.webmanifest(1 hunks)e2e/vue-start/basic-cloudflare/src/components/DefaultCatchBoundary.tsx(1 hunks)e2e/vue-start/basic-cloudflare/src/components/NotFound.tsx(1 hunks)e2e/vue-start/basic-cloudflare/src/routeTree.gen.ts(1 hunks)e2e/vue-start/basic-cloudflare/src/router.tsx(1 hunks)e2e/vue-start/basic-cloudflare/src/routes/__root.tsx(1 hunks)e2e/vue-start/basic-cloudflare/src/routes/index.tsx(1 hunks)e2e/vue-start/basic-cloudflare/src/routes/static.tsx(1 hunks)e2e/vue-start/basic-cloudflare/src/styles/app.css(1 hunks)e2e/vue-start/basic-cloudflare/src/utils/seo.ts(1 hunks)e2e/vue-start/basic-cloudflare/tests/app.spec.ts(1 hunks)e2e/vue-start/basic-cloudflare/tests/setup/global.setup.ts(1 hunks)e2e/vue-start/basic-cloudflare/tests/setup/global.teardown.ts(1 hunks)e2e/vue-start/basic-cloudflare/tsconfig.json(1 hunks)e2e/vue-start/basic-cloudflare/vite.config.ts(1 hunks)e2e/vue-start/basic-cloudflare/wrangler.jsonc(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript strict mode with extensive type safety for all code
Files:
e2e/vue-start/basic-cloudflare/src/routes/static.tsxe2e/vue-start/basic-cloudflare/playwright.config.tse2e/vue-start/basic-cloudflare/src/router.tsxe2e/vue-start/basic-auth/src/router.tsxe2e/vue-start/basic-auth/src/utils/seo.tse2e/vue-start/basic-auth/src/components/Auth.tsxe2e/vue-start/basic-cloudflare/src/utils/seo.tse2e/vue-start/basic-auth/src/utils/prisma.tse2e/solid-start/basic-auth/tests/mock-db-teardown.test.tse2e/vue-start/basic-auth/src/routes/__root.tsxe2e/vue-start/basic-auth/src/components/Login.tsxe2e/vue-start/basic-auth/src/components/DefaultCatchBoundary.tsxe2e/vue-start/basic-auth/src/utils/session.tse2e/vue-start/basic-auth/src/prisma-generated/commonInputTypes.tse2e/vue-start/basic-auth/vite.config.tse2e/vue-start/basic-auth/src/prisma-generated/internal/prismaNamespaceBrowser.tse2e/vue-start/basic-auth/src/components/NotFound.tsxe2e/vue-start/basic-auth/src/routeTree.gen.tse2e/vue-start/basic-auth/src/routes/_authed.tsxe2e/vue-start/basic-auth/src/routes/index.tsxe2e/vue-start/basic-auth/prisma.config.tse2e/solid-start/basic-auth/src/utils/prisma.tse2e/vue-start/basic-cloudflare/src/routes/__root.tsxe2e/solid-start/basic-auth/playwright.config.tse2e/vue-start/basic-auth/playwright.config.tse2e/vue-start/basic-cloudflare/tests/setup/global.teardown.tse2e/solid-start/basic-auth/tests/mock-db-setup.test.tse2e/vue-start/basic-auth/src/routes/signup.tsxe2e/vue-start/basic-auth/src/routes/_authed/posts.index.tsxe2e/vue-start/basic-cloudflare/tests/setup/global.setup.tse2e/vue-start/basic-cloudflare/src/components/DefaultCatchBoundary.tsxe2e/vue-start/basic-auth/src/prisma-generated/client.tse2e/vue-start/basic-auth/src/utils/posts.tse2e/vue-start/basic-auth/src/prisma-generated/internal/class.tse2e/solid-start/basic-auth/src/components/Login.tsxe2e/vue-start/basic-auth/src/routes/_authed/posts.$postId.tsxe2e/solid-start/basic-auth/src/components/Auth.tsxe2e/vue-start/basic-cloudflare/src/routes/index.tsxe2e/solid-start/basic-auth/tests/app.spec.tse2e/vue-start/basic-auth/src/prisma-generated/browser.tse2e/solid-start/basic-auth/src/routes/signup.tsxe2e/vue-start/basic-auth/tests/mock-db-teardown.test.tse2e/vue-start/basic-cloudflare/vite.config.tse2e/vue-start/basic-auth/src/routes/logout.tsxe2e/vue-start/basic-cloudflare/src/components/NotFound.tsxe2e/vue-start/basic-auth/src/routes/_authed/posts.tsxe2e/solid-start/basic-auth/src/utils/session.tse2e/vue-start/basic-auth/tests/app.spec.tse2e/vue-start/basic-cloudflare/src/routeTree.gen.tse2e/vue-start/basic-auth/src/prisma-generated/models.tse2e/vue-start/basic-auth/src/prisma-generated/enums.tse2e/vue-start/basic-auth/tests/mock-db-setup.test.tse2e/vue-start/basic-auth/src/routes/login.tsxe2e/vue-start/basic-auth/src/hooks/useMutation.tse2e/vue-start/basic-cloudflare/tests/app.spec.tse2e/vue-start/basic-auth/src/prisma-generated/internal/prismaNamespace.tse2e/vue-start/basic-auth/src/prisma-generated/models/User.ts
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Implement ESLint rules for router best practices using the ESLint plugin router
Files:
e2e/vue-start/basic-cloudflare/src/routes/static.tsxe2e/vue-start/basic-cloudflare/playwright.config.tse2e/vue-start/basic-cloudflare/src/router.tsxe2e/vue-start/basic-auth/src/router.tsxe2e/vue-start/basic-auth/src/utils/seo.tse2e/vue-start/basic-auth/src/components/Auth.tsxe2e/vue-start/basic-cloudflare/src/utils/seo.tse2e/vue-start/basic-auth/src/utils/prisma.tse2e/solid-start/basic-auth/tests/mock-db-teardown.test.tse2e/vue-start/basic-auth/src/routes/__root.tsxe2e/vue-start/basic-auth/src/components/Login.tsxe2e/vue-start/basic-auth/src/components/DefaultCatchBoundary.tsxe2e/vue-start/basic-auth/src/utils/session.tse2e/vue-start/basic-auth/src/prisma-generated/commonInputTypes.tse2e/vue-start/basic-auth/vite.config.tse2e/vue-start/basic-auth/src/prisma-generated/internal/prismaNamespaceBrowser.tse2e/vue-start/basic-auth/src/components/NotFound.tsxe2e/vue-start/basic-auth/src/routeTree.gen.tse2e/vue-start/basic-auth/src/routes/_authed.tsxe2e/vue-start/basic-auth/src/routes/index.tsxe2e/vue-start/basic-auth/prisma.config.tse2e/solid-start/basic-auth/src/utils/prisma.tse2e/vue-start/basic-cloudflare/src/routes/__root.tsxe2e/solid-start/basic-auth/playwright.config.tse2e/vue-start/basic-auth/playwright.config.tse2e/vue-start/basic-cloudflare/tests/setup/global.teardown.tse2e/solid-start/basic-auth/tests/mock-db-setup.test.tse2e/vue-start/basic-auth/src/routes/signup.tsxe2e/vue-start/basic-auth/src/routes/_authed/posts.index.tsxe2e/vue-start/basic-cloudflare/tests/setup/global.setup.tse2e/vue-start/basic-cloudflare/src/components/DefaultCatchBoundary.tsxe2e/vue-start/basic-auth/src/prisma-generated/client.tse2e/vue-start/basic-auth/src/utils/posts.tse2e/vue-start/basic-auth/src/prisma-generated/internal/class.tse2e/solid-start/basic-auth/src/components/Login.tsxe2e/vue-start/basic-auth/src/routes/_authed/posts.$postId.tsxe2e/solid-start/basic-auth/src/components/Auth.tsxe2e/vue-start/basic-cloudflare/src/routes/index.tsxe2e/solid-start/basic-auth/tests/app.spec.tse2e/vue-start/basic-auth/src/prisma-generated/browser.tse2e/solid-start/basic-auth/src/routes/signup.tsxe2e/vue-start/basic-auth/tests/mock-db-teardown.test.tse2e/vue-start/basic-cloudflare/vite.config.tse2e/vue-start/basic-auth/src/routes/logout.tsxe2e/vue-start/basic-cloudflare/src/components/NotFound.tsxe2e/vue-start/basic-auth/src/routes/_authed/posts.tsxe2e/solid-start/basic-auth/src/utils/session.tse2e/vue-start/basic-auth/tests/app.spec.tse2e/vue-start/basic-cloudflare/src/routeTree.gen.tse2e/vue-start/basic-auth/src/prisma-generated/models.tse2e/vue-start/basic-auth/src/prisma-generated/enums.tse2e/vue-start/basic-auth/tests/mock-db-setup.test.tse2e/vue-start/basic-auth/src/routes/login.tsxe2e/vue-start/basic-auth/src/hooks/useMutation.tse2e/vue-start/basic-cloudflare/tests/app.spec.tse2e/vue-start/basic-auth/src/prisma-generated/internal/prismaNamespace.tse2e/vue-start/basic-auth/src/prisma-generated/models/User.ts
**/package.json
📄 CodeRabbit inference engine (AGENTS.md)
Use workspace protocol
workspace:*for internal dependencies in package.json files
Files:
e2e/solid-start/basic-auth/package.jsone2e/vue-start/basic-cloudflare/package.jsone2e/vue-start/basic-auth/package.json
🧠 Learnings (9)
📚 Learning: 2025-10-09T12:59:14.842Z
Learnt from: hokkyss
Repo: TanStack/router PR: 5418
File: e2e/react-start/custom-identifier-prefix/public/site.webmanifest:2-3
Timestamp: 2025-10-09T12:59:14.842Z
Learning: In e2e test fixtures (files under e2e directories), empty or placeholder values in configuration files like site.webmanifest are acceptable and should not be flagged unless the test specifically validates those fields.
Applied to files:
e2e/vue-start/basic-cloudflare/playwright.config.tse2e/vue-start/basic-auth/playwright.config.tse2e/vue-start/basic-cloudflare/tests/setup/global.setup.tse2e/vue-start/basic-cloudflare/public/site.webmanifeste2e/vue-start/basic-auth/public/site.webmanifeste2e/vue-start/basic-cloudflare/tests/app.spec.ts
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Applies to **/*.{js,ts,tsx} : Implement ESLint rules for router best practices using the ESLint plugin router
Applied to files:
e2e/vue-start/basic-auth/src/router.tsxe2e/vue-start/basic-auth/tsconfig.jsone2e/vue-start/basic-auth/src/routes/__root.tsxe2e/vue-start/basic-auth/.prettierignoree2e/vue-start/basic-auth/src/routeTree.gen.tse2e/vue-start/basic-auth/src/routes/index.tsxe2e/vue-start/basic-cloudflare/src/routes/__root.tsxe2e/vue-start/basic-cloudflare/.prettierignoree2e/vue-start/basic-auth/src/routes/_authed/posts.tsxe2e/vue-start/basic-cloudflare/src/routeTree.gen.tse2e/vue-start/basic-auth/src/routes/login.tsx
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
Applied to files:
e2e/vue-start/basic-auth/src/router.tsxe2e/vue-start/basic-auth/.prettierignoree2e/vue-start/basic-auth/src/routeTree.gen.tse2e/vue-start/basic-auth/src/routes/index.tsxe2e/vue-start/basic-cloudflare/.prettierignoree2e/vue-start/basic-auth/src/routes/_authed/posts.tsxe2e/vue-start/basic-cloudflare/src/routeTree.gen.ts
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript strict mode with extensive type safety for all code
Applied to files:
e2e/vue-start/basic-auth/tsconfig.jsone2e/vue-start/basic-cloudflare/tsconfig.json
📚 Learning: 2025-11-02T16:16:24.898Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5732
File: packages/start-client-core/src/client/hydrateStart.ts:6-9
Timestamp: 2025-11-02T16:16:24.898Z
Learning: In packages/start-client-core/src/client/hydrateStart.ts, the `import/no-duplicates` ESLint disable is necessary for imports from `#tanstack-router-entry` and `#tanstack-start-entry` because both aliases resolve to the same placeholder file (`fake-start-entry.js`) in package.json during static analysis, even though they resolve to different files at runtime.
Applied to files:
e2e/vue-start/basic-auth/tsconfig.jsone2e/vue-start/basic-auth/vite.config.tse2e/vue-start/basic-auth/src/routeTree.gen.tse2e/vue-start/basic-auth/src/routes/index.tsxe2e/vue-start/basic-cloudflare/tests/setup/global.setup.tse2e/vue-start/basic-auth/src/prisma-generated/client.tse2e/vue-start/basic-auth/src/prisma-generated/browser.tse2e/solid-start/basic-auth/src/utils/session.tse2e/vue-start/basic-cloudflare/package.jsone2e/vue-start/basic-cloudflare/src/routeTree.gen.tse2e/vue-start/basic-auth/package.json
📚 Learning: 2025-10-14T18:59:33.990Z
Learnt from: FatahChan
Repo: TanStack/router PR: 5475
File: e2e/react-start/basic-prerendering/src/routes/redirect/$target/via-beforeLoad.tsx:8-0
Timestamp: 2025-10-14T18:59:33.990Z
Learning: In TanStack Router e2e test files, when a route parameter is validated at the route level (e.g., using zod in validateSearch or param validation), switch statements on that parameter do not require a default case, as the validation ensures only expected values will reach the switch.
Applied to files:
e2e/vue-start/basic-auth/src/routes/__root.tsx
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.
Applied to files:
e2e/vue-start/basic-auth/.prettierignoree2e/vue-start/basic-auth/src/routeTree.gen.tse2e/vue-start/basic-auth/src/routes/index.tsxe2e/vue-start/basic-cloudflare/.prettierignoree2e/vue-start/basic-cloudflare/src/routeTree.gen.ts
📚 Learning: 2025-12-17T02:17:55.086Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 6120
File: packages/router-generator/src/generator.ts:654-657
Timestamp: 2025-12-17T02:17:55.086Z
Learning: In `packages/router-generator/src/generator.ts`, pathless_layout routes must receive a `path` property when they have a `cleanedPath`, even though they are non-path routes. This is necessary because child routes inherit the path from their parent, and without this property, child routes would not have the correct full path at runtime.
Applied to files:
e2e/vue-start/basic-auth/src/routeTree.gen.tse2e/vue-start/basic-auth/src/routes/index.tsxe2e/vue-start/basic-cloudflare/src/routes/__root.tsxe2e/vue-start/basic-auth/src/routes/_authed/posts.tsxe2e/vue-start/basic-cloudflare/src/routeTree.gen.ts
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Use file-based routing in `src/routes/` directories or code-based routing with route definitions
Applied to files:
e2e/vue-start/basic-auth/src/routeTree.gen.tse2e/vue-start/basic-cloudflare/src/routeTree.gen.ts
🧬 Code graph analysis (35)
e2e/vue-start/basic-cloudflare/src/routes/static.tsx (1)
e2e/vue-start/basic-cloudflare/worker-configuration.d.ts (1)
env(9629-9629)
e2e/vue-start/basic-cloudflare/src/router.tsx (2)
e2e/vue-start/basic-cloudflare/src/components/DefaultCatchBoundary.tsx (1)
DefaultCatchBoundary(10-53)e2e/vue-start/basic-cloudflare/src/components/NotFound.tsx (1)
NotFound(3-25)
e2e/vue-start/basic-auth/src/router.tsx (4)
e2e/vue-start/basic-auth/src/components/DefaultCatchBoundary.tsx (1)
DefaultCatchBoundary(10-53)e2e/vue-start/basic-auth/src/components/NotFound.tsx (1)
NotFound(3-25)e2e/vue-start/scroll-restoration/src/router.tsx (1)
getRouter(6-16)e2e/react-start/basic-cloudflare/src/router.tsx (1)
getRouter(6-16)
e2e/vue-start/basic-auth/src/utils/seo.ts (5)
examples/solid/start-basic-netlify/src/utils/seo.ts (1)
title(1-33)examples/solid/start-basic-nitro/src/utils/seo.ts (1)
title(1-33)e2e/vue-start/website/src/utils/seo.ts (1)
title(1-33)examples/react/start-i18n-paraglide/src/utils/seo.ts (1)
title(1-33)examples/solid/start-basic-cloudflare/src/utils/seo.ts (1)
title(1-33)
e2e/vue-start/basic-auth/src/components/Auth.tsx (1)
e2e/react-start/basic-auth/src/components/Auth.tsx (1)
Auth(1-57)
e2e/vue-start/basic-cloudflare/src/utils/seo.ts (1)
scripts/llms-generate.mjs (1)
title(101-101)
e2e/vue-start/basic-auth/src/utils/prisma.ts (2)
e2e/vue-start/basic-auth/src/prisma-generated/client.ts (2)
PrismaClient(37-37)PrismaClient(38-44)e2e/vue-start/basic-auth/src/prisma-generated/internal/class.ts (1)
PrismaClient(105-238)
e2e/vue-start/basic-auth/src/routes/__root.tsx (4)
e2e/vue-start/basic-auth/src/utils/session.ts (1)
useAppSession(9-13)e2e/vue-start/basic-auth/src/utils/seo.ts (1)
seo(1-33)e2e/vue-start/basic-auth/src/components/DefaultCatchBoundary.tsx (1)
DefaultCatchBoundary(10-53)e2e/vue-start/basic-auth/src/components/NotFound.tsx (1)
NotFound(3-25)
e2e/vue-start/basic-auth/src/components/Login.tsx (4)
e2e/vue-start/basic-auth/src/routes/_authed.tsx (1)
loginFn(8-46)e2e/vue-start/basic-auth/src/routes/signup.tsx (1)
signupFn(10-67)e2e/vue-start/basic-auth/src/hooks/useMutation.ts (1)
useMutation(3-40)e2e/vue-start/basic-auth/src/components/Auth.tsx (1)
Auth(3-65)
e2e/vue-start/basic-auth/src/components/DefaultCatchBoundary.tsx (5)
e2e/vue-start/website/src/components/DefaultCatchBoundary.tsx (2)
DefaultCatchBoundary(10-53)e(42-45)e2e/vue-start/custom-basepath/src/components/DefaultCatchBoundary.tsx (1)
DefaultCatchBoundary(10-53)e2e/vue-start/server-routes/src/components/DefaultCatchBoundary.tsx (1)
DefaultCatchBoundary(10-53)e2e/vue-start/server-functions/src/components/DefaultCatchBoundary.tsx (1)
DefaultCatchBoundary(10-53)e2e/vue-start/scroll-restoration/src/components/DefaultCatchBoundary.tsx (1)
DefaultCatchBoundary(10-53)
e2e/vue-start/basic-auth/src/utils/session.ts (3)
e2e/vue-start/basic-auth/src/prisma-generated/browser.ts (1)
User(23-23)e2e/vue-start/basic-auth/src/prisma-generated/client.ts (1)
User(51-51)packages/start-server-core/src/request-response.ts (1)
useSession(274-279)
e2e/vue-start/basic-auth/src/prisma-generated/commonInputTypes.ts (2)
e2e/solid-start/basic-auth/src/prisma-generated/commonInputTypes.ts (5)
StringFilter(15-27)NestedStringFilter(46-58)StringWithAggregatesFilter(29-44)NestedStringWithAggregatesFilter(60-75)NestedIntFilter(77-86)e2e/solid-start/basic-auth/src/prisma-generated/internal/prismaNamespace.ts (2)
StringFieldRefInput(575-578)IntFieldRefInput(583-586)
e2e/vue-start/basic-auth/src/components/NotFound.tsx (5)
e2e/vue-start/custom-basepath/src/components/NotFound.tsx (1)
NotFound(3-25)e2e/vue-start/server-routes/src/components/NotFound.tsx (1)
NotFound(3-25)e2e/vue-start/basic-vue-query/src/components/NotFound.tsx (1)
NotFound(3-25)e2e/vue-start/website/src/components/NotFound.tsx (1)
NotFound(3-25)e2e/vue-start/server-functions/src/components/NotFound.tsx (1)
NotFound(3-25)
e2e/vue-start/basic-auth/src/routeTree.gen.ts (1)
e2e/vue-start/basic-auth/src/router.tsx (1)
getRouter(6-16)
e2e/vue-start/basic-auth/src/routes/index.tsx (8)
e2e/vue-start/basic-auth/src/routes/_authed/posts.tsx (1)
Route(35-38)e2e/vue-start/basic-auth/src/routes/_authed.tsx (1)
Route(48-61)e2e/vue-start/basic-auth/src/routes/__root.tsx (1)
Route(33-83)e2e/vue-start/basic-auth/src/routes/_authed/posts.$postId.tsx (1)
Route(11-18)e2e/vue-start/basic-auth/src/routes/signup.tsx (1)
Route(106-108)e2e/vue-start/basic-auth/src/routes/_authed/posts.index.tsx (1)
Route(7-9)e2e/vue-start/basic-auth/src/routes/login.tsx (1)
Route(4-6)e2e/vue-start/basic-auth/src/routes/logout.tsx (1)
Route(16-19)
e2e/vue-start/basic-cloudflare/src/routes/__root.tsx (6)
e2e/vue-start/basic-cloudflare/src/routes/index.tsx (1)
Route(5-8)e2e/vue-start/basic-cloudflare/src/routes/static.tsx (1)
Route(5-8)e2e/vue-start/basic-cloudflare/src/utils/seo.ts (1)
seo(1-33)e2e/vue-start/basic-cloudflare/src/components/DefaultCatchBoundary.tsx (1)
DefaultCatchBoundary(10-53)e2e/vue-start/basic-cloudflare/src/components/NotFound.tsx (1)
NotFound(3-25)e2e/vue-start/website/src/routes/__root.tsx (1)
RootComponent(60-73)
e2e/vue-start/basic-cloudflare/tests/setup/global.teardown.ts (2)
e2e/vue-router/basic-virtual-named-export-config-file-based/tests/setup/global.teardown.ts (1)
teardown(4-6)e2e/vue-router/basic-vue-query-file-based/tests/setup/global.teardown.ts (1)
teardown(4-6)
e2e/solid-start/basic-auth/tests/mock-db-setup.test.ts (1)
e2e/solid-start/basic-auth/src/utils/prisma.ts (2)
prismaClient(8-8)hashPassword(10-20)
e2e/vue-start/basic-auth/src/routes/signup.tsx (4)
e2e/vue-start/basic-auth/src/utils/prisma.ts (2)
prismaClient(8-8)hashPassword(10-20)e2e/vue-start/basic-auth/src/utils/session.ts (1)
useAppSession(9-13)e2e/vue-start/basic-auth/src/hooks/useMutation.ts (1)
useMutation(3-40)e2e/vue-start/basic-auth/src/components/Auth.tsx (1)
Auth(3-65)
e2e/vue-start/basic-cloudflare/src/components/DefaultCatchBoundary.tsx (2)
e2e/vue-start/website/src/components/DefaultCatchBoundary.tsx (2)
DefaultCatchBoundary(10-53)e(42-45)e2e/vue-start/server-routes/src/components/DefaultCatchBoundary.tsx (1)
DefaultCatchBoundary(10-53)
e2e/vue-start/basic-auth/src/prisma-generated/client.ts (4)
e2e/vue-start/basic-auth/src/prisma-generated/internal/class.ts (1)
PrismaClient(105-238)e2e/vue-start/basic-auth/src/prisma-generated/browser.ts (2)
Prisma(16-16)User(23-23)e2e/vue-start/basic-auth/src/prisma-generated/internal/prismaNamespace.ts (2)
LogLevel(679-679)PrismaClientOptions(603-673)e2e/vue-start/basic-auth/src/prisma-generated/models/User.ts (1)
UserModel(18-19)
e2e/vue-start/basic-auth/src/prisma-generated/internal/class.ts (3)
e2e/vue-start/basic-auth/src/prisma-generated/client.ts (3)
Prisma(45-45)PrismaClient(37-37)PrismaClient(38-44)e2e/vue-start/basic-auth/src/prisma-generated/internal/prismaNamespace.ts (6)
PrismaClientOptions(603-673)LogLevel(679-679)LogDefinition(680-683)GetEvents(691-692)TransactionIsolationLevel(546-548)TransactionIsolationLevel(550-551)e2e/vue-start/basic-auth/src/prisma-generated/internal/prismaNamespaceBrowser.ts (2)
TransactionIsolationLevel(66-68)TransactionIsolationLevel(70-71)
e2e/solid-start/basic-auth/src/components/Login.tsx (3)
e2e/solid-start/basic-auth/src/routes/_authed.tsx (1)
loginFn(8-46)examples/solid/start-basic-auth/src/routes/_authed.tsx (1)
loginFn(7-43)e2e/solid-start/basic-auth/src/hooks/useMutation.ts (1)
useMutation(3-41)
e2e/vue-start/basic-auth/src/routes/_authed/posts.$postId.tsx (3)
e2e/vue-start/basic-auth/src/routes/_authed.tsx (1)
Route(48-61)e2e/vue-start/basic-auth/src/utils/posts.ts (1)
fetchPost(11-27)e2e/vue-start/basic-auth/src/components/NotFound.tsx (1)
NotFound(3-25)
e2e/vue-start/basic-cloudflare/src/routes/index.tsx (2)
e2e/vue-start/basic-cloudflare/src/routes/static.tsx (1)
Route(5-8)e2e/vue-start/basic-cloudflare/worker-configuration.d.ts (1)
env(9629-9629)
e2e/vue-start/basic-auth/src/prisma-generated/browser.ts (2)
e2e/vue-start/basic-auth/src/prisma-generated/client.ts (2)
User(51-51)Prisma(45-45)e2e/vue-start/basic-auth/src/prisma-generated/models/User.ts (1)
UserModel(18-19)
e2e/vue-start/basic-auth/tests/mock-db-teardown.test.ts (1)
e2e/vue-start/basic-auth/src/utils/prisma.ts (2)
prismaClient(8-8)hashPassword(10-20)
e2e/vue-start/basic-auth/src/routes/logout.tsx (9)
e2e/vue-start/basic-auth/src/utils/session.ts (1)
useAppSession(9-13)e2e/vue-start/basic-auth/src/routes/_authed/posts.tsx (1)
Route(35-38)e2e/vue-start/basic-auth/src/routes/_authed.tsx (1)
Route(48-61)e2e/vue-start/basic-auth/src/routes/__root.tsx (1)
Route(33-83)e2e/vue-start/basic-auth/src/routes/_authed/posts.$postId.tsx (1)
Route(11-18)e2e/vue-start/basic-auth/src/routes/signup.tsx (1)
Route(106-108)e2e/vue-start/basic-auth/src/routes/_authed/posts.index.tsx (1)
Route(7-9)e2e/vue-start/basic-auth/src/routes/index.tsx (1)
Route(3-5)e2e/vue-start/basic-auth/src/routes/login.tsx (1)
Route(4-6)
e2e/vue-start/basic-cloudflare/src/components/NotFound.tsx (4)
e2e/vue-start/server-routes/src/components/NotFound.tsx (1)
NotFound(3-25)e2e/vue-start/website/src/components/NotFound.tsx (1)
NotFound(3-25)e2e/vue-start/scroll-restoration/src/components/NotFound.tsx (1)
NotFound(3-25)e2e/vue-start/server-functions/src/components/NotFound.tsx (1)
NotFound(3-25)
e2e/vue-start/basic-auth/src/routes/_authed/posts.tsx (9)
e2e/vue-start/basic-auth/src/routes/_authed.tsx (1)
Route(48-61)e2e/vue-start/basic-auth/src/routes/__root.tsx (1)
Route(33-83)e2e/vue-start/basic-auth/src/routes/_authed/posts.$postId.tsx (1)
Route(11-18)e2e/vue-start/basic-auth/src/routes/signup.tsx (1)
Route(106-108)e2e/vue-start/basic-auth/src/routes/_authed/posts.index.tsx (1)
Route(7-9)e2e/vue-start/basic-auth/src/routes/index.tsx (1)
Route(3-5)e2e/vue-start/basic-auth/src/routes/login.tsx (1)
Route(4-6)e2e/vue-start/basic-auth/src/routes/logout.tsx (1)
Route(16-19)e2e/vue-start/basic-auth/src/utils/posts.ts (1)
fetchPosts(29-37)
e2e/vue-start/basic-cloudflare/src/routeTree.gen.ts (1)
e2e/vue-start/basic-cloudflare/src/router.tsx (1)
getRouter(6-16)
e2e/vue-start/basic-auth/tests/mock-db-setup.test.ts (1)
e2e/vue-start/basic-auth/src/utils/prisma.ts (2)
prismaClient(8-8)hashPassword(10-20)
e2e/vue-start/basic-auth/src/routes/login.tsx (3)
e2e/vue-start/basic-auth/src/routes/signup.tsx (1)
Route(106-108)e2e/vue-start/basic-auth/src/routes/index.tsx (1)
Route(3-5)e2e/vue-start/basic-auth/src/components/Login.tsx (1)
Login(9-79)
e2e/vue-start/basic-auth/src/prisma-generated/internal/prismaNamespace.ts (1)
e2e/vue-start/basic-auth/src/prisma-generated/internal/class.ts (1)
PrismaClient(105-238)
e2e/vue-start/basic-auth/src/prisma-generated/models/User.ts (3)
e2e/vue-start/basic-auth/src/prisma-generated/internal/prismaNamespace.ts (7)
GetScalarType(359-363)UserScalarFieldEnum(553-556)UserScalarFieldEnum(558-559)SortOrder(561-564)SortOrder(566-566)Or(346-355)FieldRef(408-408)e2e/vue-start/basic-auth/src/prisma-generated/internal/prismaNamespaceBrowser.ts (4)
UserScalarFieldEnum(73-76)UserScalarFieldEnum(78-79)SortOrder(81-84)SortOrder(86-86)e2e/vue-start/basic-auth/src/prisma-generated/commonInputTypes.ts (2)
StringFilter(15-27)StringWithAggregatesFilter(29-44)
🪛 dotenv-linter (4.0.0)
e2e/vue-start/basic-auth/.env
[warning] 7-7: [EndingBlankLine] No blank line at the end of the file
(EndingBlankLine)
[warning] 7-7: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Test
| teardown('create new database', async () => { | ||
| if ( | ||
| await prismaClient.user.findUnique({ | ||
| where: { | ||
| email: 'test2@gmail.com', | ||
| }, | ||
| }) | ||
| ) { | ||
| await prismaClient.user.delete({ | ||
| where: { | ||
| email: 'test2@gmail.com', | ||
| }, | ||
| }) | ||
| } | ||
| await prismaClient.user.deleteMany() | ||
|
|
||
| const email = 'test@gmail.com' | ||
| const password = await hashPassword('test') | ||
| await prismaClient.user.create({ | ||
| data: { | ||
| email, | ||
| password, | ||
| }, | ||
| }) | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test description is misleading.
The teardown test is named "create new database" but it's performing cleanup operations. While the logic (deleting all users and recreating the test user) may be intentional to reset to a known state, the test name should reflect its teardown purpose more accurately.
🔎 Consider renaming the test:
-teardown('create new database', async () => {
+teardown('reset database to initial state', async () => {
await prismaClient.user.deleteMany()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| teardown('create new database', async () => { | |
| if ( | |
| await prismaClient.user.findUnique({ | |
| where: { | |
| email: 'test2@gmail.com', | |
| }, | |
| }) | |
| ) { | |
| await prismaClient.user.delete({ | |
| where: { | |
| email: 'test2@gmail.com', | |
| }, | |
| }) | |
| } | |
| await prismaClient.user.deleteMany() | |
| const email = 'test@gmail.com' | |
| const password = await hashPassword('test') | |
| await prismaClient.user.create({ | |
| data: { | |
| email, | |
| password, | |
| }, | |
| }) | |
| }) | |
| teardown('reset database to initial state', async () => { | |
| await prismaClient.user.deleteMany() | |
| const email = 'test@gmail.com' | |
| const password = await hashPassword('test') | |
| await prismaClient.user.create({ | |
| data: { | |
| email, | |
| password, | |
| }, | |
| }) | |
| }) |
🤖 Prompt for AI Agents
In e2e/solid-start/basic-auth/tests/mock-db-teardown.test.ts around lines 5 to
16, the test title "create new database" is misleading because the block
performs teardown/cleanup (deleting users and recreating a test user); rename
the test to reflect its teardown purpose (for example "reset test database" or
"teardown: reset users to known state") so the name matches the actions, and
update any related comments or test suite descriptions accordingly.
| datasource db { | ||
| provider = "sqlite" | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing required url field in datasource configuration.
The datasource db block is missing the required url field. Prisma needs this to know where to connect to the database. Without it, the Prisma client will fail to initialize at runtime.
🔎 Add the url field to fix this issue:
datasource db {
provider = "sqlite"
+ url = env("DATABASE_URL")
}Alternatively, if you want a default fallback:
datasource db {
provider = "sqlite"
+ url = env("DATABASE_URL") || "file:./dev.db"
}🤖 Prompt for AI Agents
In e2e/vue-start/basic-auth/prisma/schema.prisma around lines 9 to 11, the
datasource db block is missing the required url field; add a url property
pointing to your SQLite file or environment variable (e.g., datasource db {
provider = "sqlite" url = env("DATABASE_URL") } or a direct file path like
"file:./dev.db") so Prisma can locate the database and initialize the client at
runtime.
| <button | ||
| type="button" | ||
| class="w-full bg-cyan-600 text-white rounded-sm py-2 font-black uppercase" | ||
| disabled={status === 'pending'} | ||
| onClick={(event) => { | ||
| const form = (event.currentTarget as HTMLButtonElement).form | ||
| if (form) { | ||
| onSubmit(form) | ||
| } | ||
| }} | ||
| > | ||
| {status === 'pending' ? '...' : actionText} | ||
| </button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use type="submit" for better form UX.
The button is set to type="button" and uses a manual onClick handler to submit the form. This breaks native form behavior:
- Enter key in form fields won't trigger submission
- Native HTML5 form validation won't run
- Non-standard form submission pattern
The form already has an onSubmit handler (lines 19-22) that properly prevents default and calls onSubmit. Remove the button's onClick and change its type to "submit".
🔎 Apply this diff to use standard form submission:
<button
- type="button"
+ type="submit"
class="w-full bg-cyan-600 text-white rounded-sm py-2 font-black uppercase"
disabled={status === 'pending'}
- onClick={(event) => {
- const form = (event.currentTarget as HTMLButtonElement).form
- if (form) {
- onSubmit(form)
- }
- }}
>
{status === 'pending' ? '...' : actionText}
</button>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <button | |
| type="button" | |
| class="w-full bg-cyan-600 text-white rounded-sm py-2 font-black uppercase" | |
| disabled={status === 'pending'} | |
| onClick={(event) => { | |
| const form = (event.currentTarget as HTMLButtonElement).form | |
| if (form) { | |
| onSubmit(form) | |
| } | |
| }} | |
| > | |
| {status === 'pending' ? '...' : actionText} | |
| </button> | |
| <button | |
| type="submit" | |
| class="w-full bg-cyan-600 text-white rounded-sm py-2 font-black uppercase" | |
| disabled={status === 'pending'} | |
| > | |
| {status === 'pending' ? '...' : actionText} | |
| </button> |
🤖 Prompt for AI Agents
In e2e/vue-start/basic-auth/src/components/Auth.tsx around lines 47 to 59, the
submit button is declared as type="button" and manually calls onSubmit in an
onClick handler, which prevents native form behavior; change the button to
type="submit", remove the onClick handler entirely, and keep the
disabled={status === 'pending'} and inner text logic so the form's existing
onSubmit handler (lines 19-22) handles submission, enabling Enter-key submission
and native HTML5 validation.
| loginMutation.mutate({ | ||
| data: { | ||
| email: formData.get('email') as string, | ||
| password: formData.get('password') as string, | ||
| }, | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Fix the mutation payload structure.
The mutation is passing { data: { email, password } }, but the loginFn in _authed.tsx expects { email, password } directly (line 11 of _authed.tsx shows the inputValidator expects { email: string; password: string }). This wrapper will cause the server function to fail at runtime.
🔎 Apply this diff to fix the payload structure:
- loginMutation.mutate({
- data: {
- email: formData.get('email') as string,
- password: formData.get('password') as string,
- },
- })
+ loginMutation.mutate({
+ email: formData.get('email') as string,
+ password: formData.get('password') as string,
+ })📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| loginMutation.mutate({ | |
| data: { | |
| email: formData.get('email') as string, | |
| password: formData.get('password') as string, | |
| }, | |
| }) | |
| loginMutation.mutate({ | |
| email: formData.get('email') as string, | |
| password: formData.get('password') as string, | |
| }) |
🤖 Prompt for AI Agents
In e2e/vue-start/basic-auth/src/components/Login.tsx around lines 38 to 43, the
mutation is sending an object shaped as { data: { email, password } } but the
server-side loginFn/_authed.tsx expects { email, password } directly; remove the
extra data wrapper and call loginMutation.mutate with an object containing email
and password at the top level (ensure values are cast to string as before) so
the payload matches the inputValidator signature.
| onClick={(e) => { | ||
| const formData = new FormData( | ||
| (e.target as HTMLButtonElement).form!, | ||
| ) | ||
|
|
||
| signupMutation.mutate({ | ||
| data: { | ||
| email: formData.get('email') as string, | ||
| password: formData.get('password') as string, | ||
| }, | ||
| }) | ||
| }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Fix the signup mutation payload structure.
Same issue as the login mutation: the payload is wrapped in { data: { ... } } but signupFn expects { email, password, redirectUrl? } directly (line 14 of signup.tsx shows the inputValidator signature).
🔎 Apply this diff to fix the payload structure:
onClick={(e) => {
const formData = new FormData(
(e.target as HTMLButtonElement).form!,
)
signupMutation.mutate({
- data: {
- email: formData.get('email') as string,
- password: formData.get('password') as string,
- },
+ email: formData.get('email') as string,
+ password: formData.get('password') as string,
})
}}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| onClick={(e) => { | |
| const formData = new FormData( | |
| (e.target as HTMLButtonElement).form!, | |
| ) | |
| signupMutation.mutate({ | |
| data: { | |
| email: formData.get('email') as string, | |
| password: formData.get('password') as string, | |
| }, | |
| }) | |
| }} | |
| onClick={(e) => { | |
| const formData = new FormData( | |
| (e.target as HTMLButtonElement).form!, | |
| ) | |
| signupMutation.mutate({ | |
| email: formData.get('email') as string, | |
| password: formData.get('password') as string, | |
| }) | |
| }} |
🤖 Prompt for AI Agents
In e2e/vue-start/basic-auth/src/components/Login.tsx around lines 55 to 66, the
signup mutation payload is incorrectly wrapped as { data: { email, password } }
but signupFn expects the plain shape { email, password, redirectUrl? }; change
the mutate call to pass the fields directly (e.g., signupMutation.mutate({
email: formData.get('email') as string, password: formData.get('password') as
string })) and include redirectUrl only if needed by your flow.
| export function hashPassword(password: string) { | ||
| return new Promise<string>((resolve, reject) => { | ||
| crypto.pbkdf2(password, 'salt', 100000, 64, 'sha256', (err, derivedKey) => { | ||
| if (err) { | ||
| reject(err) | ||
| } else { | ||
| resolve(derivedKey.toString('hex')) | ||
| } | ||
| }) | ||
| }) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed salt is acceptable for e2e tests, but dangerous if reused in production.
Line 12 uses a hard-coded salt 'salt' in the password hashing function. While this is acceptable for deterministic e2e test scenarios, using a fixed salt in production would be a critical security vulnerability (all passwords would share the same salt, making rainbow table attacks trivial).
Since this is test code, this is acceptable, but ensure this utility is never copied to production code.
🤖 Prompt for AI Agents
In e2e/vue-start/basic-auth/src/utils/prisma.ts around lines 10 to 20, the
password hashing currently uses a hard-coded salt ('salt'); replace this with a
per-password salt generated via crypto.randomBytes (e.g., 16 bytes) and
incorporate that salt into the stored output (for example store salt and hex
hash together or return an object {salt,hash}), or alternatively change the
function to accept an explicit salt parameter so callers can supply one; also
add a clear comment that the helper is for e2e only and must not be copied into
production code.
| "dependencies": { | ||
| "@tanstack/vue-router": "workspace:^", | ||
| "@tanstack/vue-router-devtools": "workspace:^", | ||
| "@tanstack/vue-start": "workspace:^", | ||
| "vue": "^3.5.25" | ||
| }, | ||
| "devDependencies": { | ||
| "@cloudflare/vite-plugin": "^1.15.1", | ||
| "@playwright/test": "^1.50.1", | ||
| "@tailwindcss/postcss": "^4.1.15", | ||
| "@tanstack/router-e2e-utils": "workspace:^", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check workspace protocol usage across e2e packages
echo "=== Checking workspace:* usage in e2e packages ==="
rg 'workspace:\*' e2e/ --include='*.json' | wc -l
echo "---"
echo "=== Checking workspace:^ usage in e2e packages ==="
rg 'workspace:\^' e2e/ --include='*.json' | wc -l
echo "---"
echo "=== Sample of workspace:^ in e2e packages ==="
rg -n 'workspace:\^' e2e/ --include='*.json' | head -10Repository: TanStack/router
Length of output: 1561
🏁 Script executed:
#!/bin/bash
# Check workspace protocol usage across e2e packages
echo "=== Checking workspace:* usage in e2e packages ==="
rg 'workspace:\*' -g '*.json' e2e/ | wc -l
echo "---"
echo "=== Checking workspace:^ usage in e2e packages ==="
rg 'workspace:\^' -g '*.json' e2e/ | wc -l
echo "---"
echo "=== Sample of workspace:^ in e2e packages ==="
rg -n 'workspace:\^' -g '*.json' e2e/ | head -20
echo "---"
echo "=== Sample of workspace:* in e2e packages (if any) ==="
rg -n 'workspace:\*' -g '*.json' e2e/ | head -20Repository: TanStack/router
Length of output: 2054
🏁 Script executed:
#!/bin/bash
# Check workspace protocol usage across entire repo
echo "=== All workspace:* usage in repo ==="
rg 'workspace:\*' -g '*.json' | wc -l
echo "---"
echo "=== All workspace:^ usage in repo ==="
rg 'workspace:\^' -g '*.json' | wc -l
echo "---"
echo "=== Non-e2e packages sample (workspace:^) ==="
rg -n 'workspace:\^' -g '*.json' --max-count=20 | grep -v '^e2e/'Repository: TanStack/router
Length of output: 1297
Refactor to use workspace:* per coding guidelines or update guidelines accordingly.
Internal dependencies use workspace:^ throughout the monorepo (427 instances across all packages), but the coding guidelines specify workspace:*. Either the guideline requires updating to reflect the intended workspace:^ pattern, or all package.json files including this one should be refactored to use workspace:*.
🤖 Prompt for AI Agents
In e2e/vue-start/basic-cloudflare/package.json around lines 15 to 25, internal
workspace dependencies are using the caret form "workspace:^" but the repo
coding guidelines require "workspace:*"; update the internal dependency
specifiers (e.g., "@tanstack/vue-router", "@tanstack/vue-router-devtools",
"@tanstack/vue-start", "@tanstack/router-e2e-utils") to use "workspace:*"
instead of "workspace:^" so the package.json conforms to the guidelines, or if
the intended convention is to keep the caret form then raise a docs change
instead of modifying files.
| onClick={(e) => { | ||
| e.preventDefault() | ||
| window.history.back() | ||
| }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Add type annotation for the event parameter.
The onClick event handler's parameter lacks a type annotation. For TypeScript strict mode compliance, explicitly type it as MouseEvent.
🔎 Apply this diff to add the type:
- onClick={(e) => {
+ onClick={(e: MouseEvent) => {
e.preventDefault()
window.history.back()
}}As per coding guidelines, TypeScript strict mode with extensive type safety should be used for all code.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| onClick={(e) => { | |
| e.preventDefault() | |
| window.history.back() | |
| }} | |
| onClick={(e: MouseEvent) => { | |
| e.preventDefault() | |
| window.history.back() | |
| }} |
🤖 Prompt for AI Agents
e2e/vue-start/basic-cloudflare/src/components/DefaultCatchBoundary.tsx lines
42-45: the onClick handler parameter needs an explicit type for TypeScript
strict mode; change the handler signature to accept a typed event (e:
React.MouseEvent) or more specific (e:
React.MouseEvent<HTMLAnchorElement|HTMLButtonElement>), and ensure you import
the type from React (either import React from 'react' or import type {
MouseEvent } from 'react' and use it as the parameter type) so
e.preventDefault() is type-checked.
| export const Route = createRootRoute({ | ||
| head: () => ({ | ||
| meta: [ | ||
| { | ||
| charSet: 'utf-8', | ||
| }, | ||
| { | ||
| name: 'viewport', | ||
| content: 'width=device-width, initial-scale=1', | ||
| }, | ||
| ...seo({ | ||
| title: | ||
| 'TanStack Start | Type-Safe, Client-First, Full-Stack Vue Framework', | ||
| description: `TanStack Start is a type-safe, client-first, full-stack Vue framework.`, | ||
| }), | ||
| ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent property name: use charset instead of charSet.
Line 21 uses charSet, but the related file e2e/vue-start/basic-auth/src/routes/__root.tsx (line 21 from relevant code snippets) uses charset. This inconsistency may cause the charset meta tag to not render correctly.
🔎 Apply this diff to use the correct property name:
meta: [
{
- charSet: 'utf-8',
+ charset: 'utf-8',
},
{
name: 'viewport',📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const Route = createRootRoute({ | |
| head: () => ({ | |
| meta: [ | |
| { | |
| charSet: 'utf-8', | |
| }, | |
| { | |
| name: 'viewport', | |
| content: 'width=device-width, initial-scale=1', | |
| }, | |
| ...seo({ | |
| title: | |
| 'TanStack Start | Type-Safe, Client-First, Full-Stack Vue Framework', | |
| description: `TanStack Start is a type-safe, client-first, full-stack Vue framework.`, | |
| }), | |
| ], | |
| export const Route = createRootRoute({ | |
| head: () => ({ | |
| meta: [ | |
| { | |
| charset: 'utf-8', | |
| }, | |
| { | |
| name: 'viewport', | |
| content: 'width=device-width, initial-scale=1', | |
| }, | |
| ...seo({ | |
| title: | |
| 'TanStack Start | Type-Safe, Client-First, Full-Stack Vue Framework', | |
| description: `TanStack Start is a type-safe, client-first, full-stack Vue framework.`, | |
| }), | |
| ], |
🤖 Prompt for AI Agents
In e2e/vue-start/basic-cloudflare/src/routes/__root.tsx around lines 17 to 32,
the meta object uses the property name "charSet" which should be "charset" to
match the other route file and ensure the charset meta tag renders correctly;
update the property key from "charSet" to "charset" in that meta entry so it
matches the expected attribute name.
| sizes: '16x16', | ||
| href: '/favicon-16x16.png', | ||
| }, | ||
| { rel: 'manifest', href: '/site.webmanifest', color: '#fffff' }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix invalid hex color in manifest link.
The color value '#fffff' is invalid (5 hex digits instead of 6). This should be '#ffffff' for white or another valid 6-digit hex color.
🔎 Apply this diff to fix the color value:
- { rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
+ { rel: 'manifest', href: '/site.webmanifest', color: '#ffffff' },📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| { rel: 'manifest', href: '/site.webmanifest', color: '#fffff' }, | |
| { rel: 'manifest', href: '/site.webmanifest', color: '#ffffff' }, |
🤖 Prompt for AI Agents
In e2e/vue-start/basic-cloudflare/src/routes/__root.tsx around line 52, the
manifest link's color prop uses an invalid 5-digit hex '#fffff'; update it to a
valid 6-digit hex (e.g. '#ffffff' for white) so the color value is a proper
6-character hex string.
Summary by CodeRabbit
New Features
Bug Fixes & Updates
Configuration
✏️ Tip: You can customize this high-level summary in your review settings.