Skip to content

fix: respect zero ttl#5

Merged
pi0 merged 6 commits intounjs:mainfrom
Flo0806:fix/respect-zero-ttl
Mar 19, 2026
Merged

fix: respect zero ttl#5
pi0 merged 6 commits intounjs:mainfrom
Flo0806:fix/respect-zero-ttl

Conversation

@Flo0806
Copy link
Contributor

@Flo0806 Flo0806 commented Mar 18, 2026

🔗 Linked issue

Fixes: nuxt/nuxt#34307
Related: nitrojs/nitro#4126
Related: nitrojs/nitro#4125

❓ Type of change

  • 🐞 Bug fix (a non-breaking change that fixes an issue)

📚 Description

swr: 0 set in nuxt.config.ts (see linked issue to Nuxt) it should be handled like max-age=0 - but it will be ignored, because Nitro checks if (swr) what is false with 0, too.
Here it is the same.
This fix checks explicitly for 0.

📝 Checklist

  • I have linked an issue or discussion.

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed cache TTL handling to properly treat zero and other falsy cache duration values.
    • Improved cache-control header generation for stale-while-revalidate configurations.
  • Tests

    • Added comprehensive test coverage for cache expiration edge cases and SWR header scenarios.

@coderabbitai
Copy link

coderabbitai bot commented Mar 18, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1280edac-0896-4285-bf04-08a42245f2b1

📥 Commits

Reviewing files that changed from the base of the PR and between 21ab487 and 627ec9e.

📒 Files selected for processing (2)
  • src/cache.ts
  • test/index.test.ts
✅ Files skipped from review due to trivial changes (1)
  • test/index.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/cache.ts

📝 Walkthrough

Walkthrough

Changes refine TTL and cache-control header handling to treat zero and numeric falsy values as explicit thresholds rather than falsy defaults. Cache expiration and staleness checks now activate only when TTL exceeds zero, and cache-control headers properly distinguish between omitted values and explicit zero values using null-aware checks.

Changes

Cohort / File(s) Summary
Cache Expiration Logic
src/cache.ts
Modified TTL-gating conditions to check ttl > 0 instead of truthiness; cache entries expire immediately when maxAge === 0, and storage set options include ttl only when maxAge > 0.
Cache-Control Headers
src/http.ts
Updated SWR and non-SWR branches to use null-aware checks (!= null) for maxAge and staleMaxAge, allowing zero values to be treated as valid explicit thresholds rather than falsy defaults.
Test Coverage
test/index.test.ts
Added test cases for defineCachedFunction with maxAge: 0 (no caching) and omitted maxAge (indefinite caching); added defineCachedHandler tests asserting correct cache-control header construction in SWR mode with zero values.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A zero once hid, treated false by the code,
Now explicit it stands, lighting the road! 🐰✨
No more shall falsy blur what's truly meant,
Zero is zero—intention's now evident!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'fix: respect zero ttl' clearly summarizes the main change: enabling zero values for TTL parameters to be properly recognized and handled instead of being treated as falsy.
Linked Issues check ✅ Passed The pull request addresses the linked issue #34307 by treating maxAge and staleMaxAge with != null checks instead of truthiness, allowing zero values to be recognized as valid TTLs that disable caching.
Out of Scope Changes check ✅ Passed All changes in src/cache.ts, src/http.ts, and test/index.test.ts are directly related to handling zero TTL values and fixing the swr: 0 behavior described in the linked issue.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/http.ts`:
- Around line 147-150: The non-SWR branch currently uses a truthy check for
opts.maxAge which ignores explicit 0; change the condition to test for
undefined/null (e.g., if (opts.maxAge !== undefined && opts.maxAge !== null)) so
that opts.maxAge === 0 produces "max-age=0" and push into cacheControl the
`max-age=${opts.maxAge}` value; ensure this mirrors the SWR path's handling of
opts.maxAge so explicit zero values are respected.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b226f7ef-4507-4170-9550-6e6a292f9ea6

📥 Commits

Reviewing files that changed from the base of the PR and between 05c9f4e and dd56be8.

📒 Files selected for processing (2)
  • src/cache.ts
  • src/http.ts

Comment on lines 147 to 150
} else if (opts.maxAge) {
// For non-SWR, set max-age directly
cacheControl.push(`max-age=${opts.maxAge}`);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent handling of maxAge: 0 in non-SWR path.

Line 147 still uses a truthy check (opts.maxAge), so maxAge: 0 would be ignored and no max-age header would be set. This is inconsistent with the SWR path (line 139) which now respects zero values.

If a user explicitly sets maxAge: 0 without SWR, they likely expect max-age=0 to be emitted.

Proposed fix for consistency
-    } else if (opts.maxAge) {
+    } else if (opts.maxAge != null) {
       // For non-SWR, set max-age directly
       cacheControl.push(`max-age=${opts.maxAge}`);
     }
📝 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.

Suggested change
} else if (opts.maxAge) {
// For non-SWR, set max-age directly
cacheControl.push(`max-age=${opts.maxAge}`);
}
} else if (opts.maxAge != null) {
// For non-SWR, set max-age directly
cacheControl.push(`max-age=${opts.maxAge}`);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/http.ts` around lines 147 - 150, The non-SWR branch currently uses a
truthy check for opts.maxAge which ignores explicit 0; change the condition to
test for undefined/null (e.g., if (opts.maxAge !== undefined && opts.maxAge !==
null)) so that opts.maxAge === 0 produces "max-age=0" and push into cacheControl
the `max-age=${opts.maxAge}` value; ensure this mirrors the SWR path's handling
of opts.maxAge so explicit zero values are respected.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@README.md`:
- Around line 259-263: The README's TypeScript signature for
defineCachedFunction is truncated; restore the complete declaration by setting
the default for the opts parameter and the return type to match the source:
update the signature for function defineCachedFunction<T, ArgsT extends
unknown[] = any[]>(fn: (...args: ArgsT) => T | Promise<T>, opts: CacheOptions<T,
ArgsT> = {},): (...args: ArgsT) => Promise<T> so that CacheOptions has a default
{} and the function returns (...args: ArgsT) => Promise<T>; ensure the restored
tokens match the source declaration around defineCachedFunction, CacheOptions,
opts, and the return type.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cc0123c8-0524-4408-8421-5dbd53c3c6ec

📥 Commits

Reviewing files that changed from the base of the PR and between dd56be8 and eaf0bc9.

📒 Files selected for processing (1)
  • README.md

autofix-ci bot and others added 3 commits March 18, 2026 16:38
…y check

The previous fix treated both `maxAge: 0` and unset `maxAge` as always-expired
since `ttl === 0` is true for both. Now `opts.maxAge === 0` explicitly checks
the user's intent, while `undefined` maxAge preserves cache-indefinitely behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@pi0 pi0 merged commit 55e4862 into unjs:main Mar 19, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Payload is not generated with swr: 0

2 participants