diff --git a/jest.config.js b/jest.config.js index 7918ae192..b5ce151d5 100644 --- a/jest.config.js +++ b/jest.config.js @@ -21,7 +21,7 @@ const customJestConfig = { ], moduleDirectories: ['node_modules', '/'], transformIgnorePatterns: [ - '/node_modules/(?!(@auth|next-auth|next-intl|use-intl)/)', + '/node_modules/(?!(@auth|next-auth|next-intl|use-intl|cookie)/)', ], moduleNameMapper: { '^@/(.*)$': '/src/$1', @@ -40,4 +40,17 @@ const customJestConfig = { } // createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async -module.exports = createJestConfig(customJestConfig) +const buildConfig = createJestConfig(customJestConfig) + +// next/jest PREPENDS its own transformIgnorePatterns, and patterns are OR'd — +// if any one matches, the file is never transformed. So an allowlist entry in +// customJestConfig above cannot rescue an ESM-only package on its own; the +// package must also be injected into next/jest's generated allowlist here. +// cookie v2 is pure ESM ("type": "module") and is imported by src/lib/auth. +module.exports = async () => { + const config = await buildConfig() + config.transformIgnorePatterns = config.transformIgnorePatterns.map((pattern) => + pattern.includes('(?!(next-auth|') ? pattern.replace('(?!(next-auth|', '(?!(cookie|next-auth|') : pattern + ) + return config +} diff --git a/package-lock.json b/package-lock.json index 50297c207..3a26acefb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "bcryptjs": "^2.4.3", "busboy": "^1.6.0", "clsx": "^2.1.1", - "cookie": "^1.0.2", + "cookie": "^2.0.1", "cron-parser": "^5.5.0", "csv-parse": "^7.0.2", "drizzle-orm": "^0.45.1", @@ -8736,12 +8736,12 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", - "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-2.0.1.tgz", + "integrity": "sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w==", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=22" }, "funding": { "type": "opencollective", diff --git a/package.json b/package.json index b26fb3504..15171626d 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "bcryptjs": "^2.4.3", "busboy": "^1.6.0", "clsx": "^2.1.1", - "cookie": "^1.0.2", + "cookie": "^2.0.1", "cron-parser": "^5.5.0", "csv-parse": "^7.0.2", "drizzle-orm": "^0.45.1", diff --git a/src/lib/auth/csrf.ts b/src/lib/auth/csrf.ts index 5d412ed72..2b8f50c4c 100644 --- a/src/lib/auth/csrf.ts +++ b/src/lib/auth/csrf.ts @@ -12,7 +12,9 @@ */ import { NextRequest, NextResponse } from 'next/server' -import { serialize, parse } from 'cookie' +// cookie v2 renamed the exports: serialize → stringifySetCookie (now taking +// {name, value, ...options} as one object), parse → parseCookie. +import { stringifySetCookie, parseCookie } from 'cookie' // ============================================================================= // Edge-compatible crypto utilities (Web Crypto API) @@ -103,7 +105,9 @@ export async function validateCsrfToken(token: string, hash: string): Promise