-
-
Notifications
You must be signed in to change notification settings - Fork 35
[almost done] Next.js 15 support #969
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
base: canary
Are you sure you want to change the base?
Conversation
|
WalkthroughThis set of changes restructures the codebase by removing deprecated or redundant packages, files, and configurations, especially those related to classic cache handling and server modules. The cache handler logic is refactored for improved type safety, modularity, and ES module compatibility. New utilities and configurations are introduced for TypeScript, ESLint, and Vitest. Redis and LRU cache handlers are modernized, and tests are updated or replaced. Several documentation and configuration files are updated or deleted to align with the new project structure. Changes
Sequence Diagram(s)sequenceDiagram
participant App
participant CacheHandler
participant LRUHandler
participant RedisHandler
participant RemoteStore
participant RedisClient
App->>CacheHandler: get(key, ctx)
CacheHandler->>LRUHandler: get(key, {implicitTags})
LRUHandler-->>CacheHandler: value/null
CacheHandler->>RedisHandler: get(key, {implicitTags})
RedisHandler-->>CacheHandler: value/null
CacheHandler-->>App: value/null
App->>CacheHandler: set(key, value, ctx)
CacheHandler->>LRUHandler: set(key, value)
LRUHandler-->>CacheHandler: ack
CacheHandler->>RedisHandler: set(key, value)
RedisHandler-->>CacheHandler: ack
CacheHandler-->>App: ack
App->>CacheHandler: revalidateTag(tag)
CacheHandler->>LRUHandler: revalidateTag(tag)
LRUHandler-->>CacheHandler: ack
CacheHandler->>RedisHandler: revalidateTag(tag)
RedisHandler-->>CacheHandler: ack
CacheHandler-->>App: ack
App->>RemoteStore: get(cacheKey)
RemoteStore->>RedisClient: get(key) with timeout
RedisClient-->>RemoteStore: value/null
RemoteStore-->>App: value/null
App->>RemoteStore: set(cacheKey, entry)
RemoteStore->>RedisClient: set(key, value) with timeout
RedisClient-->>RemoteStore: ack
RemoteStore-->>App: ack
App->>RemoteStore: expireTags(tags)
RemoteStore->>RedisClient: publish expired tags
RedisClient-->>RemoteStore: ack
RemoteStore-->>App: ack
Note ⚡️ AI Code Reviews for VS Code, Cursor, WindsurfCodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback. Note ⚡️ Faster reviews with cachingCodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure ✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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: 1
🔭 Outside diff range comments (1)
apps/cache-testing/create-instances.ts (1)
36-55
: Enhance performance and robustness.The main execution flow could be improved in several ways:
- Parallelize independent operations
- Make port numbers configurable
- Add cleanup and validation
Consider this improved implementation:
+const PORTS = process.env.INSTANCE_PORTS?.split(',') ?? ['3000', '3001']; + +// Clean up existing directories +async function cleanup() { + try { + await rm(INSTANCES_DIR, { recursive: true, force: true }); + } catch (error) { + console.warn('Cleanup failed:', error); + } +} + +// Validate directory contents +async function validateDir(dir: string): Promise<boolean> { + try { + await access(dir); + return true; + } catch { + return false; + } +} + +// Main execution +await cleanup(); + // Copy public directory to standalone app directory -await copyDir(PUBLIC_DIR, path.join(APP_DIR, 'public')); +const copyTasks = [ + copyDir(PUBLIC_DIR, path.join(APP_DIR, 'public')), + copyDir(STATIC_DIR, path.join(APP_DIR, '.next/static')), +]; + +const results = await Promise.all(copyTasks); +if (results.some(result => result)) { + console.error('One or more copy operations failed'); + process.exit(1); +} -// Copy static directory to standalone app/.next directory -await copyDir(STATIC_DIR, path.join(APP_DIR, '.next/static')); // Create fetch cache directory and copy await mkdir(path.join(APP_DIR, '.next/cache/fetch-cache'), { recursive: true }); await copyDir(FETCH_CACHE_DIR, path.join(APP_DIR, '.next/cache/fetch-cache')); // Create instance directories -await createInstanceDir('3000'); -await createInstanceDir('3001'); +await Promise.all(PORTS.map(port => createInstanceDir(port))); // Copy files from standalone directory to instance directories -await copyDir(path.join(STANDALONE_DIR, '.'), path.join(INSTANCES_DIR, '3000')); -await copyDir(path.join(STANDALONE_DIR, '.'), path.join(INSTANCES_DIR, '3001')); +await Promise.all( + PORTS.map(port => + copyDir(path.join(STANDALONE_DIR, '.'), path.join(INSTANCES_DIR, port)) + ) +); + +// Validate final state +const validations = await Promise.all( + PORTS.map(port => validateDir(path.join(INSTANCES_DIR, port))) +); + +if (validations.some(valid => !valid)) { + console.error('One or more instance directories failed validation'); + process.exit(1); +}
🧹 Nitpick comments (1)
apps/cache-testing/create-instances.ts (1)
7-13
: Consider making paths configurable.The hardcoded paths could be made configurable through environment variables or a configuration file for better flexibility across different environments.
Example approach:
+import { config } from './config'; + // Set common paths -const STANDALONE_DIR = path.join(currentDir, '.next/standalone'); -const APP_DIR = path.join(STANDALONE_DIR, 'apps/cache-testing'); -const PUBLIC_DIR = path.join(currentDir, 'public'); -const STATIC_DIR = path.join(currentDir, '.next/static'); -const FETCH_CACHE_DIR = path.join(currentDir, '.next/cache/fetch-cache'); -const INSTANCES_DIR = path.join(currentDir, '.next/__instances'); +const STANDALONE_DIR = path.join(currentDir, config.paths.standalone ?? '.next/standalone'); +const APP_DIR = path.join(STANDALONE_DIR, config.paths.app ?? 'apps/cache-testing'); +const PUBLIC_DIR = path.join(currentDir, config.paths.public ?? 'public'); +const STATIC_DIR = path.join(currentDir, config.paths.static ?? '.next/static'); +const FETCH_CACHE_DIR = path.join(currentDir, config.paths.fetchCache ?? '.next/cache/fetch-cache'); +const INSTANCES_DIR = path.join(currentDir, config.paths.instances ?? '.next/__instances');
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/cache-testing/cache-handler-redis-stack.cjs
(2 hunks)apps/cache-testing/cache-handler-redis-stack.js
(2 hunks)apps/cache-testing/cluster.config.js
(1 hunks)apps/cache-testing/create-instances.sh
(0 hunks)apps/cache-testing/create-instances.ts
(1 hunks)apps/cache-testing/package.json
(1 hunks)
💤 Files with no reviewable changes (1)
- apps/cache-testing/create-instances.sh
✅ Files skipped from review due to trivial changes (1)
- apps/cache-testing/cluster.config.js
🔇 Additional comments (4)
apps/cache-testing/package.json (2)
6-6
: ES Module Declaration AddedThe addition of "type": "module" ensures that this package is now interpreted as an ECMAScript module. This change is crucial given the migration toward modern module syntax and should align well with the intended Next.js 15 support.
8-8
: Build Script Updated to Use TypeScript Instance SetupThe build script has been updated from invoking a shell script to using "tsx ./create-instances.ts" after "next build". This change reflects the shift to a TypeScript-based setup for instance creation. Please verify that the new create-instances.ts file is correctly implemented and located as specified.
apps/cache-testing/cache-handler-redis-stack.js (1)
3-6
: LGTM! Module syntax transition looks correct.The transition from CommonJS to ES modules is implemented correctly, with proper import statements and default export.
Let's verify the package compatibility with ES modules:
Also applies to: 89-89
✅ Verification successful
🌐 Web query:
Does @neshca/cache-handler support ES modules?
💡 Result:
Yes, `@neshca/cache-handler` supports ES Modules (ESM). The library added explicit support for ES Modules in patch version 0.6.6 through the change `ddf957f`[3][7]. This allows developers to use ESM syntax (`import/export`) when configuring their cache handlers rather than being restricted to CommonJS (`require/module.exports`). Key implementation details: 1. Configuration files can use `.mjs` extensions for ESM syntax[1] 2. Dynamic imports are supported in instrumentation files[1] 3. The library handles both ESM and CommonJS configurations interchangeably[1][3] Example ESM configuration from the documentation[1]: ```javascript // cache-handler.mjs import { CacheHandler } from '@neshca/cache-handler'; // ...ESM-style configuration export default CacheHandler; ``` The package maintains compatibility with both module systems while recommending ESM for new implementations[3][7]. When using Next.js versions 13.5.1+, developers can choose either module format based on their project configuration[1][4]. Citations: - 1: https://caching-tools.github.io/next-shared-cache/installation - 2: https://caching-tools.github.io/next-shared-cache/ - 3: https://classic.yarnpkg.com/en/package/@neshca/cache-handler - 4: https://dev.to/rafalsz/scaling-nextjs-with-redis-cache-handler-55lh - 5: https://github.com/fortedigital/nextjs-cache-handler/blob/master/README.md - 6: https://github.com/vercel/next.js/discussions/57040 - 7: https://github.com/caching-tools/next-shared-cache/blob/canary/packages/cache-handler/CHANGELOG.md - 8: https://npmpackage.info/package/@neshca/cache-handler - 9: https://www.npmjs.com/package/@neshca/cache-handler/v/0.4.3 - 10: https://www.npmjs.com/~caching-tools
Module Syntax Transition Verified and Compatible
The ES module transition in this file is correctly implemented. The import/export changes align with ES module standards, and the web query confirms that
@neshca/cache-handler
supports ES modules (since patch version 0.6.6).
- Import statements updated from CommonJS (
require
) to ES modules (import
) correctly.- The default export statement is properly converted.
- Package compatibility with ES modules has been verified via the web query.
apps/cache-testing/cache-handler-redis-stack.cjs (1)
3-6
: LGTM! CommonJS syntax transition looks correct.The CommonJS module syntax is implemented correctly, with proper handling of default exports using
.default
property access.Let's verify if this dual-module approach is necessary for Next.js 15:
Also applies to: 89-89
✅ Verification successful
🌐 Web query:
Does Next.js 15 require dual CommonJS and ES module support?
💡 Result:
Next.js 15 does not inherently require dual CommonJS/ES module support for all projects, but compatibility depends on your project's configuration and dependencies. Here's a breakdown of key considerations: ### Module Handling in Next.js 1. **Default Behavior** Next.js traditionally uses CommonJS (`require()`) for server-side configurations like `next.config.js`[3][7]. However: - You can enable ES modules (ESM) by setting `"type": "module"` in `package.json`[1][4] - File extensions (`.mjs` for ESM / `.cjs` for CommonJS) override package-level settings[6] 2. **Third-Party Dependencies** Issues arise when: - Using ESM-only packages with `require()` syntax[7][9] - Mixing module formats without proper configuration[5][8] Example error: ```bash Error [ERR_REQUIRE_ESM]: Must use import to load ES Module[7][9] ``` ### Solutions for Compatibility | Approach | Implementation | Use Case | |----------|----------------|----------| | Dynamic Imports | `const module = await import('esm-package')`[2][9] | Loading ESM packages in CommonJS contexts | | Transpilation | Use Babel/Webpack to convert ESM→CJS[1][4] | Legacy Node.js environments | | Dual Package Exports | Configure `package.json` exports field[1][6]: ```json "exports": { "import": "./esm-module.mjs", "require": "./cjs-module.cjs" } ``` | Library authors supporting both formats | ### Key Considerations - **Next.js Configuration** While native ESM support exists, some tooling (like Jest) may still require CommonJS[3][10] - **Node.js Versions** Full ESM support requires Node.js ≥14.8 for top-level await[2], with stable support since v13.2[1][4] - **TypeScript Users** Must configure `tsconfig.json` with `module: "esnext"` and `moduleResolution: "node16"`[3] Recent updates show Next.js moving toward better ESM integration, but many production setups still benefit from maintaining dual compatibility during transition periods[3][10]. The framework doesn't mandate dual support, but it becomes necessary when using mixed-module dependencies or targeting environments with legacy requirements. Citations: - 1: https://blog.logrocket.com/commonjs-vs-es-modules-node-js/ - 2: https://byteofdev.com/posts/how-to-use-esm/ - 3: https://github.com/vercel/next.js/discussions/32239 - 4: https://dev.to/logrocket/commonjs-vs-es-modules-in-nodejs-2eo1 - 5: https://answers.netlify.com/t/netlify-functions-es-module-error-when-using-paths-config/111942 - 6: https://nodejs.org/api/packages.html - 7: https://sentry.io/answers/next-js-err-require-esm/ - 8: https://event-driven.io/en/how_to_tackle_esmodules_compatibility_issues/ - 9: https://www.freecodecamp.org/news/how-to-bypass-es-modules-error-in-next-js/ - 10: https://nextjs.org/docs/messages/import-esm-externals
Dual Module Approach Verification
The web query confirms that Next.js 15 does not inherently require dual CommonJS/ES module support. In your file, the CommonJS syntax using the .cjs extension—including proper handling of default exports via the
.default
property—is correct. While maintaining dual support can be beneficial for certain compatibility scenarios, it isn’t mandated by Next.js 15.No changes are necessary in this case.
async function copyDir(src: string, dest: string) { | ||
try { | ||
await cp(src, dest, { recursive: true }); | ||
} catch (error) { | ||
console.error(`Failed to copy from ${src} to ${dest}:`, error); | ||
process.exit(1); | ||
} | ||
} | ||
|
||
async function createInstanceDir(port: string) { | ||
try { | ||
await mkdir(path.join(INSTANCES_DIR, port), { recursive: true }); | ||
} catch (error) { | ||
console.error( | ||
`Failed to create ${path.join(INSTANCES_DIR, port)} directory:`, | ||
error, | ||
); | ||
process.exit(1); | ||
} | ||
} |
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
Improve error handling and type safety.
The helper functions could benefit from:
- Better error handling without direct process exits
- More explicit TypeScript types
- More descriptive error messages
Consider this improved implementation:
-async function copyDir(src: string, dest: string) {
+type CopyError = {
+ code: string;
+ message: string;
+ source: string;
+ destination: string;
+};
+
+async function copyDir(src: string, dest: string): Promise<void | CopyError> {
try {
await cp(src, dest, { recursive: true });
} catch (error) {
- console.error(`Failed to copy from ${src} to ${dest}:`, error);
- process.exit(1);
+ return {
+ code: 'COPY_FAILED',
+ message: `Failed to copy directory: ${error instanceof Error ? error.message : 'Unknown error'}`,
+ source: src,
+ destination: dest,
+ };
}
}
-async function createInstanceDir(port: string) {
+async function createInstanceDir(port: string): Promise<void | CopyError> {
try {
await mkdir(path.join(INSTANCES_DIR, port), { recursive: true });
} catch (error) {
- console.error(
- `Failed to create ${path.join(INSTANCES_DIR, port)} directory:`,
- error,
- );
- process.exit(1);
+ return {
+ code: 'CREATE_DIR_FAILED',
+ message: `Failed to create instance directory: ${error instanceof Error ? error.message : 'Unknown error'}`,
+ source: INSTANCES_DIR,
+ destination: port,
+ };
}
}
Then handle errors in the main execution flow:
const result = await copyDir(src, dest);
if (result) {
console.error(`${result.code}: ${result.message}`);
process.exit(1);
}
c70cfa2
to
cc9e820
Compare
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: 0
🧹 Nitpick comments (2)
apps/cache-testing/create-instances.ts (2)
56-59
: Improve error message for expected conditions.The current error message suggests a failure when the fetch cache directory doesn't exist, which is an expected condition. Consider using a more appropriate log level and message.
- console.error('No fetch cache files to copy'); + console.info('No fetch cache files found - skipping copy');
62-63
: Consider making port numbers configurable.The port numbers are hardcoded. Consider making them configurable through environment variables or command-line arguments for better flexibility.
+const INSTANCE_PORTS = process.env.INSTANCE_PORTS?.split(',') ?? ['3000', '3001']; + // Create instance directories -await createInstanceDir('3000'); -await createInstanceDir('3001'); +for (const port of INSTANCE_PORTS) { + await createInstanceDir(port); +}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (9)
.github/workflows/tests.yml
(1 hunks)apps/cache-testing/cache-handler-redis-stack.cjs
(2 hunks)apps/cache-testing/cache-handler-redis-stack.js
(2 hunks)apps/cache-testing/cluster.config.js
(1 hunks)apps/cache-testing/create-instances.sh
(0 hunks)apps/cache-testing/create-instances.ts
(1 hunks)apps/cache-testing/next.config.js
(1 hunks)apps/cache-testing/package.json
(1 hunks)apps/cache-testing/src/instrumentation.ts
(1 hunks)
💤 Files with no reviewable changes (1)
- apps/cache-testing/create-instances.sh
🚧 Files skipped from review as they are similar to previous changes (7)
- .github/workflows/tests.yml
- apps/cache-testing/next.config.js
- apps/cache-testing/src/instrumentation.ts
- apps/cache-testing/package.json
- apps/cache-testing/cluster.config.js
- apps/cache-testing/cache-handler-redis-stack.cjs
- apps/cache-testing/cache-handler-redis-stack.js
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: redis-strings
- GitHub Check: redis-stack
🔇 Additional comments (3)
apps/cache-testing/create-instances.ts (3)
1-14
: LGTM! Well-structured imports and path handling.The code uses proper ES module imports and platform-agnostic path handling.
15-34
: Improve error handling and type safety.The helper functions would benefit from better error handling and type safety as previously suggested.
66-67
: Add overwrite protection for instance directories.The copy operations might silently overwrite existing files. Consider adding a check to prevent accidental overwrites or add a force flag.
❌ Verification inconclusive
🏁 Script executed:
#!/bin/bash # Description: Check if instance directories already contain files that might be overwritten # Check if instance directories exist and contain files for port in 3000 3001; do if [ -d ".next/__instances/$port" ]; then echo "Checking files in instance directory $port:" find ".next/__instances/$port" -type f -exec ls -l {} \; fi doneLength of output: 119
Action Required: Add Overwrite Protection to Instance Directories
The current check shows that the instance directories (3000 and 3001) exist but are empty, so no files were overwritten during the copy process. However, because an empty directory doesn't conclusively prove that overwriting won't occur when files are present, manual verification remains necessary if those directories could later contain files. Consider adding a check (or a force flag option) in the copy logic to avoid accidental overwrites when files already exist.
cc9e820
to
d1ccb08
Compare
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: 1
🔭 Outside diff range comments (1)
packages/server/package.json (1)
16-17
: 💡 Verification agent🧩 Analysis chain
Review the
exports
field configuration.The
exports
field being set tonull
is unusual and might cause issues with module resolution in modern Node.js versions. Consider defining proper export paths for your package entry points.Let me check the current best practices for package exports:
🌐 Web query:
What is the recommended way to configure package.json exports field for ESM packages?
💡 Result:
To configure the
package.json
exports
field effectively for ESM packages while ensuring compatibility with CommonJS (CJS), follow these best practices:
Key Recommendations
Use conditional
exports
syntax
Define separate entry points for ESM (import
) and CJS (require
) under the"."
key:{ "exports": { ".": { "import": "./dist/esm/index.mjs", "require": "./dist/cjs/index.cjs" } } }This ensures Node.js selects the correct format based on how the package is imported[1][3][4].
Avoid
"type": "module"
for dual-mode packages
Omittingtype
defaults to CommonJS, preventing conflicts when supporting both ESM and CJS consumers[3][7].Explicitly declare accessible subpaths
After definingexports
, all other internal paths become private. To expose specific files/submodules:{ "exports": { ".": { /* ... */ }, "./utils": { "import": "./dist/esm/utils.mjs", "require": "./dist/cjs/utils.cjs" }, "./package.json": "./package.json" } }This allows imports like
import utils from 'your-pkg/utils'
[1][4][10].Include TypeScript types (if applicable)
For TypeScript users:{ "exports": { ".": { "types": "./dist/types/index.d.ts", "import": "./dist/esm/index.mjs", "require": "./dist/cjs/index.cjs" } } }
Advanced Configuration
Environment-specific builds
Use conditions likenode
,browser
, or custom environments:{ "exports": { ".": { "node": "./node-specific.js", "browser": "./browser-specific.js", "default": "./fallback.js" } } }Version compatibility
For packages supporting legacy Node.js versions (<12.7.0), retainmain
as a fallback:{ "main": "./dist/cjs/index.cjs", "exports": { /* ... */ } }
Pitfalls to Avoid
- Never mix directory-level access with file-level exports[1]
- Ensure all exposed subpaths are explicitly declared[4]
- Test imports in both ESM (
import
) and CJS (require()
) contexts[3]For full implementation examples, see GitHub repositories like package-json-exports[3].
Citations:
- 1: https://commerce.nearform.com/blog/2021/node-esm-and-exports
- 2: https://dev.to/rameshpvr/export-vs-main-in-packagejson-eoj
- 3: https://snyk.io/blog/building-npm-package-compatible-with-esm-and-cjs-2024/
- 4: https://hirok.io/posts/package-json-exports
- 5: https://metrobundler.dev/docs/package-exports/
- 6: https://forums.meteor.com/t/how-to-import-npm-package-with-exports-field-in-package-json/57276
- 7: https://jeremyrichardson.dev/blog/saga_of_learning_exports_property_in_packagejson
- 8: webpack/webpack#9509
- 9: meteor/meteor#11727
- 10: https://webpack.js.org/guides/package-exports/
Action Required: Update the
exports
Field and Verify Compatibility Settings
The current
"exports": null
configuration is problematic for module resolution with ESM. Instead, define explicit export paths. For example, if supporting both ESM and CommonJS:{ "exports": { ".": { "import": "./dist/esm/index.mjs", "require": "./dist/cjs/index.cjs" } } }If your package is purely ESM, you can define a simpler export such as:
{ "exports": { ".": "./dist/esm/index.mjs" } }Adjust the entry points to match your build output.
Additionally, ensure the
distTags
configuration accurately reflects your intended Next.js 15 support, as the current tags list support for Next.js 13.5 and 14.Confirm that the updated
@types/node
version (22.13.4) is compatible with Next.js 15 and any other dependency requirements.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (18)
.github/workflows/tests.yml
(1 hunks)apps/cache-testing/cache-handler-redis-stack.cjs
(2 hunks)apps/cache-testing/cache-handler-redis-stack.js
(2 hunks)apps/cache-testing/cluster.config.js
(1 hunks)apps/cache-testing/create-instances.sh
(0 hunks)apps/cache-testing/create-instances.ts
(1 hunks)apps/cache-testing/next.config.js
(1 hunks)apps/cache-testing/package.json
(2 hunks)apps/cache-testing/src/instrumentation.ts
(1 hunks)docs/cache-handler-docs/package.json
(1 hunks)internal/backend/package.json
(1 hunks)internal/eslint-config/package.json
(1 hunks)internal/next-common/package.json
(1 hunks)internal/next-lru-cache/package.json
(1 hunks)package.json
(1 hunks)packages/cache-handler/package.json
(1 hunks)packages/json-replacer-reviver/package.json
(1 hunks)packages/server/package.json
(1 hunks)
💤 Files with no reviewable changes (1)
- apps/cache-testing/create-instances.sh
✅ Files skipped from review due to trivial changes (8)
- internal/backend/package.json
- internal/next-common/package.json
- internal/next-lru-cache/package.json
- packages/json-replacer-reviver/package.json
- package.json
- packages/cache-handler/package.json
- internal/eslint-config/package.json
- docs/cache-handler-docs/package.json
🚧 Files skipped from review as they are similar to previous changes (8)
- apps/cache-testing/src/instrumentation.ts
- apps/cache-testing/cache-handler-redis-stack.cjs
- apps/cache-testing/next.config.js
- apps/cache-testing/cluster.config.js
- apps/cache-testing/create-instances.ts
- .github/workflows/tests.yml
- apps/cache-testing/package.json
- apps/cache-testing/cache-handler-redis-stack.js
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: redis-strings
- GitHub Check: redis-stack
- GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
packages/server/package.json (1)
39-42
: Update distTags for Next.js 15 support.Since this PR is for Next.js 15 support, consider adding "next15" to the distTags array.
"distTags": [ "next13.5", "next14", + "next15" ]
packages/server/package.json
Outdated
@@ -31,7 +31,7 @@ | |||
"@repo/next-common": "workspace:*", | |||
"@repo/next-lru-cache": "workspace:*", | |||
"@repo/typescript-config": "workspace:*", | |||
"@types/node": "22.13.1", | |||
"@types/node": "22.13.4", |
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.
💡 Verification agent
🧩 Analysis chain
Verify compatibility with Next.js 15.
Let's verify if this version of @types/node is compatible with Next.js 15 and check if there's a newer version available.
🏁 Script executed:
#!/bin/bash
# Check the latest @types/node version
npm view @types/node versions --json | jq '.[-1]'
Length of output: 61
🌐 Web query:
What version of @types/node is required for Next.js 15?
💡 Result:
Next.js 15 requires using @types/node
version 18.x or higher to align with its minimum Node.js requirement of v18.18[4][7]. While not explicitly stated in documentation, this follows from:
-
Node Version Alignment:
@types/node
versions correlate with Node.js releases (e.g.,@types/node@18
matches Node.js v18 APIs)[9].- Next.js v15 mandates Node ≥18.18[4], so matching
@types/node@18+
ensures type compatibility.
-
Upgrade Practices:
- Always update
@types
packages alongside their runtime counterparts[1][8]. - Use
npm install --save-dev @types/node@latest
for latest type definitions[9].
- Always update
-
Troubleshooting:
- If encountering type errors post-upgrade, check for mismatched
@types
versions[10]. - Ensure
tsconfig.json
includes"node"
incompilerOptions.types
[2].
- If encountering type errors post-upgrade, check for mismatched
For full compatibility:
npm install --save-dev @types/node@^18
Citations:
- 1: https://nextjs.org/docs/app/building-your-application/upgrading/version-15
- 2: https://nextjs.org/docs/pages/api-reference/config/typescript
- 3: What's the version policy for @types/node? vercel/next.js#32695
- 4: https://nextjs.org/blog/next-15
- 5: https://dev.to/dimeloper/whats-new-in-nextjs-15-new-hooks-turbopack-and-more-2lo8
- 6: Error when initializing Next.js project with TypeScript (v14.2.17 and v15) vercel/next.js#72563
- 7: https://nextjs.org/docs/app/building-your-application/upgrading/version-14
- 8: Should TypeScript be a devDependency? (It now shows up under dependencies...) vercel/next.js#44283
- 9: https://www.npmjs.com/package/@types/node
- 10: Cannot install dependencies after upgrading to Next 15 and React 19 RC vercel/next.js#72204
Next.js 15 Compatibility Update:
Although the current dependency "@types/node": "22.13.4"
technically meets the minimum version requirement (≥18.x) for Next.js 15, the upgrade guidelines recommend aligning with Node 18 by using @types/node@^18
. This ensures that the type definitions closely match the Node.js runtime (v18.18) expected by Next.js 15 and avoids potential mismatches from APIs introduced in later Node versions.
- Action Item: Consider changing the dependency in
packages/server/package.json
to:"@types/node": "^18"
d1ccb08
to
52e1de3
Compare
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: 1
🧹 Nitpick comments (4)
apps/cache-testing/create-instances.ts (2)
61-64
: Consider making port numbers configurable.The port numbers are hardcoded, which reduces flexibility and reusability.
Consider making them configurable through environment variables or command-line arguments:
+const DEFAULT_PORTS = ['3000', '3001']; +const ports = process.env.INSTANCE_PORTS?.split(',') || DEFAULT_PORTS; + // Create instance directories -await createInstanceDir('3000'); -await createInstanceDir('3001'); +for (const port of ports) { + await createInstanceDir(port); +}
65-68
: Optimize performance with parallel operations.The copy operations for instance directories are executed sequentially. These operations could be parallelized for better performance.
Consider using
Promise.all
to parallelize the operations:-// Copy files from standalone directory to instance directories -await copyDir(path.join(STANDALONE_DIR, '.'), path.join(INSTANCES_DIR, '3000')); -await copyDir(path.join(STANDALONE_DIR, '.'), path.join(INSTANCES_DIR, '3001')); +// Parallelize copying files from standalone directory to instance directories +await Promise.all( + ports.map(port => + copyDir(path.join(STANDALONE_DIR, '.'), path.join(INSTANCES_DIR, port)) + ) +);internal/eslint-config/next.js (2)
66-68
: Consider using**
for recursive ignore patterns.The current ignore patterns might not catch files in nested directories. Consider using
**
instead of*
:- ignores: ['node_modules/*', '.next/*'], + ignores: ['node_modules/**', '.next/**'],
10-14
: Consider expanding configuration documentation.Since this is a significant change for Next.js 15 support, consider adding more detailed documentation about:
- The reason for switching to flat config
- Required ESLint/TypeScript versions
- Any breaking changes
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (20)
.github/workflows/tests.yml
(1 hunks)apps/cache-testing/cache-handler-redis-stack.cjs
(2 hunks)apps/cache-testing/cache-handler-redis-stack.js
(2 hunks)apps/cache-testing/cluster.config.js
(1 hunks)apps/cache-testing/create-instances.sh
(0 hunks)apps/cache-testing/create-instances.ts
(1 hunks)apps/cache-testing/next.config.js
(1 hunks)apps/cache-testing/package.json
(2 hunks)apps/cache-testing/src/instrumentation.ts
(1 hunks)docs/cache-handler-docs/package.json
(1 hunks)internal/backend/package.json
(1 hunks)internal/eslint-config/next.js
(2 hunks)internal/eslint-config/package.json
(1 hunks)internal/next-common/package.json
(1 hunks)internal/next-lru-cache/package.json
(1 hunks)package.json
(1 hunks)packages/cache-handler/package.json
(1 hunks)packages/json-replacer-reviver/package.json
(1 hunks)packages/server/package.json
(1 hunks)turbo.json
(1 hunks)
💤 Files with no reviewable changes (1)
- apps/cache-testing/create-instances.sh
🚧 Files skipped from review as they are similar to previous changes (16)
- internal/backend/package.json
- packages/json-replacer-reviver/package.json
- internal/next-lru-cache/package.json
- apps/cache-testing/src/instrumentation.ts
- apps/cache-testing/cache-handler-redis-stack.cjs
- internal/next-common/package.json
- apps/cache-testing/next.config.js
- packages/server/package.json
- .github/workflows/tests.yml
- apps/cache-testing/cluster.config.js
- package.json
- packages/cache-handler/package.json
- apps/cache-testing/package.json
- internal/eslint-config/package.json
- apps/cache-testing/cache-handler-redis-stack.js
- docs/cache-handler-docs/package.json
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: redis-strings
- GitHub Check: redis-stack
🔇 Additional comments (5)
turbo.json (1)
14-15
: Environment Variable Addition VerificationThe new environment variable
"NEXT_PRIVATE_DEBUG_CACHE"
has been correctly added next to"PPR_ENABLED"
in the build task'senv
array. Please verify that this variable aligns with the expectations for debugging in Next.js 15. Also, ensure that any related documentation or downstream usage in your codebase references and properly handles this new variable.apps/cache-testing/create-instances.ts (2)
1-14
: LGTM! Well-organized imports and constants.The imports are appropriate for the file operations, and the path constants are clearly named and properly organized. The use of
fileURLToPath
ensures ESM compatibility.
15-34
: Improve error handling and type safety.The helper functions could benefit from better error handling and type safety improvements.
The previous review comment's suggestions for improved error handling, explicit TypeScript types, and more descriptive error messages are still valid and would enhance the code's robustness.
internal/eslint-config/next.js (2)
13-14
:✅ Verification successful
Verify ESLint version compatibility.
The type change to
typescript-eslint.ConfigArray
indicates usage of ESLint's new flat config format. This requires ESLint 9.x and compatible plugins.
🏁 Script executed:
#!/bin/bash # Check ESLint and related package versions in package.json files echo "Checking ESLint version in package.json files..." fd --type f "package.json" --exec jq -r 'select(.dependencies.eslint or .devDependencies.eslint) | "ESLint version in \(.name): \(.dependencies.eslint // .devDependencies.eslint)"'Length of output: 430
ESLint Version Compatibility Confirmed
The type change to
typescript-eslint.ConfigArray
for the updated Next.js configuration is correct. Our version check shows that all package.json files are using ESLint 9.20.1, which supports the new flat config format. No further changes are needed based on this verification.
15-25
:✅ Verification successful
Verify Next.js specific globals.
The configuration includes Node.js globals but might need additional Next.js specific globals for full compatibility with Next.js 15.
🌐 Web query:
What are the required globals for Next.js 15 ESLint configuration?
💡 Result:
Next.js 15's ESLint configuration handles required global variables automatically through its built-in plugin (
eslint-plugin-next
) and recommended configurations. Here's what you need to know:
Core Configuration
Thenext/core-web-vitals
ruleset (included by default) automatically configures:
- Environment: Node.js/ES modules
- JSX/React global recognition
- TypeScript support (if used)
Implicit Globals
No manual global declarations are needed for:
- React/JSX components (
React
,JSX
, etc.)- Web APIs (
fetch
,Request
,Response
)- Node.js globals (
module
,process
,__dirname
)Custom Global Additions
If using experimental features like Edge Runtime or additional APIs, extend your.eslintrc
with:{ "globals": { "EdgeRuntime": "readonly", "AsyncLocalStorage": "readonly" } }For most projects using
next/core-web-vitals
orplugin:@next/next/recommended
, no explicit global configuration is required[1][2][5].Citations:
- 1: https://nextjs.org/docs/app/api-reference/config/eslint
- 2: https://www.danielfullstack.com/article/how-to-configure-eslint-with-nextjs-in-3-minutes
- 3: https://dev.to/jordanahaines/just-use-this-nextjs-eslint-configuration-540
- 4: https://nextjs.org/blog/next-15
- 5: https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/
- 6: https://nextjs.org/blog/next-15-rc2
- 7: vercel/next.js#71763
- 8: https://eslint.org/docs/latest/rules/global-require
- 9: https://www.youtube.com/watch?v=Mloeq7mvI00
- 10: vercel/next.js#73389
Next.js Globals Verification: No Additional Globals Required
The current configuration correctly merges the standard recommended ESLint settings with Node.js globals. As of Next.js 15, if you’re using the built-in ESLint plugin (e.g., via
next/core-web-vitals
orplugin:@next/next/recommended
), all necessary Next.js globals (for React/JSX, web APIs, etc.) are automatically handled. There’s no need to manually add extra Next.js specific globals unless you're targeting experimental features (e.g., Edge Runtime).
- File:
internal/eslint-config/next.js
- Lines: 15-25 – The code already applies
globals.node
via spread. Ensure that your project also includes the appropriate Next.js ESLint configuration to leverage the automatic global setup.
try { | ||
// Copy fetch cache directory to standalone app/.next directory | ||
await mkdir(path.join(APP_DIR, '.next/cache/fetch-cache'), { | ||
recursive: true, | ||
}); | ||
|
||
const files = await readdir(FETCH_CACHE_DIR); | ||
|
||
if (files.length > 0) { | ||
await copyDir( | ||
FETCH_CACHE_DIR, | ||
path.join(APP_DIR, '.next/cache/fetch-cache'), | ||
); | ||
} | ||
} catch (_error) { | ||
// Ignore errors - directory might not exist or be empty | ||
console.error('No fetch cache files to copy'); | ||
} |
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
Inconsistent error handling approach.
The error handling for fetch cache operations differs from other operations in the script. While other operations exit on error, this section silently continues with a console error.
Consider standardizing the error handling approach across all operations:
try {
// Copy fetch cache directory to standalone app/.next directory
await mkdir(path.join(APP_DIR, '.next/cache/fetch-cache'), {
recursive: true,
});
const files = await readdir(FETCH_CACHE_DIR);
if (files.length > 0) {
await copyDir(
FETCH_CACHE_DIR,
path.join(APP_DIR, '.next/cache/fetch-cache'),
);
}
-} catch (_error) {
- // Ignore errors - directory might not exist or be empty
- console.error('No fetch cache files to copy');
+} catch (error) {
+ console.warn('No fetch cache files to copy:', error instanceof Error ? error.message : 'Unknown error');
}
📝 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.
try { | |
// Copy fetch cache directory to standalone app/.next directory | |
await mkdir(path.join(APP_DIR, '.next/cache/fetch-cache'), { | |
recursive: true, | |
}); | |
const files = await readdir(FETCH_CACHE_DIR); | |
if (files.length > 0) { | |
await copyDir( | |
FETCH_CACHE_DIR, | |
path.join(APP_DIR, '.next/cache/fetch-cache'), | |
); | |
} | |
} catch (_error) { | |
// Ignore errors - directory might not exist or be empty | |
console.error('No fetch cache files to copy'); | |
} | |
try { | |
// Copy fetch cache directory to standalone app/.next directory | |
await mkdir(path.join(APP_DIR, '.next/cache/fetch-cache'), { | |
recursive: true, | |
}); | |
const files = await readdir(FETCH_CACHE_DIR); | |
if (files.length > 0) { | |
await copyDir( | |
FETCH_CACHE_DIR, | |
path.join(APP_DIR, '.next/cache/fetch-cache'), | |
); | |
} | |
} catch (error) { | |
console.warn('No fetch cache files to copy:', error instanceof Error ? error.message : 'Unknown error'); | |
} |
52e1de3
to
dd10f82
Compare
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: 0
🧹 Nitpick comments (2)
pnpm-workspace.yaml (2)
1-5
: Package list formatting looks correct.
The packages are now listed without quotes (except within comments) which is acceptable in YAML. Just ensure this style is consistent throughout the project.
6-9
: Consistency in dependency string quoting.
The newonlyBuiltDependencies
section mixes quoted ('@biomejs/biome'
) and unquoted (esbuild
,sharp
) entries. For readability and maintainability, consider using a consistent approach for quoting all entries.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (11)
apps/cache-testing/package.json
(2 hunks)docs/cache-handler-docs/package.json
(1 hunks)internal/backend/package.json
(1 hunks)internal/eslint-config/package.json
(1 hunks)internal/next-common/package.json
(1 hunks)internal/next-lru-cache/package.json
(1 hunks)package.json
(1 hunks)packages/cache-handler/package.json
(1 hunks)packages/json-replacer-reviver/package.json
(1 hunks)packages/server/package.json
(1 hunks)pnpm-workspace.yaml
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
- internal/next-common/package.json
- internal/backend/package.json
- internal/next-lru-cache/package.json
- packages/cache-handler/package.json
- packages/server/package.json
- packages/json-replacer-reviver/package.json
- apps/cache-testing/package.json
- internal/eslint-config/package.json
🔇 Additional comments (5)
package.json (2)
27-33
: DevDependencies version updates are aligned.
The versions for@changesets/cli
,prettier
, andturbo
have been bumped as expected in this effort. Please ensure these updates are compatible with dependent packages and your broader build process.
34-34
: Updated packageManager specification.
ThepackageManager
field now specifies[email protected]
along with its lockfile checksum. Make sure that all developers and CI environments are aware of this update to prevent any version conflicts.docs/cache-handler-docs/package.json (3)
13-16
: Dependency version bumps for Next.js and documentation tools.
The updates for"next"
,"nextra"
, and"nextra-theme-docs"
(to versions15.2.0
and4.2.13
respectively) support the Next.js 15 initiative. Confirm that the documentation build process (e.g., vianext build
andpagefind
) continues to operate as expected.
17-18
: Verify React dependency versions.
Thereact
andreact-dom
dependencies are set to"19.0.0"
. Please double-check that these versions are intentional and fully compatible with the updated Next.js 15 features, as Next.js typically maintains closer alignment with stable React releases.
20-26
: DevDependencies update enhances type safety and linting support.
The updates for@types/node
,@types/react
,@types/react-dom
, andeslint
will help maintain code quality while aligning with the latest Next.js version. It’s advisable to run the full test suite to ensure no regression issues arise from these version bumps.
b6da01d
to
cceb5a9
Compare
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: 0
🧹 Nitpick comments (1)
.github/dependabot.yml (1)
13-13
: Broadening the Dependency Version Range forlru-cache
The update from a fixed
11.x.x
range to['>=11.0.0']
allows for any version oflru-cache
starting from 11.0.0. This change improves flexibility but also opens up the possibility of incompatibilities with future major versions. Please ensure that the codebase is compatible with newer releases oflru-cache
or consider adding tests/compatibility checks that can catch breaking changes early.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (58)
.changeset/config.json
(0 hunks).github/dependabot.yml
(1 hunks)apps/cache-testing/next.config.js
(2 hunks)apps/cache-testing/src/app/app/no-params/dynamic-false/[slug]/page.tsx
(1 hunks)apps/cache-testing/src/app/app/no-params/dynamic-true/[slug]/page.tsx
(1 hunks)apps/cache-testing/src/app/app/no-params/ssr/200/page.tsx
(1 hunks)apps/cache-testing/src/app/app/ppr/page.tsx
(2 hunks)apps/cache-testing/src/app/app/randomHex/[length]/page.tsx
(1 hunks)apps/cache-testing/src/app/app/with-params/dynamic-false/[slug]/page.tsx
(2 hunks)apps/cache-testing/src/app/app/with-params/dynamic-true/[slug]/page.tsx
(2 hunks)apps/cache-testing/src/app/app/with-params/nesh-cache/[slug]/page.tsx
(0 hunks)apps/cache-testing/src/app/app/with-params/unstable-cache/[slug]/page.tsx
(0 hunks)apps/cache-testing/src/app/layout.tsx
(1 hunks)apps/cache-testing/src/components/cache-state-watcher.tsx
(1 hunks)apps/cache-testing/src/components/pre-rendered-at.tsx
(1 hunks)apps/cache-testing/src/components/restart-button.tsx
(1 hunks)apps/cache-testing/src/components/revalidate-button.tsx
(1 hunks)apps/cache-testing/src/pages/_app.tsx
(1 hunks)apps/cache-testing/src/pages/api/pages-cached-api.ts
(0 hunks)apps/cache-testing/src/pages/layout.tsx
(1 hunks)apps/cache-testing/src/pages/pages/no-paths/ssr-with-cache/200.tsx
(0 hunks)apps/cache-testing/src/pages/pages/randomHex/[length].tsx
(1 hunks)apps/cache-testing/src/utils/common-app-page.tsx
(1 hunks)apps/cache-testing/src/utils/common-pages-page.tsx
(1 hunks)apps/cache-testing/src/utils/create-get-data.ts
(2 hunks)apps/cache-testing/src/utils/create-pages-get-get-server-side-props-cached.ts
(0 hunks)apps/cache-testing/tests/app.spec.ts
(0 hunks)apps/cache-testing/tests/pages.spec.ts
(0 hunks)biome.json
(1 hunks)internal/eslint-config/next.js
(3 hunks)internal/next-common/src/next-common.ts
(3 hunks)internal/next-lru-cache/src/cache-types/next-cache-handler-value.ts
(2 hunks)internal/next-lru-cache/tsconfig.json
(1 hunks)package.json
(2 hunks)packages/cache-handler/src/cache-handler.ts
(6 hunks)packages/cache-handler/src/functions/functions.ts
(0 hunks)packages/cache-handler/src/functions/nesh-cache.ts
(0 hunks)packages/cache-handler/src/functions/nesh-classic-cache.ts
(0 hunks)packages/cache-handler/src/handlers/server.ts
(0 hunks)packages/cache-handler/src/instrumentation/register-initial-cache.ts
(3 hunks)packages/cache-handler/tsconfig.json
(1 hunks)packages/json-replacer-reviver/.npmignore
(0 hunks)packages/json-replacer-reviver/CHANGELOG.md
(0 hunks)packages/json-replacer-reviver/LICENSE
(0 hunks)packages/json-replacer-reviver/README.md
(0 hunks)packages/json-replacer-reviver/package.json
(0 hunks)packages/json-replacer-reviver/src/json-replacer-reviver.test.ts
(0 hunks)packages/json-replacer-reviver/src/json-replacer-reviver.ts
(0 hunks)packages/json-replacer-reviver/tsconfig.json
(0 hunks)packages/json-replacer-reviver/tsup.config.ts
(0 hunks)packages/server/.npmignore
(0 hunks)packages/server/CHANGELOG.md
(0 hunks)packages/server/LICENSE
(0 hunks)packages/server/README.md
(0 hunks)packages/server/package.json
(0 hunks)packages/server/src/server.ts
(0 hunks)packages/server/tsconfig.json
(0 hunks)packages/server/tsup.config.ts
(0 hunks)
💤 Files with no reviewable changes (29)
- .changeset/config.json
- packages/server/README.md
- packages/server/LICENSE
- packages/json-replacer-reviver/tsconfig.json
- packages/server/.npmignore
- packages/json-replacer-reviver/tsup.config.ts
- packages/json-replacer-reviver/LICENSE
- packages/json-replacer-reviver/README.md
- packages/server/package.json
- apps/cache-testing/src/pages/api/pages-cached-api.ts
- packages/cache-handler/src/functions/functions.ts
- packages/json-replacer-reviver/package.json
- packages/server/CHANGELOG.md
- packages/server/tsconfig.json
- apps/cache-testing/tests/app.spec.ts
- packages/json-replacer-reviver/CHANGELOG.md
- apps/cache-testing/tests/pages.spec.ts
- apps/cache-testing/src/pages/pages/no-paths/ssr-with-cache/200.tsx
- apps/cache-testing/src/utils/create-pages-get-get-server-side-props-cached.ts
- apps/cache-testing/src/app/app/with-params/unstable-cache/[slug]/page.tsx
- packages/server/src/server.ts
- packages/cache-handler/src/functions/nesh-classic-cache.ts
- packages/json-replacer-reviver/src/json-replacer-reviver.test.ts
- apps/cache-testing/src/app/app/with-params/nesh-cache/[slug]/page.tsx
- packages/cache-handler/src/handlers/server.ts
- packages/cache-handler/src/functions/nesh-cache.ts
- packages/json-replacer-reviver/.npmignore
- packages/json-replacer-reviver/src/json-replacer-reviver.ts
- packages/server/tsup.config.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- package.json
🧰 Additional context used
🪛 GitHub Actions: Check Docs Build
apps/cache-testing/src/app/layout.tsx
[error] 56-56: Type error: Unused '@ts-expect-error' directive.
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: redis-strings
- GitHub Check: redis-stack
🔇 Additional comments (47)
biome.json (1)
55-55
: Update Global Variable Declaration for React ContextThe change updates the "globals" array from
["JSX"]
to["React"]
, which aligns with the transition towards a React-centric configuration—especially pertinent for Next.js 15 support. Please verify that this update is consistent with the rest of your project’s linting settings and that any references expecting the older "JSX" global are updated accordingly.internal/eslint-config/next.js (4)
13-15
: Migration to ESLint's new "flat" configuration format.You've correctly updated the type annotation and export format to use TypeScript-ESLint's new flat configuration pattern, which aligns with modern ESLint practices introduced in ESLint v8.21.0+. This approach offers better extensibility and compatibility with Next.js 15.
19-25
: Language options configuration looks good.Proper implementation of the new languageOptions format with Node.js globals merged in. This ensures consistency across the codebase for available global variables.
45-47
: Good choice disabling React prop-types.Disabling 'react/prop-types' is appropriate for TypeScript projects since TypeScript's static type checking provides better prop validation than the runtime checks from prop-types.
69-84
: Well-configured TypeScript unused variables rule.Excellent detailed configuration of the
@typescript-eslint/no-unused-vars
rule. The setup properly handles the common convention of prefixing intentionally unused variables with underscore (_
), while still enforcing checks on other variables.apps/cache-testing/next.config.js (2)
14-14
: Verify impact of commented out outputFileTracingRoot.This configuration property was previously used for file tracing. Since it's now commented out, ensure this doesn't negatively impact the build process in Next.js 15, especially for the standalone output.
The commented line also used
import.meta.dirname
which may have been changed in Next.js 15's configuration approach. If this property is still needed, consider updating to use a compatible path resolution method.
5-5
:✅ Verification successful
Extension change aligns with module standardization.
The update from
.mjs
to.js
aligns with the broader effort to standardize module usage across the application as mentioned in the PR summary. Ensure that the referenced filecache-handler-redis-stack.js
has been properly converted to maintain compatibility.
🏁 Script executed:
#!/bin/bash # Verify the existence and syntax of the cache handler file if [ -f "apps/cache-testing/cache-handler-redis-stack.js" ]; then echo "✅ File exists" # Check for ES module syntax grep -E "export |import " "apps/cache-testing/cache-handler-redis-stack.js" || echo "⚠️ No ES module syntax found" else echo "❌ File not found: apps/cache-testing/cache-handler-redis-stack.js" fiLength of output: 426
Verified: Module Standardization and File Conversion are Correctly Implemented
The file
apps/cache-testing/cache-handler-redis-stack.js
exists and is confirmed to use ES module syntax as required. The change from.mjs
to.js
is in line with our module standardization efforts and no compatibility issues were found.apps/cache-testing/src/components/restart-button.tsx (1)
5-5
: Return type update looks goodThe change from
JSX.Element
toReact.ReactNode
is appropriate and aligns with Next.js 15 compatibility requirements.React.ReactNode
is more flexible and allows for a wider range of return types.apps/cache-testing/src/utils/common-pages-page.tsx (1)
12-12
: Return type update looks goodThe change from
JSX.Element
toReact.ReactNode
is appropriate and aligns with Next.js 15 compatibility requirements. This matches the consistent pattern applied across other components.apps/cache-testing/src/pages/_app.tsx (1)
5-8
: Return type update and improved formattingThe change from
JSX.Element
toReact.ReactNode
is appropriate for Next.js 15 support. Additionally, the improved parameter formatting with each parameter on its own line enhances readability.apps/cache-testing/src/utils/common-app-page.tsx (1)
13-13
: Return type update looks goodThe change from
JSX.Element
toReact.ReactNode
is appropriate and aligns with Next.js 15 compatibility requirements. This maintains consistency with other components in the codebase.apps/cache-testing/src/components/revalidate-button.tsx (1)
19-19
: Type broadening improves flexibility.The change from
JSX.Element
toReact.ReactNode
as the return type is a good practice that allows for more flexibility in what the component can return.React.ReactNode
is more inclusive and can represent any renderable node type (elements, strings, numbers, arrays, null, etc.), whileJSX.Element
is limited to only React elements created via JSX.apps/cache-testing/src/app/app/no-params/ssr/200/page.tsx (1)
8-8
: Return type broadening aligns with React best practices.Changing the return type from
Promise<JSX.Element>
toPromise<React.ReactNode>
is appropriate for this async component. This provides more flexibility while maintaining type safety, conforming to the pattern being applied across the codebase to standardize return types.apps/cache-testing/src/pages/pages/randomHex/[length].tsx (1)
53-53
: Consistent type improvement across components.The return type change from
JSX.Element
toReact.ReactNode
follows the same pattern applied to other components in this PR. This is a beneficial change that improves type flexibility while maintaining strong typing for the component's return value.apps/cache-testing/src/components/cache-state-watcher.tsx (1)
10-10
: Return type broadening completes the pattern.This change completes the consistent update pattern across components by changing the return type from
JSX.Element
toReact.ReactNode
. This standardization improves flexibility while maintaining type safety throughout the codebase.apps/cache-testing/src/pages/layout.tsx (1)
7-9
: Return type updated to React.ReactNode for broader type flexibilityThis change from
JSX.Element
toReact.ReactNode
aligns with Next.js 15 standards and provides greater flexibility for return values.React.ReactNode
allows for strings, numbers, arrays, and other React elements to be returned, not just JSX elements.apps/cache-testing/src/app/layout.tsx (1)
13-15
: Return type updated to React.ReactNode for broader type flexibilityThis change from
JSX.Element
toReact.ReactNode
aligns with Next.js 15 standards and provides greater flexibility for return values.apps/cache-testing/src/components/pre-rendered-at.tsx (1)
5-8
: Return type updated to React.ReactNode for broader type flexibilityThis change from
JSX.Element
toReact.ReactNode
provides greater flexibility for return values and maintains consistency with other component updates in the codebase.apps/cache-testing/src/app/app/no-params/dynamic-false/[slug]/page.tsx (3)
10-10
: Updated PageParams type to support asynchronous route parametersThe
PageParams
type has been updated to handle route parameters as promises, which is likely required for Next.js 15 compatibility.
14-16
: Return type updated to Promise<React.ReactNode> for broader type flexibilityThis change aligns with Next.js 15 standards and provides greater flexibility for return values by using
React.ReactNode
instead ofJSX.Element
.
17-18
: Properly handling asynchronous route parametersThe code now correctly awaits the promise-based parameters before using them, addressing the type change made in the
PageParams
interface.apps/cache-testing/src/app/app/ppr/page.tsx (1)
7-7
: Type updates align with Next.js 15 standardsThese return type changes from
JSX.Element
toReact.ReactNode
are appropriate and follow React best practices.React.ReactNode
is more flexible as it can represent any possible return value of a React component (elements, strings, numbers, arrays, etc.), whereasJSX.Element
is limited to React elements specifically.Also applies to: 23-23, 27-27
apps/cache-testing/src/app/app/no-params/dynamic-true/[slug]/page.tsx (1)
10-10
: Correctly handles Promise-based params in Next.js 15The changes properly adapt the component to work with Next.js 15's Promise-based params. The type update to
Promise<{ slug: string }>
and the addition of awaiting the params before accessing the slug property are necessary adaptations.Also applies to: 16-18
apps/cache-testing/src/utils/create-get-data.ts (1)
7-7
: Streamlined caching implementation for Next.js 15The code has been simplified to use only standard
RequestCache
types, removing the custom cache options ('unstable-cache' and 'nesh-cache'). The fetch implementation is now more direct with cleaner error handling, which aligns with Next.js 15's consolidated caching approach.Also applies to: 18-25, 27-28
apps/cache-testing/src/app/app/with-params/dynamic-false/[slug]/page.tsx (1)
6-6
: Improved type definitions and Promise handling for Next.js 15The changes correctly adapt to Next.js 15's Promise-based params pattern. The explicit type definition for
generateStaticParams
improves code clarity. The addition of awaiting params before accessing the slug property ensures compatibility with the new API.Also applies to: 14-18, 28-30
apps/cache-testing/src/app/app/with-params/dynamic-true/[slug]/page.tsx (3)
6-6
: Updated type signature to handle asynchronous paramsThe
PageParams
type has been updated to makeparams
a Promise, which aligns with Next.js 15's new approach to handling route parameters asynchronously.
14-18
: Explicit typing for generateStaticParams return valueThe return type is now more explicitly defined instead of using
PageParams['params'][]
, which improves type clarity and maintainability.
28-30
: Updated component to handle async params and broadened return typeThe changes correctly:
- Update the return type to
React.ReactNode
which is more flexible thanJSX.Element
- Add async handling for params to accommodate the new Promise-based type structure
This implementation properly adapts to Next.js 15's new parameter handling approach.
apps/cache-testing/src/app/app/randomHex/[length]/page.tsx (3)
10-10
: Updated type signature to handle asynchronous paramsThe
PageParams
type has been updated to makeparams
a Promise, consistent with Next.js 15's new approach to handling route parameters asynchronously.
12-16
: Made generateStaticParams async with explicit return typeThe function has been properly updated to:
- Be marked as
async
- Have a clearly defined return type instead of using
PageParams['params'][]
This change is consistent with Next.js 15's parameter handling approach.
21-24
: Updated component to handle async params and broadened return typeThe changes correctly:
- Update the destructuring to handle the Promise-based params
- Await the resolution of the params before accessing the length property
- Change the return type to the more flexible
React.ReactNode
These updates appropriately adapt the component to Next.js 15's new parameter handling pattern.
internal/next-lru-cache/tsconfig.json (1)
4-7
: Verify and Confirm Module Isolation SettingThe new
"compilerOptions"
block introduces"isolatedModules": false
. Please confirm that disabling isolated module checks is intentional for Next.js 15 support and aligns with the overall migration to ECMAScript modules. This configuration may affect how modules are transpiled and type-checked, so ensure that it meets your project’s requirements.packages/cache-handler/tsconfig.json (1)
5-6
: Ensure Consistency with ECMAScript Module MigrationThe addition of
"isolatedModules": false
in thecompilerOptions
section matches changes in other parts of the repository. Please verify that this setting is consistent with the expectations of the new TypeScript build process under Next.js 15. Disabling isolated modules can bypass some module-level type checks, so double-check that this is the intended behavior.internal/next-lru-cache/src/cache-types/next-cache-handler-value.ts (4)
1-1
: Import enhanced to include CachedRouteKind enumGood change to import the enum directly, providing better type safety than using string literals.
14-18
: Improved type safety with CachedRouteKind enumReplacing string literals with enum values from CachedRouteKind improves code maintainability and provides better type checking.
Also applies to: 18-23, 24-27, 28-31
32-37
: Added size calculation for PAGES and APP_PAGE route kindsThe addition of specific size calculations for these route kinds helps ensure accurate memory usage tracking. The implementation correctly accounts for both HTML content and associated data.
38-40
:❓ Verification inconclusive
Verify the default case behavior
The default case now simply returns 0 instead of attempting to estimate size. This might lead to underestimating memory usage for unhandled cache types.
Is this intentional, or should there be a fallback calculation for unknown types?
🏁 Script executed:
#!/bin/bash # Look for any other cache kinds that might need specific size calculations ast-grep --pattern 'CachedRouteKind.$_' | grep -v "REDIRECT\|IMAGE\|FETCH\|APP_ROUTE\|PAGES\|APP_PAGE"Length of output: 104
Cache Type Fallback Behavior Verification
After running the search for additional cache kinds (beyond REDIRECT, IMAGE, FETCH, APP_ROUTE, PAGES, and APP_PAGE) we didn’t identify any extra entries in the codebase. Please confirm that having the default case simply return 0 is an intentional design decision. If there’s any possibility for new or unforeseen cache types in the future, consider if a fallback size estimation would prevent underestimating memory usage.
internal/next-common/src/next-common.ts (3)
8-11
: Improved import organization for typesGood refactoring to improve type organization, separating CachedRouteKind and IncrementalCacheValue in a clean import structure.
27-27
: Added export for CachedRouteKind enumExplicitly exporting CachedRouteKind makes it available for other modules, supporting the migration from string literals to enum values.
134-134
: Updated IncrementalCachedPageValue to use enumThe type now references CachedRouteKind.PAGES instead of a string literal, improving type safety and consistency.
packages/cache-handler/src/instrumentation/register-initial-cache.ts (3)
3-8
: Improved import organization and added CachedRouteKindThe imports are now better organized with named imports, and CachedRouteKind is properly imported.
208-208
: Updated route cache to use CachedRouteKind.APP_ROUTEReplaced string literal 'ROUTE' with the enum value for consistency and type safety.
295-295
: Updated page cache to use CachedRouteKind.PAGESReplaced string literal 'PAGE' with the enum value for consistency and type safety.
packages/cache-handler/src/cache-handler.ts (4)
16-16
: Added import for CachedRouteKind enumGood addition to support the transition from string literals to enum values throughout the file.
442-442
: Updated kind checks to use CachedRouteKind enumReplaced string literal comparisons with enum values, improving type safety and consistency.
Also applies to: 852-857
907-940
: Refactored switch statement to use enum valuesAll case statements now use CachedRouteKind enum values instead of string literals, and the conditional check for pages has been updated accordingly.
832-832
:❓ Verification inconclusive
Removed default value for ctx parameter
The default value for the
ctx
parameter in theget
method has been removed, making it a required parameter.This could potentially break existing code if it relied on the default value. Please confirm that all call sites provide this parameter.
🏁 Script executed:
#!/bin/bash # Find all calls to get() method to check if they provide the ctx parameter ast-grep --pattern 'cacheHandler.get($_, $_)' || true ast-grep --pattern '\.get($_, $_)' | grep -v 'CacheHandler.#mergedHandler'Length of output: 122
Attention: Verify Explicit Provision of
ctx
ParameterThe default value for the
ctx
parameter in theget
method (atpackages/cache-handler/src/cache-handler.ts
line 832) has been removed, making it mandatory. Automated AST queries did not return any results, which might indicate that no call sites rely on the default value—but the absence of output is inconclusive.
- Action Needed: Manually verify that every call to the
get()
method provides thectx
parameter to prevent any potential runtime errors.
cceb5a9
to
8295b90
Compare
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: 0
🧹 Nitpick comments (3)
apps/cache-testing/tsconfig.json (1)
8-8
: Confirm the updatedinclude
array.
The"include"
array now omits"run-app-instances.ts"
, consolidating the entries into a single line. Please verify that excluding"run-app-instances.ts"
is intentional and that no necessary files are skipped from type checking.packages/cache-handler/src/lru-cache-next-adapter/cache-types/next-cache-handler-value.ts (1)
42-42
: Simplified default case to return 0.The default case now returns 0 instead of attempting to calculate a size. This might be less accurate if there are unhandled kinds in the future.
Consider adding a warning log in the default case to help identify any unhandled kinds during development, or implement a fallback calculation:
- return 0; + console.warn(`Unhandled kind in calculateObjectSize: ${(value as any).kind}`); + return JSON.stringify(value).length || 0;packages/cache-handler/package.json (1)
17-17
: Trailing space in repository URL.There's an extra space at the end of the repository URL which should be removed.
- "url": "git+https://github.com/caching-tools/next-shared-cache.git " + "url": "git+https://github.com/caching-tools/next-shared-cache.git"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (94)
.changeset/config.json
(0 hunks).github/dependabot.yml
(1 hunks).github/workflows/tests.yml
(1 hunks).gitignore
(1 hunks)apps/cache-testing/cache-handler-redis-stack.cjs
(2 hunks)apps/cache-testing/cache-handler-redis-stack.js
(2 hunks)apps/cache-testing/next.config.ts
(1 hunks)apps/cache-testing/package.json
(2 hunks)apps/cache-testing/src/app/app/no-params/dynamic-false/[slug]/page.tsx
(1 hunks)apps/cache-testing/src/app/app/no-params/dynamic-true/[slug]/page.tsx
(1 hunks)apps/cache-testing/src/app/app/no-params/ssr/200/page.tsx
(1 hunks)apps/cache-testing/src/app/app/ppr/page.tsx
(2 hunks)apps/cache-testing/src/app/app/randomHex/[length]/page.tsx
(1 hunks)apps/cache-testing/src/app/app/with-params/dynamic-false/[slug]/page.tsx
(2 hunks)apps/cache-testing/src/app/app/with-params/dynamic-true/[slug]/page.tsx
(2 hunks)apps/cache-testing/src/app/app/with-params/nesh-cache/[slug]/page.tsx
(0 hunks)apps/cache-testing/src/app/app/with-params/unstable-cache/[slug]/page.tsx
(0 hunks)apps/cache-testing/src/app/layout.tsx
(1 hunks)apps/cache-testing/src/components/cache-state-watcher.tsx
(1 hunks)apps/cache-testing/src/components/pre-rendered-at.tsx
(1 hunks)apps/cache-testing/src/components/restart-button.tsx
(1 hunks)apps/cache-testing/src/components/revalidate-button.tsx
(1 hunks)apps/cache-testing/src/instrumentation.ts
(1 hunks)apps/cache-testing/src/pages/_app.tsx
(1 hunks)apps/cache-testing/src/pages/api/pages-cached-api.ts
(0 hunks)apps/cache-testing/src/pages/layout.tsx
(1 hunks)apps/cache-testing/src/pages/pages/no-paths/ssr-with-cache/200.tsx
(0 hunks)apps/cache-testing/src/pages/pages/randomHex/[length].tsx
(1 hunks)apps/cache-testing/src/utils/common-app-page.tsx
(1 hunks)apps/cache-testing/src/utils/common-pages-page.tsx
(1 hunks)apps/cache-testing/src/utils/create-get-data.ts
(2 hunks)apps/cache-testing/src/utils/create-pages-get-get-server-side-props-cached.ts
(0 hunks)apps/cache-testing/tests/app.spec.ts
(0 hunks)apps/cache-testing/tests/pages.spec.ts
(0 hunks)apps/cache-testing/tsconfig.json
(1 hunks)biome.json
(1 hunks)docs/cache-handler-docs/package.json
(1 hunks)docs/cache-handler-docs/src/app/layout.tsx
(0 hunks)docs/cache-handler-docs/tsconfig.json
(1 hunks)internal/backend/package.json
(2 hunks)internal/backend/tsconfig.json
(1 hunks)internal/eslint-config/next.js
(3 hunks)internal/eslint-config/package.json
(1 hunks)internal/next-common/package.json
(0 hunks)internal/next-common/tsconfig.json
(0 hunks)internal/next-lru-cache/package.json
(0 hunks)internal/next-lru-cache/tsconfig.json
(0 hunks)internal/typescript-config/lib.json
(1 hunks)internal/typescript-config/local.json
(1 hunks)internal/typescript-config/nextjs.json
(1 hunks)package.json
(2 hunks)packages/cache-handler/.npmignore
(1 hunks)packages/cache-handler/package.json
(2 hunks)packages/cache-handler/src/cache-handler.ts
(4 hunks)packages/cache-handler/src/functions/functions.ts
(0 hunks)packages/cache-handler/src/functions/nesh-cache.ts
(0 hunks)packages/cache-handler/src/functions/nesh-classic-cache.ts
(0 hunks)packages/cache-handler/src/handlers/experimental-redis-cluster.ts
(1 hunks)packages/cache-handler/src/handlers/local-lru.ts
(1 hunks)packages/cache-handler/src/handlers/redis-stack.ts
(1 hunks)packages/cache-handler/src/handlers/redis-strings.ts
(6 hunks)packages/cache-handler/src/handlers/server.ts
(0 hunks)packages/cache-handler/src/helpers/create-validated-age-estimation-function.test.ts
(1 hunks)packages/cache-handler/src/helpers/create-validated-age-estimation-function.ts
(1 hunks)packages/cache-handler/src/helpers/helpers.ts
(1 hunks)packages/cache-handler/src/helpers/is-implicit-tag.ts
(1 hunks)packages/cache-handler/src/helpers/is-tags-manifest.ts
(1 hunks)packages/cache-handler/src/helpers/promise-with-timeout.test.ts
(1 hunks)packages/cache-handler/src/helpers/promise-with-timeout.ts
(1 hunks)packages/cache-handler/src/instrumentation/instrumentation.ts
(0 hunks)packages/cache-handler/src/instrumentation/register-initial-cache.ts
(3 hunks)packages/cache-handler/src/lru-cache-next-adapter/cache-types/cache-string-value.ts
(1 hunks)packages/cache-handler/src/lru-cache-next-adapter/cache-types/next-cache-handler-value.ts
(2 hunks)packages/cache-handler/src/next-common-types.ts
(3 hunks)packages/cache-handler/tsconfig.json
(1 hunks)packages/cache-handler/tsup.config.ts
(0 hunks)packages/json-replacer-reviver/.npmignore
(0 hunks)packages/json-replacer-reviver/CHANGELOG.md
(0 hunks)packages/json-replacer-reviver/LICENSE
(0 hunks)packages/json-replacer-reviver/README.md
(0 hunks)packages/json-replacer-reviver/package.json
(0 hunks)packages/json-replacer-reviver/src/json-replacer-reviver.test.ts
(0 hunks)packages/json-replacer-reviver/src/json-replacer-reviver.ts
(0 hunks)packages/json-replacer-reviver/tsconfig.json
(0 hunks)packages/json-replacer-reviver/tsup.config.ts
(0 hunks)packages/server/.npmignore
(0 hunks)packages/server/CHANGELOG.md
(0 hunks)packages/server/LICENSE
(0 hunks)packages/server/README.md
(0 hunks)packages/server/package.json
(0 hunks)packages/server/src/server.ts
(0 hunks)packages/server/tsconfig.json
(0 hunks)packages/server/tsup.config.ts
(0 hunks)turbo.json
(2 hunks)
💤 Files with no reviewable changes (36)
- docs/cache-handler-docs/src/app/layout.tsx
- internal/next-common/tsconfig.json
- packages/json-replacer-reviver/LICENSE
- packages/server/README.md
- packages/server/LICENSE
- packages/server/package.json
- packages/json-replacer-reviver/.npmignore
- packages/json-replacer-reviver/tsup.config.ts
- packages/server/CHANGELOG.md
- packages/server/.npmignore
- packages/server/tsup.config.ts
- internal/next-lru-cache/tsconfig.json
- packages/json-replacer-reviver/package.json
- packages/server/tsconfig.json
- internal/next-lru-cache/package.json
- packages/cache-handler/tsup.config.ts
- packages/json-replacer-reviver/README.md
- internal/next-common/package.json
- packages/json-replacer-reviver/CHANGELOG.md
- apps/cache-testing/tests/app.spec.ts
- packages/cache-handler/src/functions/functions.ts
- apps/cache-testing/src/pages/api/pages-cached-api.ts
- apps/cache-testing/src/utils/create-pages-get-get-server-side-props-cached.ts
- packages/cache-handler/src/functions/nesh-classic-cache.ts
- packages/cache-handler/src/instrumentation/instrumentation.ts
- apps/cache-testing/src/app/app/with-params/unstable-cache/[slug]/page.tsx
- packages/cache-handler/src/handlers/server.ts
- .changeset/config.json
- apps/cache-testing/src/app/app/with-params/nesh-cache/[slug]/page.tsx
- packages/json-replacer-reviver/tsconfig.json
- packages/server/src/server.ts
- packages/json-replacer-reviver/src/json-replacer-reviver.test.ts
- apps/cache-testing/src/pages/pages/no-paths/ssr-with-cache/200.tsx
- apps/cache-testing/tests/pages.spec.ts
- packages/cache-handler/src/functions/nesh-cache.ts
- packages/json-replacer-reviver/src/json-replacer-reviver.ts
✅ Files skipped from review due to trivial changes (13)
- .gitignore
- packages/cache-handler/src/helpers/promise-with-timeout.ts
- packages/cache-handler/.npmignore
- packages/cache-handler/src/helpers/create-validated-age-estimation-function.ts
- packages/cache-handler/src/helpers/is-tags-manifest.ts
- packages/cache-handler/src/helpers/promise-with-timeout.test.ts
- packages/cache-handler/src/helpers/create-validated-age-estimation-function.test.ts
- internal/typescript-config/lib.json
- packages/cache-handler/src/helpers/helpers.ts
- packages/cache-handler/src/lru-cache-next-adapter/cache-types/cache-string-value.ts
- packages/cache-handler/src/handlers/redis-stack.ts
- packages/cache-handler/src/helpers/is-implicit-tag.ts
- packages/cache-handler/src/handlers/experimental-redis-cluster.ts
🚧 Files skipped from review as they are similar to previous changes (28)
- apps/cache-testing/src/components/cache-state-watcher.tsx
- apps/cache-testing/src/components/restart-button.tsx
- apps/cache-testing/src/components/revalidate-button.tsx
- apps/cache-testing/src/utils/common-app-page.tsx
- apps/cache-testing/src/app/app/no-params/ssr/200/page.tsx
- apps/cache-testing/src/pages/pages/randomHex/[length].tsx
- apps/cache-testing/src/pages/layout.tsx
- apps/cache-testing/src/components/pre-rendered-at.tsx
- apps/cache-testing/src/pages/_app.tsx
- .github/dependabot.yml
- apps/cache-testing/src/instrumentation.ts
- apps/cache-testing/cache-handler-redis-stack.cjs
- internal/backend/package.json
- turbo.json
- apps/cache-testing/src/utils/common-pages-page.tsx
- biome.json
- apps/cache-testing/src/app/app/no-params/dynamic-true/[slug]/page.tsx
- apps/cache-testing/src/app/app/ppr/page.tsx
- apps/cache-testing/cache-handler-redis-stack.js
- .github/workflows/tests.yml
- apps/cache-testing/src/app/app/randomHex/[length]/page.tsx
- apps/cache-testing/src/app/layout.tsx
- apps/cache-testing/src/app/app/with-params/dynamic-true/[slug]/page.tsx
- internal/eslint-config/package.json
- apps/cache-testing/src/app/app/with-params/dynamic-false/[slug]/page.tsx
- packages/cache-handler/src/instrumentation/register-initial-cache.ts
- docs/cache-handler-docs/package.json
- package.json
🔇 Additional comments (64)
docs/cache-handler-docs/tsconfig.json (2)
4-7
: Paths Configuration Update: Transition to “cache-testing”.The paths mapping has been updated from its previous value (presumably
"cache-handler-docs/*"
) to"cache-testing/*": ["./src/*"]
to reflect the shift in focus. Please ensure that all import paths in the rest of the project have been updated accordingly so that there are no unresolved module errors.
8-8
: Update to "include" Array: Aligning with Next.js 15.The "include" array now includes
.next/types/**/*.ts
and has removed entries likenext.config.ts
to better match the Next.js 15 file structure. Verify that all necessary TypeScript files are still covered and that no critical files are inadvertently excluded from the compilation process.internal/backend/tsconfig.json (3)
2-2
: Ensure TSConfig base configuration update is intentional.
The change from@repo/typescript-config/base.json
to@repo/typescript-config/local.json
indicates a switch to a configuration intended for local development or specific project needs. Verify that any differences in settings between these two files align with your current TypeScript and Next.js 15 requirements.
3-3
: Confirm the include pattern covers all required files.
The updated"include": ["**/*.ts"]
will match all TypeScript files. If your project (or parts of it) uses TSX files (especially in a Next.js context), consider whether they should also be included (e.g.,"**/*.{ts,tsx}"
).
4-4
: Review exclusion settings for potential side effects.
Excluding only"node_modules"
means that directories likedist
(previously excluded) will now be processed. Verify that this change is intentional and that it won’t introduce unwanted files into the compilation process.internal/typescript-config/nextjs.json (2)
5-17
: Modern TypeScript Compiler Options Setup for Next.jsThe updated options (target, lib, allowJs, skipLibCheck, strict, noEmit, esModuleInterop, module, moduleResolution, resolveJsonModule, isolatedModules, jsx, and incremental) are well-aligned with a modern Next.js workflow. Please double-check that using
"target": "ES2017"
meets your application's browser support requirements and that"moduleResolution": "bundler"
is fully supported by your build pipeline.
18-22
: Next.js Plugin Declaration ValidatedThe plugins array correctly retains the Next.js plugin configuration. This minimal setup is appropriate; however, ensure that if additional plugins are needed later they follow the same structured schema.
apps/cache-testing/tsconfig.json (1)
3-7
: Review thepaths
configuration.
The"paths"
property mapping"cache-testing/*"
to"./src/*"
is clear and concise. There are no apparent issues here.packages/cache-handler/tsconfig.json (3)
1-3
: Validate schema addition and extends update.
Adding the"$schema": "https://json.schemastore.org/tsconfig"
property enhances editor support and configuration validation. Updating the"extends"
property to use"@repo/typescript-config/lib.json"
aligns with the new configurations. Please confirm that these changes are consistent with the intended configuration for packages in this repository.
4-7
: Review compiler options configuration.
The addition of"outDir": "dist"
and"rootDir": "src"
in thecompilerOptions
ensures that the build artifacts and source files are organized as expected. This setup is standard for library packages; no issues are observed here.
8-9
: Confirm file inclusion and exclusion patterns.
The updated"include": ["**/*.ts"]
ensures that only TypeScript files are processed, while"exclude": ["**/*.test.ts", "node_modules", "dist"]
explicitly omits test files and build outputs. This configuration should help maintain a clean build but ensure that no essential TSX or other file types are inadvertently omitted if they are needed.internal/typescript-config/local.json (6)
3-4
: Strengthen Node configuration with display and version properties.
The addition of"display": "Node 22"
and"_version": "22.0.0"
clearly signals the target environment and internal versioning for this configuration. Make sure that any tooling consuming this config recognizes and appropriately handles these fields.
6-7
: Modernize target and library settings.
Changing"target"
to"es2022"
and updating"lib"
to["es2024"]
ensures that the build is aligned with the latest ECMAScript features expected in your Node 22 environment. Verify that all downstream dependencies are compatible with these settings.
11-11
: Preserve module syntax for ES module compatibility.
The new setting"module": "preserve"
maintains the original module syntax, which is essential when leveraging native ES modules in Node 22. Confirm that build tools and bundlers in the codebase are configured to work with this preserved module structure.
13-13
: Enable strict type-checking.
Enabling"strict": true
enforces rigorous type safety, which will help catch errors early. This is a best practice in modern TypeScript projects.
15-15
: Require explicit override declarations.
The introduction of"noImplicitOverride": true
ensures that any method overrides are clearly marked, reducing potential mistakes in object-oriented code structures.
17-19
: Improve module resolution and isolation.
Adding"resolveJsonModule": true
,"isolatedModules": true
, and"verbatimModuleSyntax": true
enhances module handling by:
- Allowing JSON imports with type safety.
- Enforcing isolation to aid tooling and transpilation.
- Preserving the original module syntax without transformation.
Confirm that your current TypeScript version and build environment fully support these options.internal/eslint-config/next.js (5)
13-15
: Updated ESLint configuration to use flat config formatThe migration from traditional ESLint configuration array to the new flat config format using
tseslint.config()
is a significant upgrade. This change aligns with modern ESLint practices and better supports TypeScript integration.
19-25
: Well-structured language options configurationAdding explicit language options with proper globals from Node.js environment ensures consistent behavior across different environments where the code might run.
45-47
: Appropriate rule disabling for TypeScript projectsDisabling 'react/prop-types' is appropriate since TypeScript's static typing eliminates the need for React's PropTypes validation.
69-84
: Comprehensive unused variables configurationThis detailed configuration for
@typescript-eslint/no-unused-vars
provides a good balance between catching genuinely unused variables while allowing for common patterns like ignored parameters (prefixed with underscore).The configuration properly handles different contexts where variables might be intentionally unused:
- Function parameters
- Catch clause parameters
- Destructured array elements
- Regular variables
- Rest siblings in object destructuring
1-85
:✅ Verification successful
Verify compatibility with the project's TypeScript version
The ESLint configuration is now using typescript-eslint's flat config format, which requires a specific minimum version of TypeScript and ESLint.
🏁 Script executed:
#!/bin/bash # Check TypeScript and ESLint versions in the project echo "Checking package.json for TypeScript and ESLint versions:" find . -name "package.json" -not -path "*/node_modules/*" -exec grep -l "typescript\|eslint" {} \; | xargs cat | grep -E '"typescript"|"eslint"' | sort | uniqLength of output: 363
Project Compatibility Verified: TypeScript 5.7.3 and ESLint 9.21.0 Meet Requirements
The package.json output confirms that the project is using TypeScript 5.7.3 and ESLint 9.21.0. These versions satisfy the minimum requirements for the typescript-eslint flat config format, so no changes are required based on this review comment.
apps/cache-testing/src/app/app/no-params/dynamic-false/[slug]/page.tsx (3)
10-10
: Type update properly handles asynchronous params in Next.js 15The type update from
{ params: { slug: string } }
to{ params: Promise<{ slug: string }> }
aligns with Next.js 15's changes to how route parameters are handled.
16-16
: Return type change provides better type flexibilityChanging from
Promise<JSX.Element>
toPromise<React.ReactNode>
is more appropriate as it's the recommended return type for React components, offering better compatibility with different node types.
17-18
: Correctly handles asynchronous paramsThe code properly awaits the Promise-based params and uses the resolved value, which is the correct approach for Next.js 15's new parameter handling mechanism.
apps/cache-testing/src/utils/create-get-data.ts (5)
7-7
: Simplified cache parameter typeThe
cache
parameter type has been simplified fromRequestCache | 'unstable-cache' | 'nesh-cache'
to justRequestCache
, indicating the removal of custom caching strategies. This aligns with Next.js 15's improved built-in caching.
18-21
: Improved data fetching implementationThe implementation has been simplified to use the native
fetch
API with Next.js 15's caching options, removing complex custom caching logic. This approach is cleaner and leverages platform standards.
23-25
: Streamlined error handlingError handling has been simplified to a single check on the fetch response, which is sufficient for this use case and makes the code more maintainable.
27-28
: Direct response parsingParsing the JSON response directly from the fetch result simplifies the code by eliminating unnecessary intermediate variables and handling.
4-37
:❓ Verification inconclusive
Verify dependent files for cache removal compatibility
The removal of custom caching options ('unstable-cache' and 'nesh-cache') could impact dependent files that might still be using these options.
🏁 Script executed:
#!/bin/bash # Check for any usages of removed caching options in dependent files echo "Checking for usages of removed caching options..." rg -l "'unstable-cache'|'nesh-cache'" --type=ts --type=tsx apps/cache-testing/Length of output: 229
Action Required: Verify Dependent Files for Removed Cache Options
It looks like the initial shell command failed due to an unrecognized file type ("tsx"). To ensure that no dependent files in the
apps/cache-testing/
directory are still referencing the removed caching options, please run the updated verification script below:#!/bin/bash # Define file type for tsx and search for usages of removed caching options in .ts and .tsx files rg --type-add 'tsx:*.tsx' -l "'unstable-cache'|'nesh-cache'" -g "*.{ts,tsx}" apps/cache-testing/Once executed, manually verify that the search results return no hits. If any files are listed, please update them to remove or replace references to
'unstable-cache'
or'nesh-cache'
.apps/cache-testing/next.config.ts (4)
2-2
: Type import added for stronger typing.The addition of the NextConfig type enhances type safety in the configuration.
4-4
: Path updated from .mjs to .js for Next.js 15 compatibility.This change aligns with the module system transitions mentioned in the PR objectives, moving from ES module syntax (.mjs) to regular JavaScript files (.js).
6-6
: Added explicit type annotation for the config object.The configuration object is now properly typed as NextConfig, improving type safety and code clarity.
12-12
: Commented out outputFileTracingRoot that used import.meta.dirname.This configuration may need to be updated with a compatible approach for Next.js 15 if this functionality is still required.
Would you like me to verify if there's a recommended replacement for this configuration in Next.js 15?
packages/cache-handler/src/handlers/local-lru.ts (2)
1-2
: Imports updated to use relative paths with .js extensions.These changes replace package imports with relative paths, improving module resolution in ES modules.
4-5
: Import paths updated to include .js extensions.Adding explicit .js extensions to import paths is a common pattern for ES module compatibility, which aligns with Next.js 15 requirements.
packages/cache-handler/src/cache-handler.ts (7)
15-16
: Updated imports with .js extensions and added CachedRouteKind.Adding the CachedRouteKind enum import and using .js extensions in import paths improves type safety and module compatibility.
18-19
: Updated helper function imports with .js extensions.Consistent use of .js extensions in import paths for ES module compatibility.
442-442
: Replaced string literal with enum value.Using
CachedRouteKind.PAGES
instead of the string literal 'PAGE' improves type safety and maintainability.
897-904
: Updated conditional checks to use enum values.Using
CachedRouteKind
enum values instead of string literals improves type safety and makes the code more robust against typos.
910-910
: Simplified value assignment.Direct assignment of incrementalCacheValue without modification simplifies the code.
915-918
: Updated conditional check to use enum value.Consistent use of
CachedRouteKind.PAGES
enum value instead of string literals improves type safety.
832-832
:❓ Verification inconclusive
Default parameter value removed.
Removing the default value for the
ctx
parameter makes it a required parameter. Ensure all calling code passes this parameter to avoid runtime errors.
🏁 Script executed:
#!/bin/bash # Search for calls to get method without providing ctx parameter rg -A 5 'get\s*\(\s*[^,)]+\s*\)' --type tsLength of output: 3661
Action Required: Ensure All Calls to
CacheHandler#get
Explicitly Providectx
The change removing the default value for the
ctx
parameter leaves it as required. Our search for invocations using a lone parameter did not reveal any obvious cases where the new required argument is omitted. However, since the removal of the default could lead to runtime errors if any call sites were overlooked, please review all usages ofCacheHandler#get
—especially in less obvious contexts or integration flows—to ensure that a validctx
value is passed every time.
- Confirm that every call to the
get
method in the cache handler now correctly supplies thectx
parameter.- Re-run integration tests to catch any potential runtime issues related to this change.
packages/cache-handler/src/lru-cache-next-adapter/cache-types/next-cache-handler-value.ts (3)
2-5
: Updated imports for better structure and type safety.The import for CacheHandlerValue now also includes CachedRouteKind enum, which is used throughout the file for type-safe comparisons.
7-8
: Updated import paths with .js extensions.Consistent use of .js extensions in import paths for ES module compatibility.
17-40
: Updated switch cases to use enum values and added specific cases.Using
CachedRouteKind
enum values instead of string literals improves type safety. Adding specific cases for PAGES and APP_PAGE with tailored size calculations improves accuracy.packages/cache-handler/src/next-common-types.ts (6)
5-5
: Added CacheHandlerContext import for stronger typing.Good addition of the CacheHandlerContext type import, which is now used for the FileSystemCacheContext type definition below.
8-11
: Updated imports with explicit .js extensions.The import paths now include
.js
extensions, which aligns with Next.js 15's ESM support requirements. This is a necessary change for compatibility.
14-14
: Added explicit CacheHandler type export.Good addition to explicitly export the CacheHandler type, improving the module's public API.
22-24
: Updated export paths with .js extensions and added CachedRouteKind.The export with explicit
.js
extension and adding the CachedRouteKind enum export improves compatibility with Next.js 15's ESM requirements.
90-95
: Improved FileSystemCacheContext type definition.Good refactoring of the FileSystemCacheContext type to use Omit with CacheHandlerContext, which makes the type relationship more explicit while ensuring serverDistDir is properly typed as string.
134-134
: Replaced string literal with enum value.Replacing the string literal 'PAGE' with the enum value CachedRouteKind.PAGES improves type safety and maintainability.
packages/cache-handler/src/handlers/redis-strings.ts (4)
1-1
: Added superjson for improved serialization.Good addition of superjson, which provides better serialization/deserialization support than native JSON, especially for complex objects and special types like Date, Map, and Set.
3-8
: Updated import paths with .js extensions.The import paths now include
.js
extensions, aligning with Next.js 15's ESM support requirements.
71-71
: Replaced JSON.parse with superjson.parse.Good upgrade from JSON.parse to superjson.parse for better type preservation during deserialization.
119-119
: Replaced JSON.stringify with superjson.stringify.Good upgrade from JSON.stringify to superjson.stringify for better type preservation during serialization.
Also applies to: 132-132, 157-157, 192-192
apps/cache-testing/package.json (4)
6-6
: Added type:module for ESM support.Adding "type": "module" is necessary for Next.js 15 compatibility, which uses ESM by default.
8-9
: Updated build script and added type checking.Good improvements:
- Changed build script to use TypeScript instead of a shell script
- Added a dedicated type checking script
These changes improve the development experience and maintainability.
21-24
: Updated to Next.js 15 and React 19.Key dependency updates:
- Next.js 14.2.15 → 15.2.0
- React 18.3.1 → 19.0.0
- React DOM 18.3.1 → 19.0.0
These updates are essential for the PR's objective of supporting Next.js 15.
31-36
: Updated dev dependencies and added dotenv-cli.Good updates to development tools and dependencies to maintain compatibility with the latest versions.
packages/cache-handler/package.json (4)
26-29
: Simplified exports configuration for ESM.Good simplification of the exports field to use direct paths with
.js
extensions, which is more compatible with Next.js 15's ESM support.
32-34
: Switched from tsup to tsc for builds.Updated build scripts to use TypeScript's tsc compiler directly instead of tsup. This is a reasonable approach for simple TypeScript projects, though tsup can offer faster builds for larger projects.
39-41
: Added superjson dependency and updated others.Adding superjson as a dependency is consistent with the code changes in the handlers that now use it for improved serialization. Good use of caret ranges for semver compatibility.
50-50
: Updated Next.js peer dependency range.Updated the peer dependency to require Next.js 15, which is appropriate given the codebase changes specifically targeting Next.js 15 compatibility.
5a174d8
to
1421a1c
Compare
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: 1
🧹 Nitpick comments (6)
.vscode/settings.json (1)
1-44
: Overall Configuration Cleanup and Modernization
The updated settings file demonstrates a thoughtful cleanup:
- The explicit setting for the TypeScript SDK supports improved type safety and aligns with the ES module migration.
- Removal of outdated configuration settings (file nesting patterns and Grammarly selectors) streamlines the VS Code environment.
Ensure that these removals won’t adversely affect any specific developer tooling requirements.
packages/cache-handler/src/helpers/create-redis-timeout-config.ts (1)
25-31
: Consider adding input validation for negative timeout values.The function handles the case where
timeoutMs
is 0, but there's no check for negative values. WhileAbortSignal.timeout()
might handle negative values internally, adding explicit validation would make the function more robust and prevent potential issues.export function createRedisTimeoutConfig(timeoutMs: number): CommandOptions { + if (timeoutMs < 0) { + throw new Error('Timeout value cannot be negative'); + } if (timeoutMs === 0) { return commandOptions({}); } return commandOptions({ signal: AbortSignal.timeout(timeoutMs) }); }packages/cache-handler/src/utils/get-tags-from-headers.ts (1)
23-35
: Consider handling edge cases more explicitlyThe implementation handles array and string cases well but could be more explicit about other potential header value types.
Consider adding explicit handling for other potential header value types:
export function getTagsFromHeaders(headers: OutgoingHttpHeaders): string[] { const tagsHeader = headers['x-next-cache-tags']; if (Array.isArray(tagsHeader)) { return tagsHeader; } if (typeof tagsHeader === 'string') { return tagsHeader.split(','); } + // Handle potential buffer or number types that might come from headers + if (tagsHeader !== undefined && tagsHeader !== null) { + // Convert to string and handle as string + return String(tagsHeader).split(','); + } return []; }packages/cache-handler/src/handlers/local-lru.ts (3)
1-7
: Sort the import statements to fix pipeline failure.The pipeline reports that the import statements should be sorted. Adopting a consistent ordering practice generally places external libraries first, followed by local imports in alphabetical order. Consider applying this diff:
-import type { Handler } from '../cache-handler.js'; -import { NEXT_CACHE_IMPLICIT_TAG_ID } from '../next-common-types.js'; -import { - type CacheHandlerValue, - CachedRouteKind, -} from '../next-common-types.js'; -import { LRUCache } from 'lru-cache'; +import { LRUCache } from 'lru-cache'; +import type { Handler } from '../cache-handler.js'; +import { CachedRouteKind, type CacheHandlerValue, NEXT_CACHE_IMPLICIT_TAG_ID } from '../next-common-types.js';🧰 Tools
🪛 GitHub Actions: Tests
[error] 1-1: Import statements could be sorted.
9-44
: Consider caching stringified data to reduce repeated JSON.stringify calls.Each case calculates size by calling
JSON.stringify()
, which can be computationally expensive for large objects or frequent calls. A small optimization would be to store the stringified data in a local variable before returning its length:-function calculateObjectSize({ value }: CacheHandlerValue): number { - // Return default size if value is falsy - if (!value) { - return 25; - } - - switch (value.kind) { - case CachedRouteKind.REDIRECT: { - return JSON.stringify(value.props).length; - } - ... - } -} +function calculateObjectSize({ value }: CacheHandlerValue): number { + if (!value) { + return 25; + } + + switch (value.kind) { + case CachedRouteKind.REDIRECT: { + const strProps = JSON.stringify(value.props); + return strProps.length; + } + ... + } +}
132-197
: Optimize revalidateTag for large caches.Currently, the cache iteration in
revalidateTag
(for (const [key, { tags }] of lruCacheStore.entries())
) can become expensive when the cache grows large. Consider maintaining a tag-to-keys index or reference counting to avoid scanning every entry:- for (const [key, { tags }] of lruCacheStore.entries()) { - if (tags.includes(tag)) { - lruCacheStore.delete(key); - } - } + // Potential approach (requires maintaining a separate Map or multi-map of tag -> set of keys) + const keysWithTag = tagsToKeysIndex.get(tag) || []; + for (const key of keysWithTag) { + lruCacheStore.delete(key); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (30)
.vscode/settings.json
(2 hunks)apps/cache-testing/package.json
(2 hunks)apps/cache-testing/run-app-instances.ts
(1 hunks)docs/cache-handler-docs/src/app/usage/creating-a-custom-handler/page.mdx
(2 hunks)internal/typescript-config/test.json
(1 hunks)packages/cache-handler/package.json
(2 hunks)packages/cache-handler/src/cache-handler.ts
(5 hunks)packages/cache-handler/src/handlers/experimental-redis-cluster.ts
(9 hunks)packages/cache-handler/src/handlers/local-lru.ts
(1 hunks)packages/cache-handler/src/handlers/redis-stack.ts
(8 hunks)packages/cache-handler/src/handlers/redis-strings.ts
(11 hunks)packages/cache-handler/src/helpers/create-redis-timeout-config.ts
(1 hunks)packages/cache-handler/src/helpers/create-validated-age-estimation-function.test.ts
(0 hunks)packages/cache-handler/src/helpers/create-validated-age-estimation-function.ts
(0 hunks)packages/cache-handler/src/helpers/get-tags-from-headers.ts
(0 hunks)packages/cache-handler/src/helpers/get-timeout-redis-command-options.ts
(0 hunks)packages/cache-handler/src/helpers/helpers.ts
(1 hunks)packages/cache-handler/src/helpers/is-implicit-tag.ts
(0 hunks)packages/cache-handler/src/helpers/is-tag-implicit.ts
(1 hunks)packages/cache-handler/src/helpers/is-tags-manifest.ts
(0 hunks)packages/cache-handler/src/helpers/promise-with-timeout.test.ts
(0 hunks)packages/cache-handler/src/helpers/promise-with-timeout.ts
(0 hunks)packages/cache-handler/src/instrumentation/register-initial-cache.ts
(3 hunks)packages/cache-handler/src/next-common-types.ts
(3 hunks)packages/cache-handler/src/utils/compose-age-estimation-fn.ts
(1 hunks)packages/cache-handler/src/utils/get-tags-from-headers.ts
(1 hunks)packages/cache-handler/test/tsconfig.json
(1 hunks)packages/cache-handler/test/utils/compose-age-estimation-fn.test.ts
(1 hunks)packages/cache-handler/tsconfig.json
(1 hunks)packages/cache-handler/vitest.config.ts
(1 hunks)
💤 Files with no reviewable changes (8)
- packages/cache-handler/src/helpers/promise-with-timeout.ts
- packages/cache-handler/src/helpers/get-tags-from-headers.ts
- packages/cache-handler/src/helpers/create-validated-age-estimation-function.test.ts
- packages/cache-handler/src/helpers/create-validated-age-estimation-function.ts
- packages/cache-handler/src/helpers/is-tags-manifest.ts
- packages/cache-handler/src/helpers/promise-with-timeout.test.ts
- packages/cache-handler/src/helpers/get-timeout-redis-command-options.ts
- packages/cache-handler/src/helpers/is-implicit-tag.ts
✅ Files skipped from review due to trivial changes (4)
- packages/cache-handler/test/tsconfig.json
- apps/cache-testing/run-app-instances.ts
- packages/cache-handler/vitest.config.ts
- internal/typescript-config/test.json
🚧 Files skipped from review as they are similar to previous changes (7)
- packages/cache-handler/src/next-common-types.ts
- packages/cache-handler/src/handlers/redis-strings.ts
- packages/cache-handler/src/handlers/experimental-redis-cluster.ts
- packages/cache-handler/src/handlers/redis-stack.ts
- packages/cache-handler/src/instrumentation/register-initial-cache.ts
- packages/cache-handler/package.json
- apps/cache-testing/package.json
🧰 Additional context used
🪛 GitHub Actions: Tests
packages/cache-handler/test/utils/compose-age-estimation-fn.test.ts
[error] 3-3: Formatter would have printed the following content: import { composeAgeEstimationFn, getInitialExpireAge } from '../../src/utils/compose-age-estimation-fn.js';
packages/cache-handler/src/handlers/local-lru.ts
[error] 1-1: Import statements could be sorted.
🔇 Additional comments (28)
packages/cache-handler/src/helpers/is-tag-implicit.ts (1)
1-29
: Implementation looks solid and well-documented.This is a clean, focused implementation of a utility function that determines whether a tag is an implicit Next.js-generated tag. The thorough JSDoc documentation clearly explains the purpose, behavior, and provides helpful examples.
The function follows the single responsibility principle and has a clear, descriptive name that matches its purpose. The implementation is straightforward and correct, checking if the tag starts with the Next.js implicit tag identifier.
The import statement correctly uses the
.js
extension, which is appropriate for ES modules and aligns with Next.js 15 module resolution requirements.docs/cache-handler-docs/src/app/usage/creating-a-custom-handler/page.mdx (2)
21-21
: Update Import for Renamed FunctionThe import now correctly references the new helper function name
isTagImplicit
from@neshca/cache-handler/helpers
. This update aligns with the renaming changes across the codebase. Please verify that all references to this helper are updated in related files.
182-190
: Confirm Consistent Usage ofisTagImplicit
The function call in the
revalidateTag
method has been updated to useisTagImplicit(tag)
instead of the old name. This change appears to be correctly implemented, ensuring consistency with the helper’s new naming. Consider a quick review of the end-to-end cache revalidation flow to ensure that the behavior remains intact.packages/cache-handler/tsconfig.json (3)
2-3
: JSON Schema and Extends Update.
The addition of the$schema
property ("https://json.schemastore.org/tsconfig"
) enhances IDE support by enabling schema validation and autocompletion. Updating the"extends"
property to"@repo/typescript-config/lib.json"
aligns the configuration with the new TypeScript settings for Node.js 20.
5-6
: Compiler Options: outDir and rootDir Configuration.
Defining"outDir": "dist"
and"rootDir": "src"
clearly delineates the source files and the build output folder. This setup promotes consistency in the project’s build process. Ensure that the physical directory structure in the package reflects these settings.
8-9
: Include and Exclude Paths Improvement.
Switching the"include"
pattern to["**/*.ts"]
ensures only TypeScript files are compiled, and updating the"exclude"
array to omit"node_modules"
,"dist"
,"test"
, and"vitest.config.ts"
further refines the compilation scope. Verify that no essential files are unintentionally excluded..vscode/settings.json (2)
8-8
: Add explicit TypeScript SDK setting
The new"typescript.tsdk": "node_modules/typescript/lib"
entry ensures that VS Code uses the project’s locally installed TypeScript, which can improve consistency across development environments. Please confirm that this path matches your project structure and that all team members are aware of this change.
40-42
: Consistent Configuration for TypeScriptReact
The[typescriptreact]
block now only sets"editor.defaultFormatter": "biomejs.biome"
, harmonizing it with the other language settings. This change, along with removed configurations (such as file nesting patterns and Grammarly selectors), aligns the settings with the newer ES module and TypeScript setup. Verify that these removals do not impact your team's workflow if any previously relied on those options.packages/cache-handler/src/helpers/create-redis-timeout-config.ts (3)
1-4
: Well-structured imports and type definition.The use of
ReturnType<typeof commandOptions>
is a good practice for type safety. It ensures that the return type of the utility function stays in sync with any changes to the Redis package's API.
5-24
: Excellent documentation with clear examples.The JSDoc comments are comprehensive, well-structured, and include a helpful usage example that demonstrates how to use the function in practice. This kind of thorough documentation significantly improves developer experience and code maintainability.
25-31
:❓ Verification inconclusive
Verify browser compatibility of AbortSignal.timeout API.
The
AbortSignal.timeout()
method is relatively recent. If this code needs to run in environments that might not support this API, consider checking compatibility or providing a fallback.
🌐 Web query:
What is the browser compatibility for AbortSignal.timeout() and when was it introduced?
💡 Result:
The
AbortSignal.timeout()
method, introduced to simplify timeout handling in asynchronous operations like fetch requests, has varying browser support:Browser Compatibility
Browser Supported Versions Notes Chrome 103+ (Desktop/Android) Introduced in June 2022 [3] Edge 103+ Chromium-based versions [1] Firefox 100+ Supported since ~May 2022 [1] Safari 16.0+ (macOS/iOS) Requires macOS Ventura/iOS 16 [1][3] Opera 89+ Chromium-based versions [1] Samsung Internet 20+ [1] Key Details
- Unsupported browsers: Internet Explorer (all versions) and pre-2022 browsers like Chrome ≤102, Firefox ≤99, and Safari ≤15.6[1][7].
- Mobile support: Chrome for Android (129+), Firefox for Android (130+), and Safari iOS (16.0+)[1].
- Error handling: Throws
TimeoutError
DOMException on timeout, distinct from user-triggeredAbortError
[4][8].The method was first implemented in Chrome 103 (June 2022)[3], followed by Firefox 100 and Safari 16.0 later that year. It simplifies timeout logic by replacing manual
AbortController
+setTimeout
setups with a single static method[2][5].Citations:
- 1: https://caniuse.com/mdn-api_abortsignal_timeout_static
- 2: https://betterstack.com/community/guides/scaling-nodejs/understanding-abortcontroller/
- 3: https://developer.chrome.com/blog/new-in-chrome-103
- 4: https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout_static
- 5: https://dev.to/rashidshamloo/adding-timeout-and-multiple-abort-signals-to-fetch-typescriptreact-33bb
- 6: https://www.whitespectre.com/ideas/abortcontroller-api-javascript/
- 7: https://www.lambdatest.com/web-technologies/abortcontroller
- 8: whatwg/dom#1082
- 9: https://github.com/shaseley/abort-signal-any/blob/main/signal-memory-management.md
- 10: https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal
AbortSignal.timeout API Usage — Confirm Compatibility and Fallback Strategy
Based on recent browser data,
AbortSignal.timeout()
is supported in modern browsers—Chrome 103+, Firefox 100+, Safari 16.0+, Opera 89+, and Samsung Internet 20+—with its initial release around mid-2022. If your project targets only these environments (or Node.js versions that support it), the current implementation is acceptable. However, if legacy browser support (e.g., Internet Explorer or older versions of mainstream browsers) is required, please consider adding a fallback approach (such as using anAbortController
with a manualsetTimeout
).
- Action: Confirm that all environments running this code meet or exceed these compatibility thresholds.
- Fallback Consideration: If legacy support is needed, update the implementation accordingly.
packages/cache-handler/src/helpers/helpers.ts (1)
1-2
:✅ Verification successful
Module path update for ES Module compatibility
The module import paths now use explicit
.js
extensions, which is required for ES Module compatibility in Node.js. This change aligns with the PR objective of adding Next.js 15 support, which relies on ES Modules.Note that function naming has also changed from
isImplicitTag
toisTagImplicit
andgetTimeoutRedisCommandOptions
tocreateRedisTimeoutConfig
, indicating a refactoring of these utilities.
🏁 Script executed:
#!/bin/bash # Verify that the renamed functions are being used consistently across the codebase echo "Checking for any remaining references to old function names..." rg "isImplicitTag|getTimeoutRedisCommandOptions" --type ts echo "Checking usage of new function names..." rg "isTagImplicit|createRedisTimeoutConfig" --type tsLength of output: 5253
Module path and function renaming verified
The explicit
.js
extensions in the import statements and the renaming ofisImplicitTag
toisTagImplicit
andgetTimeoutRedisCommandOptions
tocreateRedisTimeoutConfig
have been successfully propagated across the codebase. The shell script verification confirmed that no legacy names remain and that the changes are consistently applied (e.g., in files underpackages/cache-handler/src/handlers/
).packages/cache-handler/src/utils/get-tags-from-headers.ts (1)
1-22
: Well-documented utility function with good examplesThe import and JSDoc comments are well-structured with clear descriptions and useful examples demonstrating both string and array header formats.
packages/cache-handler/src/utils/compose-age-estimation-fn.ts (2)
4-18
: Simple utility function with clear purposeThe
getInitialExpireAge
function has a clear purpose and good documentation explaining the rationale behind multiplying by 1.5.
20-60
: Well-designed composition function with thorough validationThe
composeAgeEstimationFn
function is well-structured with:
- Good default implementation
- Thorough validation of returned values
- Proper error handling with descriptive messages
- Clear JSDoc with examples
The code correctly handles edge cases by:
- Flooring floating point numbers
- Capping at MAX_INT32
- Validating positive integers
- Throwing informative assertion errors
This is a robust implementation that follows best practices.
packages/cache-handler/test/utils/compose-age-estimation-fn.test.ts (2)
1-69
: Comprehensive test suite for valid inputsThe tests thoroughly cover a wide range of valid inputs and edge cases:
- Simple callbacks
- Floating point handling
- MAX_INT32 boundary handling
- Default callback behavior
- Large values close to MAX_INT32
The tests are well-organized and include descriptive assertions that clearly document the expected behavior.
🧰 Tools
🪛 GitHub Actions: Tests
[error] 3-3: Formatter would have printed the following content: import { composeAgeEstimationFn, getInitialExpireAge } from '../../src/utils/compose-age-estimation-fn.js';
71-120
: Thorough testing of invalid inputs and error handlingThe test suite properly covers various error conditions:
- Negative values
- Non-integers
- Zero
- Non-numeric inputs
- Error propagation
- Infinity handling
This ensures the function will behave predictably and provide clear error messages when misused.
packages/cache-handler/src/handlers/local-lru.ts (3)
46-50
: Nicely implemented handoff to createConfiguredCache.
The delegation tocreateConfiguredCache
is clean and emphasizes single-responsibility. No concerns here.
57-74
: Option definitions look comprehensive.
TheLruCacheOptions
adequately covers typical usage scenarios, and the documentation is clear.
84-105
: The createConfiguredCache function is well-structured.
The generic extends an object or string, and the inline usage ofsizeCalculation
property is appropriate.packages/cache-handler/src/cache-handler.ts (8)
15-16
: Use ofCachedRouteKind
enum is appropriate.
Adopting the enumerated type fromnext-common-types.js
instead of string literals is a solid improvement for type safety and maintainability.
18-19
: Confirm ES module import extension behavior.
Importing.js
files in a.ts
file may require specific TypeScript configurations (e.g."moduleResolution": "NodeNext"
). Please ensure your build setup supports ESM imports with explicit.js
extensions.Would you like me to provide a script to grep for your tsconfig entries to confirm ESM readiness?
442-442
: Refactor from string literal to enum constant.
Replacing'PAGE'
withCachedRouteKind.PAGES
aligns the code with the enumerated types and reduces magic strings.
626-626
: Verify equivalent functionality of new age estimation function.
Switching tocomposeAgeEstimationFn
may change how expiration ages are calculated. Ensure no unintended side effects or discrepancies compared to the previous approach.If you prefer, I can help devise tests to confirm parity with the old function’s logic.
896-902
: Apply tags only toPAGES
andAPP_PAGE
cases.
UsinggetTagsFromHeaders
conditionally forCachedRouteKind.PAGES
orAPP_PAGE
is consistent with enumerated usage. No obvious issues.
909-909
: Storing the incremental cache value is correct.
Saving theincrementalCacheValue
directly into the.value
property is straightforward and maintains clarity.
914-917
: Confirm fallback false handling forAPP_PAGE
.
ForPAGES
, fallback false triggers file system writes. If you intend the same logic forAPP_PAGE
, consider adding an additional check (or combine the conditions). If it’s intentional to exclude, disregard.
831-831
:❓ Verification inconclusive
Mandatory
ctx
parameter may cause breaking changes.
Previously, callers could omit the second parameter. Now thatctx
is mandatory, confirm all call sites pass it in.Here’s a script to search for
.get(
calls that might be missing thectx
argument:
🏁 Script executed:
#!/bin/bash rg -A 2 "CacheHandler\.get\("Length of output: 31
ACTION: MANUALLY VERIFY ALL
CacheHandler.get
CALLS INCLUDE THE NEWctx
ARGUMENTThe automated search using the previous rg command (and our follow‐up with a PCRE2 regex) did not return any instances where
CacheHandler.get
is invoked with only one argument. However, because this result may be affected by formatting variations or other nuances in how the method is called, it’s best to double-check manually that no call site misses providing the mandatoryctx
parameter.
- Location of Change:
packages/cache-handler/src/cache-handler.ts
(line 831) now requires a non-optionalctx
parameter.- Action: Confirm throughout the repository that every invocation of
CacheHandler.get
explicitly passes thectx
parameter.Please verify this manually to ensure no regressions occur due to this breaking change.
import { MAX_INT32 } from '../../src/constants.js'; | ||
import { composeAgeEstimationFn, getInitialExpireAge } from '../../src/utils/compose-age-estimation-fn.js'; |
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 import formatting according to pipeline failure
There's a formatting issue with the import statement reported by the pipeline.
Fix the import formatting according to your style guidelines:
import { describe, expect, it } from 'vitest';
import { MAX_INT32 } from '../../src/constants.js';
-import { composeAgeEstimationFn, getInitialExpireAge } from '../../src/utils/compose-age-estimation-fn.js';
+import {
+ composeAgeEstimationFn,
+ getInitialExpireAge,
+} from '../../src/utils/compose-age-estimation-fn.js';
📝 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.
import { MAX_INT32 } from '../../src/constants.js'; | |
import { composeAgeEstimationFn, getInitialExpireAge } from '../../src/utils/compose-age-estimation-fn.js'; | |
import { MAX_INT32 } from '../../src/constants.js'; | |
import { | |
composeAgeEstimationFn, | |
getInitialExpireAge, | |
} from '../../src/utils/compose-age-estimation-fn.js'; |
🧰 Tools
🪛 GitHub Actions: Tests
[error] 3-3: Formatter would have printed the following content: import { composeAgeEstimationFn, getInitialExpireAge } from '../../src/utils/compose-age-estimation-fn.js';
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: 2
🔭 Outside diff range comments (1)
packages/cache-handler/src/handlers/local-lru.ts (1)
134-136
: 💡 Verification agent❓ Verification inconclusive
Verify integration with existing handler
The existing
createHandler
function now uses the updatedcreateCacheStore
function. Since this function signature has been preserved, the integration should work seamlessly. However, I recommend adding a test to verify that the cache behaves as expected with the new size calculation implementation.
🏁 Script executed:
#!/bin/bash # Check if there are any tests that verify the LRU cache's behavior fd -e test.ts -e spec.ts -e test.js -e spec.js -p "packages/cache-handler" | xargs grep -l "local-lru" | sortLength of output: 107
Action Required: Add Tests for LRU Cache Behavior
The integration of
createCacheStore
withcreateHandler
remains intact since the function signature is preserved. However, our search did not locate any test files referencing thelocal-lru
handler in thepackages/cache-handler
directory. To ensure that the new size calculation implementation behaves as expected, please add integration tests covering the LRU cache functionality.
🧹 Nitpick comments (15)
packages/cache-handler/src/instrumentation/register-initial-cache.ts (1)
7-7
: Consider a direct type import for simpler maintainability.
IfCacheHandler
is purely a type, you can directly import it by name usingimport type { CacheHandler }
to eliminate the dynamictypeof import()
approach. This can help with readability and reduce complexity if the module is statically referenced.apps/cache-testing/cache-handler-none.js (2)
1-19
: Consider adding documentation to explain purpose and usage of this no-op cache handler.The implementation of a "no-op" cache handler is clean and follows the expected interface pattern, with all methods properly returning resolved promises with
undefined
. This is valuable for testing scenarios where you want to disable caching completely.To improve maintainability:
- Add JSDoc comments explaining the purpose of this handler
- Document when this handler should be used versus other caching implementations
// @ts-check import { CacheHandler } from '@neshca/cache-handler'; +/** + * A no-op cache handler that doesn't perform any caching operations. + * Useful for testing scenarios or environments where caching should be disabled. + */ CacheHandler.onCreation(() => { return { handlers: [ { name: 'handler-none', + /** + * No-op get implementation + * @param {any} key - The cache key + * @returns {Promise<undefined>} Always returns undefined + */ get: () => Promise.resolve(undefined), set: () => Promise.resolve(undefined), revalidateTag: () => Promise.resolve(undefined), delete: () => Promise.resolve(undefined), }, ], }; }); export default CacheHandler;
8-14
: Consider implementing parameter types for better type safety.While the file uses
@ts-check
, adding explicit parameter types to the handler methods would improve type safety and make the expected interface clearer.{ name: 'handler-none', - get: () => Promise.resolve(undefined), - set: () => Promise.resolve(undefined), - revalidateTag: () => Promise.resolve(undefined), - delete: () => Promise.resolve(undefined), + get: (key) => Promise.resolve(undefined), + set: (key, value, options) => Promise.resolve(undefined), + revalidateTag: (tag) => Promise.resolve(undefined), + delete: (key) => Promise.resolve(undefined), },packages/cache-handler/src/cache-handler.ts (1)
883-883
: Simplified parameter destructuringThe destructuring syntax is more concise, improving code readability by clearly showing which properties are being extracted from the context object.
packages/cache-handler/src/handlers/local-lru.ts (1)
148-153
: Consider using the spread operator directly on the Set constructorThe code creates a combined set of tags by spreading arrays into a new Set. While this works correctly, you could simplify it by passing both arrays directly to the Set constructor.
- const combinedTags = new Set([ - ...cacheValue.tags, - ...sanitizedImplicitTags, - ]); + const combinedTags = new Set([...cacheValue.tags, ...sanitizedImplicitTags]);Alternatively, for even better performance with large arrays:
- const combinedTags = new Set([ - ...cacheValue.tags, - ...sanitizedImplicitTags, - ]); + const combinedTags = new Set(cacheValue.tags); + sanitizedImplicitTags.forEach(tag => combinedTags.add(tag));packages/cache-handler/src/use-cache/redis.ts (6)
15-44
: Consider supporting additional authentication and SSL options in RedisConfig.While this configuration covers the basics, some deployments may require username/password and SSL/TLS configuration. Extending the
RedisConfig
type to include these fields (or documenting how users can pass them viaclientOptions
) can improve flexibility for secure and production use cases.
63-75
: Add optional metadata to tag invalidation messages for debugging.Currently, the
TagInvalidationMessage
type includes basic fields. Adding optional context (e.g., the invalidation source or environment information) can simplify root-cause analysis in distributed caching environments.
202-234
: Handle large tag sets or partial loading to avoid potential memory issues.Loading all tags into
localTagsManifest.items
can lead to high memory usage if there are thousands of tags. Consider strategies like partitioning or partial loading from Redis, or pruning stale tags more aggressively, to keep memory consumption managed.
358-448
: Avoid storing very large streams entirely in memory before base64 encoding.Reading the entire stream into a buffer may be fine for smaller objects, but can degrade performance when dealing with large payloads. Consider streaming directly to Redis, chunk-by-chunk, or setting size limits on cacheable items to minimize memory usage.
455-510
: Consider concurrency and partial invalidation strategies for tagged data.When multiple clients attempt to invalidate overlapping tags, race conditions could arise if new tags are being added at the same time. Evaluating concurrency controls (e.g., Lua scripts or version checks) may keep data consistent in high-traffic scenarios.
527-530
: Use caution with the default export instantiating a global Redis client.Returning a default Redis handler instance can introduce unexpected side effects if multiple imports configure or reuse it differently. Encourage consumers to use
createRedisCacheHandler
directly if they need separate connections or custom configurations.apps/cache-testing/next.config.ts (1)
12-12
: Consider removing or explaining commented-out code.
If you no longer needoutputFileTracingRoot
, removing or clarifying this line will reduce clutter.- // outputFileTracingRoot: path.join(import.meta.dirname, '../../'),
apps/cache-testing/src/utils/create-get-data.ts (2)
24-24
: Suggestion: Add additional error handling to fetch.
Wrapping the fetch call with try/catch can offer more robust error diagnosis.- const result = await fetch(url); + let result; + try { + result = await fetch(url); + } catch (err) { + console.error('Fetch failed:', err); + return null; + }
26-27
: Minimal error checks.
Returning null is fine, but consider logging error details for debugging.apps/cache-testing/src/app/app/no-params/dynamic-true/[slug]/page.tsx (1)
8-8
: Hardcoded revalidate.
Consider reading from config or environment variables for flexibility.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (20)
apps/cache-testing/cache-handler-none.js
(1 hunks)apps/cache-testing/next.config.ts
(1 hunks)apps/cache-testing/redis.js
(1 hunks)apps/cache-testing/src/app/app/no-params/dynamic-false/[slug]/page.tsx
(1 hunks)apps/cache-testing/src/app/app/no-params/dynamic-true/[slug]/page.tsx
(1 hunks)apps/cache-testing/src/app/app/no-params/ssr/200/page.tsx
(1 hunks)apps/cache-testing/src/app/app/randomHex/[length]/page.tsx
(1 hunks)apps/cache-testing/src/app/app/with-params/dynamic-false/[slug]/page.tsx
(2 hunks)apps/cache-testing/src/app/app/with-params/dynamic-true/[slug]/page.tsx
(2 hunks)apps/cache-testing/src/utils/create-get-data.ts
(1 hunks)apps/cache-testing/tests/app.spec.ts
(1 hunks)apps/cache-testing/tests/pages.spec.ts
(1 hunks)packages/cache-handler/package.json
(2 hunks)packages/cache-handler/src/cache-handler.ts
(8 hunks)packages/cache-handler/src/handlers/experimental-redis-cluster.ts
(9 hunks)packages/cache-handler/src/handlers/local-lru.ts
(1 hunks)packages/cache-handler/src/instrumentation/register-initial-cache.ts
(3 hunks)packages/cache-handler/src/next-common-types.ts
(3 hunks)packages/cache-handler/src/use-cache/redis.ts
(1 hunks)packages/cache-handler/test/utils/compose-age-estimation-fn.test.ts
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- apps/cache-testing/redis.js
🚧 Files skipped from review as they are similar to previous changes (9)
- apps/cache-testing/tests/pages.spec.ts
- packages/cache-handler/src/handlers/experimental-redis-cluster.ts
- apps/cache-testing/src/app/app/with-params/dynamic-true/[slug]/page.tsx
- packages/cache-handler/src/next-common-types.ts
- apps/cache-testing/src/app/app/randomHex/[length]/page.tsx
- packages/cache-handler/test/utils/compose-age-estimation-fn.test.ts
- apps/cache-testing/src/app/app/with-params/dynamic-false/[slug]/page.tsx
- apps/cache-testing/src/app/app/no-params/dynamic-false/[slug]/page.tsx
- packages/cache-handler/package.json
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: redis-strings
- GitHub Check: redis-stack
🔇 Additional comments (37)
apps/cache-testing/tests/app.spec.ts (1)
144-144
:✅ Verification successful
The test description change correctly reflects the modified Next.js 15 caching behavior.
The updated test description now states the page should be fresh after "becoming stale and reloaded" instead of "becoming stale and reloaded twice". This aligns with the Next.js 15 caching model, which now requires only a single reload to observe fresh data after a cache entry becomes stale, rather than multiple reloads as in previous versions.
The test implementation appears consistent with this behavior change and follows good testing practices by validating the expected cache refresh pattern.
🏁 Script executed:
#!/bin/bash # Check if Next.js 15 is mentioned in package.json or other configuration files echo "Looking for Next.js version references:" grep -r --include="*.json" --include="*.md" "next\":" . | head -5Length of output: 416
Test description update for Next.js 15 caching behavior verified
The test now reads:
test(`Page should be fresh after becoming stale and reloaded ${path}`, async ({which correctly reflects that a single reload is sufficient for observing fresh data after staleness.
Verification confirms that the project uses Next.js version 15.2.0 in multiple packages (e.g., in
apps/cache-testing/package.json
), aligning with the behavior change described.The updated test description and implementation are consistent with the new caching model.
apps/cache-testing/src/app/app/no-params/ssr/200/page.tsx (2)
8-8
: Return type broadened appropriatelyChanging from
Promise<JSX.Element>
toPromise<React.ReactNode>
is a good practice that provides more flexibility in what the component can return. This aligns with Next.js 15's typing conventions and is consistent with other component updates in the project.
6-6
:❓ Verification inconclusive
Verify caching behavior change
The parameter in
createGetData
has been changed from using'no-store'
to0
, which likely alters the caching behavior of this component. Make sure this change is intentional and aligns with Next.js 15's caching expectations.
🏁 Script executed:
#!/bin/bash # Check implementation of createGetData to understand parameter impact echo "Searching for createGetData implementation..." fd -t f "create-get-data" --exec cat {}Length of output: 1083
Caching Behavior Verification: Confirm Revalidate Value
It appears that the caching parameter passed to
createGetData
has been updated from using'no-store'
to0
. In the implementation, this0
value is directly passed as therevalidate
parameter to Next.js’sunstable_cacheLife
. Please confirm that settingrevalidate
to0
aligns with Next.js 15’s caching expectations and achieves the intended caching strategy. Verify that this change does not inadvertently alter cache invalidation or data freshness compared to the previous behavior.packages/cache-handler/src/instrumentation/register-initial-cache.ts (3)
154-159
: Parallel file reading looks good—just ensure robust handling of JSON parse errors.
Reading.html
and.json
in parallel withPromise.all
is efficient. The fallback error handling is in place, so this approach should work well as long as the downstream logic anticipates possible missing or malformed JSON.
177-181
: Confirm consumers are aware of omitted headers and status.
You're now settingheaders
andstatus
toundefined
in the cache. Ensure that any consumers expecting headers or a status code can handle the absence of this data without raising errors. Consider adding a fallback or documenting this behavior in the public API.
3-5
:❓ Verification inconclusive
Confirm stability of internal Next.js imports.
Imports ofnext/constants.js
andnext/dist/build/index.js
rely on internal Next.js structures and may break with future releases if Next.js significantly refactors its internals. Consider verifying official guidance or adjusting to documented public exports to ensure compatibility with Next.js 15 and beyond.Would you like to run a quick search to confirm Next.js 15 includes stable references for these modules?
🏁 Script executed:
#!/bin/bash # Verify that next/constants.js and next/dist/build/index.js exist fd --glob 'node_modules/next/**/constants.js' fd --glob 'node_modules/next/**/build/index.js'Length of output: 97
Attention: Manual Verification Required for Next.js Internal Imports
The initial verification script did not yield output confirming the existence or stability of
next/constants.js
andnext/dist/build/index.js
. Since these imports depend on internal Next.js structures that may change in future releases, please manually verify the following:
- Confirm that these paths exist in your current Next.js version.
- Check the official Next.js documentation or release notes for guidance on using internal APIs.
- Consider switching to documented public exports to ensure future compatibility (especially for Next.js 15 and onward).
apps/cache-testing/cache-handler-none.js (1)
19-19
:❓ Verification inconclusive
Ensure this cache handler is properly tested.
Since this is a new file implementing a specific caching strategy (or lack thereof), verify that tests exist to confirm its behavior works as expected when integrated with Next.js.
🏁 Script executed:
#!/bin/bash # Check if there are tests for the none cache handler echo "Searching for tests related to the none cache handler..." rg -i "handler-none|cache-handler-none" --type js --type ts --type jsx --type tsxLength of output: 234
Action: Verify None Cache Handler Testing
It appears our initial test search for "cache-handler-none" encountered an error with the
jsx
file type flag. Please manually verify that tests exist for this new caching strategy and that they correctly cover its integration with Next.js. In particular, confirm that:
- Tests cover the expected behavior (or lack thereof) of the cache handler.
- Integration tests validate its functionality within the Next.js environment.
If tests are missing or insufficient, consider adding them to ensure comprehensive coverage.
packages/cache-handler/src/cache-handler.ts (8)
14-15
: Import paths updated to use .js extension for ES modules compatibilityThe import paths now include explicit
.js
extensions, which is required for proper ES module resolution in Next.js 15. This change aligns with the ECMAScript modules specification.
440-440
: Improved type safety using enumeration instead of string literalReplacing the string literal
'PAGE'
with the enum valueCachedRouteKind.PAGES
improves type safety and maintainability by preventing typos and providing better IDE support.
831-833
: Added type-safe check for page router kindThe new check for
ctx?.kind !== IncrementalCacheKind.PAGES
early returns for non-Pages router content. This improves the method's clarity by explicitly handling only supported router types.
868-870
: Added type-safe check for cache value kindSimilar to the get method, the set method now explicitly checks for
incrementalCacheValue?.kind !== CachedRouteKind.PAGES
and early returns for unsupported kinds. This improves type safety and makes the behavior more predictable.
898-903
: Refactored cache value creation for improved clarityThe restructured cache value definition is more concise and clear. Using
as const
also provides better type safety by ensuring the object's properties are read-only.
915-917
: Simplified revalidateTag implementationThe
revalidateTag
method has been simplified to return an empty promise with a comment indicating it's not implemented yet. This is acceptable for a work-in-progress PR, but should be properly implemented before final release.Is this intentional as part of the Next.js 15 migration? Consider whether this functionality needs to be implemented before the migration is complete, as it may affect applications relying on tag-based revalidation.
17-17
:❓ Verification inconclusive
Function replacement for age estimation
The
composeAgeEstimationFn
utility has been introduced to replace the previous age estimation implementation. This appears to be part of the ES modules update.
🏁 Script executed:
#!/bin/bash # Look for the implementation of composeAgeEstimationFn to verify its behavior matches the previous function fd "compose-age-estimation-fn.js" --type f --exec cat {} \;Length of output: 62
Action Required: Verify the presence of the replacement utility implementation
The import update in
packages/cache-handler/src/cache-handler.ts
now points to:import { composeAgeEstimationFn } from './utils/compose-age-estimation-fn.js';Our automated search did not locate a file named
compose-age-estimation-fn.js
anywhere in the repository. Please verify manually that:
- The file exists at the expected location (
packages/cache-handler/src/utils/compose-age-estimation-fn.js
).- It contains the intended replacement logic for the previous age estimation implementation.
Once confirmed, we can confidently approve the change.
624-624
:❓ Verification inconclusive
Updated age estimation function implementation
The previous
createValidatedAgeEstimationFunction
has been replaced withcomposeAgeEstimationFn
from a new utility file. Make sure the new implementation maintains the same behavior or improves upon it.
🏁 Script executed:
#!/bin/bash # Compare the old and new implementation of the age estimation functions rg -A 10 "createValidatedAgeEstimationFunction" --type tsLength of output: 57
Updated age estimation function implementation replacement
The oldcreateValidatedAgeEstimationFunction
is no longer present in the codebase and has been fully replaced bycomposeAgeEstimationFn
as seen on line 624. Although the absence of references suggests the transition is complete, please manually verify that:
- Behavior Consistency: The new utility function retains the age estimation logic (or improves upon it) compared to the old implementation.
- Test Coverage: Existing tests for cache expiration behave as expected with the new function.
packages/cache-handler/src/handlers/local-lru.ts (6)
1-7
: Import statements updated for ES module compatibilityThe import statements have been properly updated to use ES module syntax with explicit
.js
extensions. This change aligns with the project's migration from CommonJS to ES modules as mentioned in the PR summary.
9-44
: Well-structured size calculation function with comprehensive case handlingThe
calculateObjectSize
function provides a systematic approach to calculating cache entry sizes based on their kind. The implementation handles eachCachedRouteKind
case appropriately:
- Provides a default size (25) for falsy values
- Calculates string length for redirects and fetches
- Handles special cases for pages and app routes
- Explicitly prevents image caching through error throwing
- Falls back to zero size for unhandled cases
This granular approach to size calculation will help manage memory usage more effectively.
46-50
: Simplified cache store creation with better compositionThe
createCacheStore
function has been refactored to leverage the newcreateConfiguredCache
utility function, which improves code organization and reusability. This separation of concerns allows for easier maintenance going forward.
52-74
: Well-documented type definition with appropriate defaultsThe
LruCacheOptions
type has comprehensive JSDoc comments that clearly document the purpose, defaults, and version information for each option. This level of documentation significantly improves developer experience and code maintainability.
76-82
: Constants for default cache configurationExtracting the cache configuration values into named constants improves code readability and maintainability. The values (1000 items and 100MB max size) seem reasonable defaults for a local LRU cache.
84-105
: Generic cache configuration utility with flexible size calculationThe
createConfiguredCache
function is a well-designed utility that:
- Accepts a generic type parameter for the cache value type
- Takes a callback function for size calculation
- Uses parameter destructuring with defaults for clean option handling
- Properly configures the LRUCache with the provided options
This implementation provides flexibility while maintaining type safety, making it easier to create different types of caches with custom size calculations.
packages/cache-handler/src/use-cache/redis.ts (1)
291-356
:✅ Verification successful
Verify usage of
performance.timeOrigin + performance.now()
in Node.js.Some Node.js versions may not fully support the global
performance
API in the same way as browsers do. This might cause unexpected results or undefined behavior in older environments.
🌐 Web query:
Is the global performance API, specifically timeOrigin and now(), reliably supported in Node.js 18+ and Next.js 15?
💡 Result:
The global Performance API, including
timeOrigin
andnow()
, is reliably supported in Node.js 18+ and Next.js 15, with some nuances to consider:
Node.js 18+ Support
performance.timeOrigin
- Added in Node.js 16.0.0 and stable in later versions, including Node.js 18+ [9][10].
- Returns a high-resolution timestamp representing the start of the current process, similar to browser behavior.
performance.now()
- Part of the
perf_hooks
module, available since Node.js 8.5.0.- In Node.js 18+, it uses a monotonic clock (not affected by system time changes) for reliability [2][9].
Global Scope
- Unlike browsers, Node.js requires importing
perf_hooks
for full access:const { performance } = require('perf_hooks'); // or in ESM: import { performance } from 'node:perf_hooks';- Some methods (e.g.,
timeOrigin
) are directly available globally in newer versions [9].
Next.js 15 Support
Next.js 15 inherits Node.js 18+ compatibility but has specific considerations:
App Router vs. Edge Runtime
- In standard App Router (Node.js runtime),
performance.timeOrigin
andnow()
work as expected.- In Edge Runtime (e.g., middleware), Node.js APIs like
perf_hooks
are not supported [8]. Use browser-compatible APIs instead.Metrics in Server Components
Next.js 15 introducesunstable_after
for executing code post-response, which can be used withperformance.now()
:import { unstable_after as after } from 'next/server'; export default function Page() { const start = performance.now(); // ... logic after(() => { const duration = performance.now() - start; console.log(`Task took ${duration}ms`); }); return <div>Content</div>; }This avoids blocking responses while capturing performance data [4][7].
Key Considerations
Feature Node.js 18+ Next.js 15 (Node) Next.js 15 (Edge) performance.now()
✅ Yes ✅ Yes ❌ No performance.timeOrigin
✅ Yes ✅ Yes ❌ No Monotonic Clock ✅ Yes ✅ Yes ❌ No For Edge Runtime, use the Web Performance API (
window.performance
in browsers) or platform-specific alternatives likeDate.now()
[8][10].
Summary: Node.js 18+ and Next.js 15 fully support
performance.timeOrigin
andnow()
in Node.js environments, but Edge Runtime in Next.js restricts access to Node.js-specific APIs. Always verify the runtime context when using performance metrics.Citations:
- 1: https://www.nearform.com/insights/whats-new-in-node-js-18/
- 2: https://developer.mozilla.org/en-US/docs/Web/API/Performance/timeOrigin
- 3: https://nextjs.org/blog/next-15
- 4: https://docs.getunleash.io/reference/sdks/next-js
- 5: https://sdtimes.com/softwaredev/node-js-18-available-with-fetch-api-enabled-by-default/
- 6: https://forum.serverless.com/t/ci-cd-issue-for-node-18-x-runtime/18211
- 7: https://nextjs.org/blog/next-15-rc2
- 8: https://answers.netlify.com/t/404-on-all-pages-of-a-next-js-application-with-app-router-setup/93605
- 9: https://nodejs.org/en/blog/announcements/v18-release-announce
- 10: parcel-bundler/parcel#9530
Confirmed: Global
performance
API usage is reliable in our Node.js environment.
- The web query confirms that both
performance.timeOrigin
andperformance.now()
are fully supported in Node.js 18+ and in Next.js 15 when running in the standard Node environment.- Since the cache handler is expected to run on a Node server, the current usage is safe.
- Note: If this code were to run in a Next.js Edge Runtime context, alternative approaches would be required. However, as it stands, no changes are needed.
apps/cache-testing/next.config.ts (4)
2-2
: Use of NextConfig import.
No issues; this addition strengthens type safety.
6-6
: Typed configuration is a good practice.
Definingconst nextConfig: NextConfig
increases clarity and maintainability.
18-21
:✅ Verification successful
Ensure path consistency for caching logic.
Double-check that'./redis.js'
is correct and not meant to referencecache-handler-redis-stack.js
.
🏁 Script executed:
#!/bin/bash # Searching for redis.js in the repo fd "redis.js"Length of output: 41
Verified: The caching handler path is correct.
The fileredis.js
exists inapps/cache-testing
as expected, so referencing'./redis.js'
innext.config.ts
is valid. No changes are needed.
4-4
:✅ Verification successful
Verify that the specified file path exists.
Ifcache-handler-redis-stack.js
is not guaranteed to exist, please confirm and adjust accordingly.
🏁 Script executed:
#!/bin/bash # Searching for cache-handler-redis-stack.js in the repo fd "cache-handler-redis-stack.js"Length of output: 81
Verified file path exists:
The filecache-handler-redis-stack.js
is confirmed to exist atapps/cache-testing/cache-handler-redis-stack.js
. Since this path is correct relative toapps/cache-testing/next.config.ts
, no changes are necessary.apps/cache-testing/src/utils/create-get-data.ts (8)
8-8
: Simplified function signature looks good.
Removing cache strategy parameters reduces complexity and centralizes caching logic.
12-12
: 'use cache' directive.
This directive is typically for Next.js server-side caching. Confirm it matches your intended caching behavior.
14-14
: No immediate concerns.
ConstructingpathAndTag
withnormalizeSlug
is clear and straightforward.
16-18
: Cache revalidation approach approved.
UsingcacheLife
with a dynamicrevalidate
is a solid pattern for precise control.
20-20
: Tagging with cacheTag.
Straightforward usage; no issues identified.
22-22
: Constructing local fetch URL.
No concerns; the approach is conventional for local service calls.
30-30
: JSON parsing successfully integrated.
No issues; looks correct.
1-4
:❓ Verification inconclusive
Confirm the stability of 'unstable_cacheLife' & 'unstable_cacheTag'.
Their naming suggests experimental APIs. Please verify they are safe for your production environment.
🌐 Web query:
Are next/cache's unstable_cacheLife and unstable_cacheTag APIs stable in Next.js 15?
💡 Result:
Next.js 15 introduces significant caching improvements, but the
unstable_cacheLife
andunstable_cacheTag
APIs remain experimental and are not yet stable. Here's a breakdown:Key Points
Experimental Status
- Both APIs are marked as unstable and require enabling the
dynamicIO
experimental flag innext.config.js
[4][10].- They are currently available in the canary channel and subject to change[4][10].
Replacement for
unstable_cache
- The
unstable_cache
API (deprecated in v15) is being phased out in favor of theuse cache
directive, which integrates withcacheLife
andcacheTag
[1][4].- Example using the new pattern:
'use cache' import { unstable_cacheLife as cacheLife } from 'next/cache' export default async function Page() { cacheLife('hours') // Configures cache lifetime return <div>Page</div> }Caching Configuration
cacheLife
allows setting predefined or custom cache profiles (e.g.,seconds
,days
) for granular control[4].cacheTag
enables cache invalidation viarevalidateTag
[4].Current Limitations
- The
dynamicIO
flag (required for these APIs) is only available in canary builds[10].- Stability timelines are unclear, with ongoing community feedback shaping the APIs[3][10].
Recommendations
- For production, continue using
unstable_cache
untiluse cache
stabilizes.- Monitor Next.js canary releases and official documentation for updates[4][10].
In summary, while these APIs offer powerful caching customization, they are not yet stable and should be used cautiously in non-canary environments.
Citations:
- 1: https://nextjs.org/docs/app/api-reference/functions/unstable_cache
- 2: vercel/next.js#54075
- 3: https://hackernoon.com/nextjs-v15-reflecting-on-previous-mistakes
- 4: https://nextjs.org/docs/app/api-reference/functions/cacheLife
- 5: https://nextjs.org/blog/next-15
- 6: https://nextjs.org/docs/app/building-your-application/caching
- 7: vercel/next.js#75462
- 8: https://www.youtube.com/watch?v=-FMwdg2wx4M
- 9: https://blog.logrocket.com/caching-next-js-unstable-cache/
- 10: vercel/next.js#72101
Caution on Using Experimental Caching APIs
We've confirmed that both
unstable_cacheLife
andunstable_cacheTag
remain experimental in Next.js 15. These APIs require enabling thedynamicIO
experimental flag and are only available on canary builds, so they are not recommended for production unless you thoroughly validate their behavior. Consider evaluating stable alternatives—such as continuing with the deprecatedunstable_cache
or migrating to the newuse cache
directive—until these APIs are officially stabilized.apps/cache-testing/src/app/app/no-params/dynamic-true/[slug]/page.tsx (3)
10-10
: Promised params approach.
Be certain this pattern is valid in your Next.js version; dynamic route params are often plain objects, not promises.
12-12
: Correct usage of createGetData.
Passingrevalidate
to unify caching logic is consistent with your design.
16-18
: Asynchronous parameter resolution.
Awaiting the promise forparams
works, though it's an unusual pattern. Confirm your route definitions align with this structure.
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: 0
🔭 Outside diff range comments (1)
packages/cache-handler/src/instrumentation/register-initial-cache.ts (1)
29-63
: 🛠️ Refactor suggestionFunction documentation is outdated.
The function documentation still mentions populating the cache with "routes" and "fetch calls" (lines 34-35), along with a
fetch
option (line 41) and aroutes
option (line 45), but according to the implementation these features have been removed.Update the documentation to accurately reflect the current functionality. Here's a suggested change:
/** * Populates the cache with the initial data. * * * By default, it includes the following: * - Pre-rendered pages - * - Routes - * - Fetch calls * * * @param CacheHandler - The configured CacheHandler class, not an instance. * * * @param [options={}] - Options for the instrumentation. See {@link RegisterInitialCacheOptions}. * * - * @param [options.fetch=true] - Whether to populate the cache with fetch calls. * * @param [options.pages=true] - Whether to populate the cache with pre-rendered pages. * - * @param [options.routes=true] - Whether to populate the cache with routes. * * @example file: `instrumentation.ts` * * ```js * export async function register() { * if (process.env.NEXT_RUNTIME === 'nodejs') { * const { registerInitialCache } = await import('@neshca/cache-handler/instrumentation'); * // Assuming that your CacheHandler configuration is in the root of the project and the instrumentation is in the src directory. * // Please adjust the path accordingly. * // CommonJS CacheHandler configuration is also supported. * const CacheHandler = (await import('../cache-handler.mjs')).default; * await registerInitialCache(CacheHandler); * } * } * ``` * * @since 1.7.0 */
🧹 Nitpick comments (5)
packages/cache-handler/src/instrumentation/register-initial-cache.ts (2)
18-27
: Documentation needs updating to reflect removed options.The RegisterInitialCacheOptions type has been simplified to only include the
pages
option, but the function documentation (lines 29-63) still mentionsfetch
androutes
options which have been removed from the implementation.Please update the function documentation to reflect the current available options.
56-56
: The example code should use.js
extension.The example in the documentation shows importing from
'../cache-handler.mjs'
, but with the migration to ES modules, this should probably use the.js
extension to be consistent with the rest of the codebase.- const CacheHandler = (await import('../cache-handler.mjs')).default; + const CacheHandler = (await import('../cache-handler.js')).default;packages/cache-handler/src/cache-handler.ts (3)
886-886
: Minor naming nitpick.
neshca_lastModified
is a bit unconventional. If it's a shared field, consider using a more general name likelastModifiedIdentifier
.
903-908
: Consider the usage of empty tags.
Iftags
remain permanently empty, you could make them optional or remove them to reduce clutter. Otherwise, this is fine if you plan to add tags later.
920-921
:revalidateTag
not implemented.
Currently a placeholder. Let me know if you’d like assistance implementing this method.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/cache-handler/src/cache-handler.ts
(8 hunks)packages/cache-handler/src/instrumentation/register-initial-cache.ts
(3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: redis-strings
- GitHub Check: redis-stack
🔇 Additional comments (14)
packages/cache-handler/src/instrumentation/register-initial-cache.ts (4)
3-5
: Import paths updated for Next.js 15 compatibility.The import paths have been updated to include
.js
extensions, which is consistent with ES module syntax required by Next.js 15. The imports have also been reorganized to use the new type structure.
7-7
: Updated CacheHandlerType import path for ES modules.The import path for CacheHandlerType has been updated to include the
.js
extension for ES module compatibility.
154-159
: Improved Promise.all pattern for file reading.The Promise.all pattern with immediate JSON parsing looks good for concurrent file reading operations.
177-187
: Replaced string literals with enum and updated cache structure.Good improvements:
- Replaced hardcoded 'PAGE' string with CachedRouteKind.PAGES enum
- Explicitly set headers and status to undefined
- Updated the cache options structure
These changes make the code more maintainable and type-safe.
packages/cache-handler/src/cache-handler.ts (10)
14-15
: Imports approved.
These import statements correctly bring inCachedRouteKind
andIncrementalCacheKind
from the shared types file. No concerns here.
17-17
: New utility import looks good.
ImportingcomposeAgeEstimationFn
is straightforward and matches usage below.
624-624
: Verify behavior whenestimateExpireAge
is undefined.
Ensure thatcomposeAgeEstimationFn
handles a missing or undefined parameter gracefully, preventing runtime errors or unexpected behavior.Would you like me to generate a script that searches for usage of
ttl.estimateExpireAge
to confirm it is never called with invalid inputs?
829-830
: [Duplicate] Thectx
parameter is now mandatory.
This reaffirms the previous breaking change comment about requiringctx
. Ensure that all call sites now supply this parameter without relying on a default.
831-833
: Confirm null return for non-PAGES requests.
Returningnull
ifctx.kind
is notIncrementalCacheKind.PAGES
may disregard other valid cache scenarios. Verify this is intentional.
835-835
: Configuration call looks good.
Invoking#configureCacheHandler()
before proceeding ensures that the handler is properly set up.
848-848
: Implicit tags array is acceptable.
Storing an empty array forimplicitTags
is reasonable if you plan to populate it in the future.
869-874
: Validate non-caching condition.
Skipping cache whenincrementalCacheValue.kind !== PAGES
orctx.fetchCache === true
might exclude some valid use cases. Confirm that conditional is correct.
888-888
: Revalidate extraction is straightforward.
Extractingrevalidate
fromcacheControl
is clear and maintains readability.
912-912
: Good fallback check.
Writing pages to the file system upon fallback expansion appears correct for pages router behavior.
339d5c0
to
7135e65
Compare
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: 0
🧹 Nitpick comments (1)
packages/cache-handler/src/cache-handler.ts (1)
920-921
:revalidateTag
remains unimplemented.
Would you like assistance drafting an implementation that iterates over handlers or extends the existing revalidation logic?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/cache-testing/tests/pages.spec.ts
(1 hunks)packages/cache-handler/src/cache-handler.ts
(8 hunks)packages/cache-handler/src/instrumentation/register-initial-cache.ts
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/cache-testing/tests/pages.spec.ts
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: redis-strings
- GitHub Check: redis-stack
🔇 Additional comments (16)
packages/cache-handler/src/instrumentation/register-initial-cache.ts (7)
3-5
: Import path updates for ES Module syntax complianceThe import paths have been updated to include file extensions as required by ES modules syntax:
next/constants.js
instead ofnext/constants
next/dist/build/index.js
instead ofnext/dist/build
- Changed from
@repo/next-common
to a relative path../next-common-types.js
These changes align with the NextJS 15 move toward native ES modules.
7-7
: Updated import path for CacheHandlerTypeThe type import now includes the
.js
extension for ES module compatibility.
154-159
: Improved Promise handling in setPageCacheThe Promise.all implementation has been refined with proper chaining of the JSON parse operation. This is a cleaner approach that properly handles the parsing step.
177-177
: Using enum instead of hardcoded stringChanged from hardcoded string 'PAGE' to use the
CachedRouteKind.PAGES
enum value. This is a good practice for type safety and maintainability.
180-187
: Simplified cache structure and metadata handlingThe cache structure has been simplified:
- Headers and status are now explicitly set to undefined instead of using metadata
- Cache options are now more explicitly structured with
neshca_lastModified
,fetchCache
, andcacheControl
parametersThis change aligns with the removal of metadata handling and route caching functionality, creating a more streamlined approach.
64-211
: Verification needed for removed route cache functionalityThe overall function has been significantly simplified by removing the route caching and fetch cache management functionality. Based on the PR objective for Next.js 15 support, please ensure that these removals are intentional and that the functionality is either no longer needed or implemented elsewhere.
The documentation comments at the top of the function (lines 30-36) still mention that this populates routes and fetch calls, which are no longer supported. Please update the documentation to reflect the current functionality.
18-27
:❓ Verification inconclusive
API simplification in RegisterInitialCacheOptions
The options type has been simplified by removing the previously available
fetch
androutes
properties, leaving only thepages
option. This matches the documentation comments that were left intact and aligns with the apparent codebase simplification.Make sure that all consumers of this API have been updated to no longer pass the removed options.
🏁 Script executed:
#!/bin/bash # Search for any imports and usages of registerInitialCache that might still pass the removed options rg -A 3 -B 3 "registerInitialCache.*\{" --type ts --type jsLength of output: 61
Action Required: Perform Additional Manual Verification for Removed Options
The updated
RegisterInitialCacheOptions
type now only allows thepages
option, with thefetch
androutes
properties intentionally removed. Our automatedrg
search didn’t return any results for consumers still passing these removed options. However, since the command did not yield output and the inference quality is low, please manually verify that there are no residual usages of the removed options in the codebase—especially in less common scenarios or test files that might not match the initial pattern.
- Ensure that all invocations of
registerInitialCache
across the repository no longer passfetch
orroutes
.- Double-check unit and integration tests for any references to these deprecated options.
- Confirm that the documentation and usage examples have been updated accordingly.
packages/cache-handler/src/cache-handler.ts (9)
14-17
: Imports look good and remain consistent with the enumerations.
No issues flagged; this helps align with the typed constants across the codebase.
624-624
: Switch tocomposeAgeEstimationFn
is valid and consistent.
This refactor follows the new approach for estimating expiration ages.
829-833
: Ensure correctness with mandatoryctx
parameter and non-PAGES fallback.
This snippet now returnsnull
ifctx?.kind
isn'tPAGES
. Confirm that all.get()
call sites pass the properctx
(as previously recommended) and that ignoring non-PAGES entries is the intended behavior.
835-835
: Configuration call appears logically placed.
Invoking#configureCacheHandler()
only forPAGES
is clear and consistent.
848-848
: DefaultingimplicitTags
to an empty array is consistent with the metadata definition.
No concerns.
868-874
: Confirm exclusion of non-PAGES orfetchCache
items from caching.
This conditional short-circuits storing any data that isn’tPAGES
or ifctx.fetchCache
is true. Verify that this is the correct and desired behavior.
887-887
: Parameter destructuring looks correct.
Extractingneshca_lastModified
andcacheControl
matches the new property usage.
903-908
: Object construction for the cache entry is appropriately updated.
Storingtags: []
andvalue: incrementalCacheValue
aligns with the new enumerated approach forPAGES
.
912-912
: Conditionally writing pages to disk based onfallback: false
is consistent.
This ensures file system caching is only applied where needed.
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: 1
🧹 Nitpick comments (4)
.vscode/settings.json (1)
8-8
: Explicit TypeScript SDK Path Configuration Added
The new entry"typescript.tsdk": "node_modules/typescript/lib"
ensures that VS Code uses your project's locally installed TypeScript version. Please verify that this relative path correctly points to the intended TypeScript SDK directory in your repository.packages/cache-handler/src/cache-handler.ts (3)
838-838
: Configuring the cache before fetching is sensible.
Be mindful of any performance overhead if this is invoked repeatedly. You might consider caching the configuration after the first invocation.
863-868
: Consider refactoring fallback logic to avoid duplication.
Currently, page data is read again ifctx.isFallback
is true. You can combine this logic with the check at line 855 for a cleaner flow.if (CacheHandler.#fallbackFalseRoutes.has(cacheKey) || ctx.isFallback) { cachedData = await CacheHandler.#readPagesRouterPage( cacheKey, - false, + !!ctx.isFallback ); }
930-931
:revalidateTag()
remains unimplemented.
We can help finalize a tag-based invalidation mechanism if needed. Let me know if you'd like to open an issue to track implementing this method.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
.vscode/settings.json
(2 hunks)apps/cache-testing/tests/pages.spec.ts
(0 hunks)packages/cache-handler/src/cache-handler.ts
(10 hunks)packages/cache-handler/src/use-cache/redis.ts
(1 hunks)turbo.json
(2 hunks)
💤 Files with no reviewable changes (1)
- apps/cache-testing/tests/pages.spec.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- turbo.json
- packages/cache-handler/src/use-cache/redis.ts
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: redis-strings
- GitHub Check: redis-stack
🔇 Additional comments (15)
.vscode/settings.json (2)
43-45
: New HTML Default Formatter Configuration Added
The addition of the[html]
section with"editor.defaultFormatter": "esbenp.prettier-vscode"
aligns HTML formatting with your updated project standards. Ensure that this formatter matches your team’s expectations and that any HTML files are consistently formatted.
1-7
: General Configuration Cleanup and Consistency Check
The removal of previous configurations (such asexplorer.fileNesting.patterns
andgrammarly.selectors
) appears intentional based on the broader project updates toward modern JavaScript/TypeScript practices. Please double-check that these removals do not impact any existing workflows or extensions your team relies on.Also applies to: 9-42
packages/cache-handler/src/cache-handler.ts (13)
14-15
: Adoption of enumerations fromnext-common-types.js
is a solid step for maintainability.
No issues found. This addition enhances type safety compared to plain string constants.
17-17
: Good update referencingcomposeAgeEstimationFn
.
This aligns well with the switch to ES modules and ensures a more modular approach to calculating expiration ages.
421-425
: Verify the fallback logic for JSON file omission.
WhenisFallback
is truthy, the.json
file is skipped. Ensure this is fully aligned with the intended behavior for fallback pages.
443-443
: Switchingkind
toCachedRouteKind.PAGES
is a welcome type improvement.
This transition from a string literal to an enum clarifies intent and reduces errors.
627-627
: Refactoring to usecomposeAgeEstimationFn
for stale age logic looks clean.
This improves extensibility by allowing a pluggable age estimation function.
834-836
: Confirm restricting theget
method toIncrementalCacheKind.PAGES
.
The short-circuit might skip caching for other route kinds. Verify if this is intentional or if fallback logic for other route types is needed.
851-851
: EmptyimplicitTags
array could limit future tag-based invalidation.
Confirm whether you plan to add tags later or keep them empty by design.
855-855
: Falling back to a file system read for non-cached pages matches Next.jsfallback: false
behavior.
Looks correct for pages that must be served from disk when not found in the cache.
879-883
: Validate the early return condition for non-PAGES
routes orfetchCache
usage.
Ensure it’s correct to skip storing such entries. Some workflows might still want partial caching.
896-897
: Extractingneshca_lastModified
andcacheControl
fromctx
looks fine.
No issues found; this is straightforward destructuring.
898-898
: Verify behavior whencacheControl
is undefined.
revalidate
will be undefined in that scenario, so confirm that case is acceptable for your flow.
913-918
: Emptytags
array might lose track of potential tag associations.
Confirm if ignoring or discarding tags is intended. Otherwise, consider preserving relevant tags incacheHandlerValue
.
922-922
: Conditional file write for fallback false routes is aligned with Next.js semantics.
No further concerns here.
@@ -829,11 +829,13 @@ export class CacheHandler implements NextCacheHandler { | |||
|
|||
async get( | |||
cacheKey: CacheHandlerParametersGet[0], | |||
ctx: CacheHandlerParametersGet[1] = {}, | |||
ctx: CacheHandlerParametersGet[1], |
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.
💡 Verification agent
🧩 Analysis chain
ctx
as a required parameter is a breaking change.
Please confirm that all call sites now pass the ctx
argument to avoid runtime errors.
🏁 Script executed:
#!/bin/bash
# Locate calls to the get method across the codebase, ensuring a second argument for ctx
rg -A 3 '\.get\(' --type ts
Length of output: 6598
Action Required: Ensure ctx
Parameter is Passed in All CacheHandler.get Calls
The recent change in the cache-handler.ts
API makes the ctx
argument mandatory when calling the get
method. Our verification shows that while some call sites (e.g., in cache-handler.ts
) correctly pass the required second argument (like await handler.get(key, meta)
and await CacheHandler.#mergedHandler.get(cacheKey, { implicitTags: [] })
), other call sites—most notably in packages/cache-handler/src/use-cache/redis.ts
(e.g., await pendingSets.get(cacheKey);
)—do not provide a ctx
argument.
Please review and update the following:
-
packages/cache-handler/src/use-cache/redis.ts
- Confirm whether
pendingSets.get(cacheKey)
should now be called with an addedctx
argument.
- Confirm whether
-
Other related modules (such as in
handlers/local-lru.ts
if applicable)- Check if their
get
calls are intended to use the updated API and ensure they pass the required context.
- Check if their
Addressing these inconsistencies is crucial to avoid runtime errors due to the breaking change in the API.
5f76eb2
to
c49268e
Compare
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: 1
🧹 Nitpick comments (3)
packages/cache-handler/src/use-cache/redis.ts (2)
394-406
: Reading the entire stream into memory may cause performance bottlenecks.
Accumulating all chunks before storing them in Redis can be expensive for large streams, potentially leading to high memory usage. If inputs can be large, consider chunking or an alternative storage approach.
1-529
: Add or extend test coverage for this file.
This file implements complex logic (e.g., streaming, tag invalidation, pub/sub, concurrency withpendingSets
). Thorough tests will help prevent regressions and ensure all edge cases, such as Redis downtime or large data streams, are handled.Would you like me to propose a set of Jest or integration tests to validate these features?
packages/cache-handler/src/cache-handler.ts (1)
930-931
:revalidateTag
is not yet implemented
A placeholder is present forrevalidateTag
. If this feature is required, consider adding an actual implementation or removing the method until needed.Do you want me to open a follow-up issue or draft an implementation for tag-based revalidation?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (9)
.vscode/settings.json
(2 hunks)apps/cache-testing/package.json
(2 hunks)apps/cache-testing/run-app-instances.ts
(1 hunks)apps/cache-testing/tests/pages.spec.ts
(0 hunks)docs/cache-handler-docs/package.json
(1 hunks)internal/eslint-config/package.json
(1 hunks)packages/cache-handler/src/cache-handler.ts
(10 hunks)packages/cache-handler/src/use-cache/redis.ts
(1 hunks)turbo.json
(2 hunks)
💤 Files with no reviewable changes (1)
- apps/cache-testing/tests/pages.spec.ts
🚧 Files skipped from review as they are similar to previous changes (6)
- apps/cache-testing/run-app-instances.ts
- turbo.json
- .vscode/settings.json
- internal/eslint-config/package.json
- docs/cache-handler-docs/package.json
- apps/cache-testing/package.json
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: redis-stack
- GitHub Check: redis-strings
🔇 Additional comments (12)
packages/cache-handler/src/use-cache/redis.ts (3)
1-8
: Usage of internal Next.js modules is risky.
This import references internal Next.js modulescache-handlers/types.js
andincremental-cache/tags-manifest.external.js
, which are undocumented and prone to breaking changes in Next.js 15+. Prefer documented caching interfaces (e.g.,cacheHandler
config,revalidateTag
) to ensure forward compatibility.
331-344
: Consider verifying the usage ofperformance.timeOrigin + performance.now()
.
Usingperformance.timeOrigin + performance.now()
for expiration checks might introduce issues if the Node.js environment lacks consistent real-time alignment withDate.now()
, especially under serverless or container restarts. Consider usingDate.now()
consistently to simplify time comparisons.Would you like a script to search for any other instances where
performance
is used for time tracking?
300-303
: Review concurrency approach.
WhilependingSets
helps serialize concurrent writes to the same cache key, make sure your usage model correctly handles high concurrency or frequent reads-and-writes to the same key. Tests should confirm that multiple concurrent requests waiting on a pending set operation do not cause data loss or race conditions.Also applies to: 364-377
packages/cache-handler/src/cache-handler.ts (9)
14-15
: Good import adjustments for enumerated types.
Revising the import to bring inCachedRouteKind
andIncrementalCacheKind
aligns with their usage in the code below.
627-627
: Replacing the old estimation function withcomposeAgeEstimationFn
UsingcomposeAgeEstimationFn
ensures a more flexible approach and is consistent with the new design.
832-838
: Confirm that all call sites provide the new requiredctx
param.
Makingctx
mandatory and returningnull
unlessctx.kind === IncrementalCacheKind.PAGES
is a breaking change. As previously noted, please verify that everyCacheHandler.get
call passes a compatible context.#!/bin/bash # Verify that all get calls have the second argument rg -A 2 '\.get\(' --type ts
851-851
: InitializingimplicitTags
to an empty array
This is a clear approach to ensure no default tags are used. No immediate concerns.
855-855
: Fetching from file system for fallback-false routes
Good approach to populate cache misses from the filesystem. This ensures consistency when the route is markedfallback: false
.
896-898
: Extractingrevalidate
fromcacheControl
Destructuringneshca_lastModified
and referencingcacheControl?.revalidate
is straightforward. Confirm thatneshca_lastModified
is reliably set in all relevant contexts.
913-918
: Constructing the cache value object
Replacing references to any priorsoftTags
or dynamic tags with a static empty array is fine if tags are not used. Ensure that any future expansions to caching logic handle tags properly.
863-868
:✅ Verification successful
Handle fallback pages directly from the file system
Adding logic to read from disk ifctx.isFallback
is true covers fallback scenarios for the Pages Router. Verify that the code cannot conflict with the line 855 fallback logic.
🏁 Script executed:
#!/bin/bash # Checks if new logic with both fallback:false and fallback:true might conflict rg -A 5 'isFallback'Length of output: 3212
Fallback pages logic verified – no conflicts detected.
After reviewing the search results, the fallback handling via the conditional block using
ctx.isFallback
is distinct and does not interfere with the logic around line 855. Specifically:
- In the debug block (line 855), the ternary operator returns an empty object when
isFallback
is true.- In the new block (lines 863–868), when
ctx.isFallback
is true, the code retrieves fallback pages usingCacheHandler.#readPagesRouterPage
.Both branches are mutually exclusive, ensuring that fallback pages are correctly handled without conflict.
879-883
:✅ Verification successful
Skipping cache set for non-PAGES or fetchCache flows
Conditionally returning early ifincrementalCacheValue.kind
is notPAGES
or ifctx.fetchCache
is true may be intentional. Confirm you don’t need to store other route kinds.
🏁 Script executed:
#!/bin/bash # Inspect references to incrementalCacheValue.kind across code rg -A 4 'incrementalCacheValue\.kind'Length of output: 39
I'll run an additional search to inspect how
CachedRouteKind
is referenced across the repository. This will help us verify if any non‑PAGES route kinds are being used elsewhere and whether the early return is truly appropriate.
🏁 Script executed:
#!/bin/bash # Searching for references to CachedRouteKind (including .PAGES) across the repository for better context rg -n --context 4 'CachedRouteKind\.' .Length of output: 5569
Clarifying cache-setting logic for CachedRouteKind
It appears that the early return in
cache-handler.ts
(lines 879–883) intentionally bypasses caching for routes whose kind is notCachedRouteKind.PAGES
(or whenctx.fetchCache === true
). The repository scan confirms that this file only handles the PAGES kind—other kinds (e.g., REDIRECT, IMAGE, FETCH, APP_ROUTE, APP_PAGE) are processed elsewhere (for example, in the switch statement inhandlers/local-lru.ts
). Please confirm that this split in responsibilities is intentional and that caching for non‑PAGES routes is indeed managed by other components.
|
||
import { createValidatedAgeEstimationFunction } from './helpers/create-validated-age-estimation-function'; | ||
import { getTagsFromHeaders } from './helpers/get-tags-from-headers'; | ||
import { composeAgeEstimationFn } from './utils/compose-age-estimation-fn.js'; |
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.
💡 Verification agent
🧩 Analysis chain
Ensure the utility import path is correct.
The new composeAgeEstimationFn
utility import looks relevant. Confirm that ./utils/compose-age-estimation-fn.js
is the intended path and that no references remain to any removed functions.
🏁 Script executed:
#!/bin/bash
# Verify that no references to deprecated or old age estimation functions remain
rg "createValidatedAgeEstimationFunction"
Length of output: 41
I'm going to run an additional verification script to confirm that no deprecated function references remain and that the new utility file exists at the intended path. This script checks for any occurrences of "createValidatedAgeEstimationFunction"
across the repository and verifies that the file compose-age-estimation-fn.js
exists under packages/cache-handler/src/utils
.
Please run this script and share the output so we can conclusively verify that:
- The file import path (
./utils/compose-age-estimation-fn.js
) is correct. - No obsolete references remain in the codebase.
🏁 Script executed:
#!/bin/bash
echo "Searching for any reference to 'createValidatedAgeEstimationFunction':"
rg -n "createValidatedAgeEstimationFunction" || echo "No references found."
echo ""
echo "Checking for 'compose-age-estimation-fn.js' existence in packages/cache-handler/src/utils:"
find packages/cache-handler/src/utils -type f | grep "compose-age-estimation-fn.js" || echo "compose-age-estimation-fn.js not found in the expected path."
Length of output: 675
Action Required: Update the Utility Import Path
The verification shows that no deprecated functions remain, but the file compose-age-estimation-fn.js
was not found under packages/cache-handler/src/utils
. Please verify that this file exists at the intended path. If the new utility is located elsewhere or has been renamed, update the import statement accordingly.
- Confirm if
compose-age-estimation-fn.js
was moved or renamed. - Update the import path in
packages/cache-handler/src/cache-handler.ts
if necessary.
@better-salmon, I'd be willing to take on the remaining of this PR and contribute would just like to align on what the remaining work is before I dive deep |
let's make sure to show a little bit of appreciation for the great work Arseny has done so far 😊 https://opencollective.com/caching-tools#category-CONTRIBUTE @Pruxis @ricotijsen @Rikard-Johansson97 @iz-podpolja @ishida0210 @Edge1S-mgawlik @druckmax @MrBuBBLs @QurcoJr @Andr1yK |
@jobenjada |
Very nice work, if there are some more things where we can help with development/test, let's make it happen :) |
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: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (7)
apps/cache-testing/package.json
(1 hunks)docs/cache-handler-docs/package.json
(1 hunks)internal/backend/package.json
(1 hunks)internal/eslint-config/package.json
(1 hunks)package.json
(1 hunks)packages/cache-handler/package.json
(2 hunks)pnpm-workspace.yaml
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
- internal/backend/package.json
- pnpm-workspace.yaml
- docs/cache-handler-docs/package.json
- packages/cache-handler/package.json
- internal/eslint-config/package.json
- package.json
🔇 Additional comments (5)
apps/cache-testing/package.json (5)
6-6
: Verify ESM module configuration
Adding"type": "module"
will enforce ES module semantics for all.js
files. Please ensure that files likecluster.config.js
or other scripts intended to remain CommonJS are either renamed to.cjs
or updated to valid ESM syntax.
8-8
: Ensure build script dependencies are available
The build script now usestsx create-instances.ts
instead of the shell script. Confirm thatcreate-instances.ts
exists at the project root and thattsx
is installed in CI environments before runningbuild
.
13-14
: Update documentation and CI for lint scripts
The scripts have been renamed fromeslint:check
/eslint:fix
tolint:check
/lint:fix
with--max-warnings=0
. Remember to update any documentation, project README, or CI workflows that reference the old script names.
20-23
: Upgrade runtime dependencies for Next.js 15 support
Bumpingaxios
,next
,react
, andreact-dom
aligns with the PR goal of Next.js 15 compatibility. Good to see versions updated. Ensure that any peer dependencies or lock files are updated accordingly.
27-27
: Apply consistent dev dependency upgrades
Dev dependencies such as Playwright, TypeScript, ESLint, and their type definitions have been updated to the latest compatible versions, keeping the development environment standardized.Also applies to: 30-32, 34-38
"@types/node": "22.15.18", | ||
"@types/react": "19.1.4", | ||
"@types/react-dom": "19.1.5", | ||
"dotenv-cli": "8.0.0", |
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: Move dotenv-cli
to production dependencies or adjust start script
The start
script relies on the dotenv
command from dotenv-cli
, which is currently in devDependencies
. In production (NODE_ENV=production
), dev dependencies may not be installed, causing start
to fail. Consider moving dotenv-cli
to dependencies
or handling environment variables at runtime via CI or a lightweight wrapper.
🤖 Prompt for AI Agents
In apps/cache-testing/package.json at line 33, the `dotenv-cli` package is
listed under devDependencies but is required by the start script in production.
To fix this, move `dotenv-cli` from devDependencies to dependencies to ensure it
is installed in production environments, or alternatively, modify the start
script to handle environment variables without relying on `dotenv-cli` at
runtime.
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: 7
♻️ Duplicate comments (2)
packages/cache-handler/src/handlers/redis-stack.ts (1)
230-232
:⚠️ Potential issueKey prefix is missing in
delete
– item will never be removed
This is the same issue flagged in earlier reviews for theredis-strings
handler.-await client.withAbortSignal(AbortSignal.timeout(timeoutMs)).unlink(key); +await client + .withAbortSignal(AbortSignal.timeout(timeoutMs)) + .unlink(keyPrefix + key);packages/cache-handler/src/handlers/experimental-redis-cluster.ts (1)
270-274
:⚠️ Potential issueKey prefix omitted in cluster
delete
The data was stored with
keyPrefix + key
; deleting without the prefix will orphan the entry.-.unlink(key); +.unlink(keyPrefix + key);
🧹 Nitpick comments (3)
packages/cache-handler/package.json (2)
33-40
: Refine build and dev scripts & remove unused devDependency
- The
tsx
package is no longer referenced in any script; you can drop it to slim down installs.- Consider adding a
prepare
orprepublishOnly
hook to run"build"
and"check-types"
automatically before publishing.Example adjustments:
"scripts": { - "build": "tsc -p tsconfig.build.json", + "build": "tsc -p tsconfig.build.json", "check-types": "tsc --noEmit", - "dev": "tsc -w -p tsconfig.build.json", + "dev": "tsc -w -p tsconfig.build.json", "lint:check": "eslint . --max-warnings=0", "lint:fix": "eslint --fix . --max-warnings=0", "test": "vitest run", "test:watch": "vitest", + "prepare": "npm run build && npm run check-types" },And remove
tsx
fromdevDependencies
if unused.
57-59
: Review peer dependency ranges
Lockingnext
to>=15 <16
is appropriate for Next.js 15 support. Forredis
, confirm that you don’t need to support v6+ (e.g., for compatibility with newer Redis clients). Adjust the range if broader compatibility is required.packages/cache-handler/src/handlers/redis-stack.ts (1)
160-181
: Optional: filter out undefined promises inPromise.all
When
expireCacheValue
isundefined
, it is still passed toPromise.all
; this resolves fine but is a small smell. Consider filtering falsy values for clarity.-await Promise.all([setCacheValue, expireCacheValue]); +await Promise.all([setCacheValue, expireCacheValue].filter(Boolean));
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (9)
apps/cache-testing/package.json
(1 hunks)internal/eslint-config/vitest.js
(1 hunks)packages/cache-handler/package.json
(2 hunks)packages/cache-handler/src/handlers/experimental-redis-cluster.ts
(8 hunks)packages/cache-handler/src/handlers/redis-stack.ts
(7 hunks)packages/cache-handler/src/handlers/redis-strings.ts
(8 hunks)packages/cache-handler/src/helpers/helpers.ts
(1 hunks)packages/cache-handler/src/use-cache/node-redis.ts
(1 hunks)packages/cache-handler/test/utils/compose-age-estimation-fn.test.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- internal/eslint-config/vitest.js
- packages/cache-handler/test/utils/compose-age-estimation-fn.test.ts
- packages/cache-handler/src/use-cache/node-redis.ts
- packages/cache-handler/src/handlers/redis-strings.ts
- apps/cache-testing/package.json
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: redis-stack
- GitHub Check: redis-strings
🔇 Additional comments (3)
packages/cache-handler/package.json (2)
42-45
: Dependencies updates look good
The bump to caret ranges forcluster-key-slot
andlru-cache
, plus the introduction ofsuperjson
, align with the modernization effort.
47-55
: Verify workspace protocol compatibility
You’ve switched toworkspace:*
for local ESLint and TS configs. Ensure that your chosen package manager (npm, Yarn, pnpm) supports this notation in published packages, or consider replacing it with explicit relative paths or versioned entries.packages/cache-handler/src/helpers/helpers.ts (1)
1-1
:✅ Verification successful
Export barrel now exposes only one helper – double-check downstream imports
All other helpers (
promiseWithTimeout
,getTimeoutRedisCommandOptions
, etc.) were removed from this barrel. If any consumer code (internal or external) still imports them frompackages/cache-handler/src/helpers
, it will now fail at runtime. Please run a repo-wide grep before merging to ensure no lingering imports remain.Example verification command:
🏁 Script executed:
rg "from ['\"].*helpers['\"]" --glob '!dist/**'Length of output: 251
No lingering imports of removed helpers found
I ran a repo-wide grep for imports from “…/helpers” and only found:
apps/cache-testing/tests/app.spec.ts
importing from./test-helpers
(unrelated)docs/cache-handler-docs/src/app/usage/creating-a-custom-handler/page.mdx
importingisTagImplicit
(the only remaining export)Since no other helpers are being imported from
packages/cache-handler/src/helpers
, there are no runtime breakages.
@@ -14,7 +14,7 @@ | |||
"bugs": "https://github.com/caching-tools/next-shared-cache/issues", | |||
"repository": { | |||
"type": "git", | |||
"url": "git+https://github.com/caching-tools/next-shared-cache.git" | |||
"url": "git+https://github.com/caching-tools/next-shared-cache.git " |
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 trailing whitespace in the Git repository URL
The value for "url"
has an extra space at the end, which can cause failures when installing or cloning the package.
Apply this diff to remove the trailing space:
- "url": "git+https://github.com/caching-tools/next-shared-cache.git "
+ "url": "git+https://github.com/caching-tools/next-shared-cache.git"
📝 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.
"url": "git+https://github.com/caching-tools/next-shared-cache.git " | |
"url": "git+https://github.com/caching-tools/next-shared-cache.git" |
🤖 Prompt for AI Agents
In packages/cache-handler/package.json at line 17, remove the trailing
whitespace at the end of the Git repository URL value for the "url" field to
ensure the URL is correctly formatted and avoid installation or cloning errors.
".": "./dist/cache-handler.js", | ||
"./helpers/*": "./dist/helpers/*.js", | ||
"./handlers/*": "./dist/handlers/*.js", | ||
"./instrumentation/*": "./dist/instrumentation/*.js", | ||
"./use-cache/*": "./dist/use-cache/*.js" | ||
}, |
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.
Add TypeScript declaration exports
You’ve consolidated the ESM exports nicely, but consumers of this package won’t be able to locate the generated .d.ts
files. It’s critical to expose type definitions so that TypeScript projects can statically validate imports.
Consider extending your exports with a dual-field format or adding a top-level "types"
entry. For example:
"exports": {
- ".": "./dist/cache-handler.js",
+ ".": {
+ "import": "./dist/cache-handler.js",
+ "types": "./dist/cache-handler.d.ts"
+ },
"./helpers/*": "./dist/helpers/*.js",
"./handlers/*": "./dist/handlers/*.js",
"./instrumentation/*": "./dist/instrumentation/*.js",
"./use-cache/*": "./dist/use-cache/*.js"
},
+ "types": "dist/cache-handler.d.ts",
This ensures editors and compilers pick up the declarations correctly.
📝 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.
".": "./dist/cache-handler.js", | |
"./helpers/*": "./dist/helpers/*.js", | |
"./handlers/*": "./dist/handlers/*.js", | |
"./instrumentation/*": "./dist/instrumentation/*.js", | |
"./use-cache/*": "./dist/use-cache/*.js" | |
}, | |
".": { | |
"import": "./dist/cache-handler.js", | |
"types": "./dist/cache-handler.d.ts" | |
}, | |
"./helpers/*": "./dist/helpers/*.js", | |
"./handlers/*": "./dist/handlers/*.js", | |
"./instrumentation/*": "./dist/instrumentation/*.js", | |
"./use-cache/*": "./dist/use-cache/*.js" | |
}, | |
"types": "dist/cache-handler.d.ts", |
🤖 Prompt for AI Agents
In packages/cache-handler/package.json around lines 26 to 31, the exports field
lacks references to the TypeScript declaration (.d.ts) files, which prevents
TypeScript consumers from accessing type definitions. To fix this, extend the
exports entries to include a "types" or "typings" field pointing to the
corresponding .d.ts files alongside the JavaScript files, or add a top-level
"types" entry referencing the main declaration file. This will enable editors
and TypeScript compilers to locate and use the type declarations properly.
const signal = AbortSignal.timeout(timeoutMs); | ||
|
||
await client.unlink(options, keysToDelete); | ||
await client.withAbortSignal(signal).unlink(keysToDelete); | ||
}, |
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.
unlink
should be called with spread keys, not an array
unlink(keysToDelete)
transmits a single argument (the array).
Redis will treat that as one key and delete nothing.
-await client.withAbortSignal(signal).unlink(keysToDelete);
+await client.withAbortSignal(signal).unlink(...keysToDelete);
📝 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.
const signal = AbortSignal.timeout(timeoutMs); | |
await client.unlink(options, keysToDelete); | |
await client.withAbortSignal(signal).unlink(keysToDelete); | |
}, | |
const signal = AbortSignal.timeout(timeoutMs); | |
await client.withAbortSignal(signal).unlink(...keysToDelete); | |
}, |
🤖 Prompt for AI Agents
In packages/cache-handler/src/handlers/redis-stack.ts around lines 226 to 229,
the unlink method is called with an array argument keysToDelete, which causes
Redis to treat it as a single key. To fix this, spread the keysToDelete array
when calling unlink so that each key is passed as a separate argument, ensuring
all keys are properly deleted.
const revalidationTimes = await client | ||
.withAbortSignal(AbortSignal.timeout(timeoutMs)) | ||
.hmGet(revalidatedTagsKey, Array.from(combinedTags)); | ||
|
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.
hmGet
receives an array – API expects variadic fields
redis
v4’s signature is hmGet(key, ...fields)
.
Passing an array results in a single stringified field lookup, so all revalidation checks silently fail.
-const revalidationTimes = await client
- .withAbortSignal(AbortSignal.timeout(timeoutMs))
- .hmGet(revalidatedTagsKey, Array.from(combinedTags));
+const revalidationTimes = await client
+ .withAbortSignal(AbortSignal.timeout(timeoutMs))
+ .hmGet(revalidatedTagsKey, ...combinedTags);
📝 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.
const revalidationTimes = await client | |
.withAbortSignal(AbortSignal.timeout(timeoutMs)) | |
.hmGet(revalidatedTagsKey, Array.from(combinedTags)); | |
const revalidationTimes = await client | |
.withAbortSignal(AbortSignal.timeout(timeoutMs)) | |
.hmGet(revalidatedTagsKey, ...combinedTags); |
🤖 Prompt for AI Agents
In packages/cache-handler/src/handlers/redis-stack.ts around lines 140 to 143,
the call to hmGet incorrectly passes an array of fields instead of variadic
arguments. To fix this, spread the array of combinedTags using the spread
operator (...) so that each tag is passed as a separate argument to hmGet,
matching the expected variadic parameters of the redis v4 API.
for (const [slot, keys] of slotKeysMap) { | ||
const targetMasterNode = cluster.slots[slot]?.master; | ||
const client = await targetMasterNode?.client; | ||
|
||
const client = targetMasterNode?.client; | ||
|
||
if (keys.length === 0 || !client) { | ||
continue; | ||
} | ||
|
||
const unlinkPromisesForSlot = client.unlink( | ||
getTimeoutRedisCommandOptions(timeoutMs), | ||
keys, | ||
unlinkPromises.push( | ||
client.withAbortSignal(AbortSignal.timeout(timeoutMs)).unlink(keys), | ||
); | ||
|
||
if (unlinkPromisesForSlot) { | ||
unlinkPromises.push(unlinkPromisesForSlot); | ||
} | ||
} |
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.
Cluster unlink
uses array instead of variadic keys
Each individual master node client needs unlink(...keys)
not unlink(keys)
:
-unlinkPromises.push(
- client.withAbortSignal(AbortSignal.timeout(timeoutMs)).unlink(keys),
-);
+unlinkPromises.push(
+ client.withAbortSignal(AbortSignal.timeout(timeoutMs)).unlink(...keys),
+);
📝 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.
for (const [slot, keys] of slotKeysMap) { | |
const targetMasterNode = cluster.slots[slot]?.master; | |
const client = await targetMasterNode?.client; | |
const client = targetMasterNode?.client; | |
if (keys.length === 0 || !client) { | |
continue; | |
} | |
const unlinkPromisesForSlot = client.unlink( | |
getTimeoutRedisCommandOptions(timeoutMs), | |
keys, | |
unlinkPromises.push( | |
client.withAbortSignal(AbortSignal.timeout(timeoutMs)).unlink(keys), | |
); | |
if (unlinkPromisesForSlot) { | |
unlinkPromises.push(unlinkPromisesForSlot); | |
} | |
} | |
for (const [slot, keys] of slotKeysMap) { | |
const targetMasterNode = cluster.slots[slot]?.master; | |
const client = targetMasterNode?.client; | |
if (keys.length === 0 || !client) { | |
continue; | |
} | |
unlinkPromises.push( | |
client.withAbortSignal(AbortSignal.timeout(timeoutMs)).unlink(...keys), | |
); | |
} |
🤖 Prompt for AI Agents
In packages/cache-handler/src/handlers/experimental-redis-cluster.ts around
lines 250 to 262, the unlink method is called with a single array argument
(unlink(keys)) but it requires variadic arguments (unlink(...keys)). To fix
this, spread the keys array when calling unlink by changing unlink(keys) to
unlink(...keys) so each key is passed as a separate argument.
.withCommandOptions({ abortSignal: AbortSignal.timeout(timeoutMs) }) | ||
.hDel(keyPrefix + sharedTagsKey, tagsToDelete); | ||
|
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.
hDel
must receive spread fields
-.hDel(keyPrefix + sharedTagsKey, tagsToDelete);
+.hDel(keyPrefix + sharedTagsKey, ...tagsToDelete);
🤖 Prompt for AI Agents
In packages/cache-handler/src/handlers/experimental-redis-cluster.ts around
lines 265 to 267, the hDel command is called with tagsToDelete as a single
argument, but it requires the fields to be passed as separate arguments. Fix
this by spreading the tagsToDelete array or iterable into individual arguments
when calling hDel, ensuring each field to delete is passed separately.
const revalidationTimes = await cluster | ||
.withCommandOptions({ abortSignal: AbortSignal.timeout(timeoutMs) }) | ||
.hmGet(revalidatedTagsKey, Array.from(combinedTags)); |
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.
hmGet
array issue – same as in redis-stack
Spread the tag array so each field is sent separately:
-.hmGet(revalidatedTagsKey, Array.from(combinedTags));
+.hmGet(revalidatedTagsKey, ...combinedTags);
📝 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.
const revalidationTimes = await cluster | |
.withCommandOptions({ abortSignal: AbortSignal.timeout(timeoutMs) }) | |
.hmGet(revalidatedTagsKey, Array.from(combinedTags)); | |
const revalidationTimes = await cluster | |
.withCommandOptions({ abortSignal: AbortSignal.timeout(timeoutMs) }) | |
.hmGet(revalidatedTagsKey, ...combinedTags); |
🤖 Prompt for AI Agents
In packages/cache-handler/src/handlers/experimental-redis-cluster.ts around
lines 125 to 127, the hmGet command is called with an array of tags as a single
argument, but it requires each tag to be passed as a separate argument. Fix this
by spreading the combinedTags array so that each tag is sent individually to
hmGet.
Would love to see this cross the line soon! We're looking to use redis clusters in a self hosted Next.js setup, and this would make the approach much easier than writing a custom solution. 🚀 |
We are welcoming anybody to try out: https://github.com/trieb-work/nextjs-turbo-redis-cache We saw around 80% less redis traffic with our approach and because in the long run also 90% less memory usage in Redis in comparison to our setup with neshca. |
@JannikZed would love to but unfortunately cannot due to
We are moving to app router but currently are in a hybrid state split across app and pages. We can't easily move off pages router without a shared cache, hence waiting for this to land. Is this something you plan to support? |
For people needing a fast switch with minimal breaking changes -> https://github.com/fortedigital/nextjs-cache-handler |
76abafa
to
9fdb6a4
Compare
@better-salmon Is there anything that can be done from the community here to get this moving? I've been telling engineers at my work that this is coming soon - almost done - for several months now. I don't see a migration path to a community replacement (https://github.com/fortedigital/nextjs-cache-handler, https://github.com/trieb-work/nextjs-turbo-redis-cache) that supports pages router, so feel rather stuck. If there are any outstanding tasks, that could help get this released, it would be great to align the community so those who want to could try and contribute 🙏🏻 |
@harry-gocity fyi even though most users who decided to go with https://github.com/fortedigital/nextjs-cache-handler use app router, the library has recently had compatibility fixes for Next 15 with pages router as well. |
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Chores
Tests
Style
Documentation