Conversation
📝 WalkthroughWalkthroughFormatting and config normalization across repo, CI and devcontainer tweaks, removal of package-level manifests/configs under Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@package.json`:
- Around line 2-100: The package's exports and publishConfig reference missing
build artifacts (e.g., "main": "./dist/index.cjs", "module": "./dist/index.mjs",
"types": "./dist/index.d.cts" and all subpath files under "exports" /
"./providers/redis", "./plugin", etc.), so either run the library build to
produce the ./dist/* outputs before publishing or modify the "exports" and
"publishConfig" entries to point to the actual compiled outputs (or
remove/adjust entries you don't ship). Update the references for index.cjs,
index.mjs, index.d.cts and each subpath (./plugin, ./providers/memory,
./providers/redis, ./schemas, ./superjson, ./types, ./utils) to match the real
artifact filenames/paths produced by your build step or ensure the build emits
those exact files.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@package.json`:
- Around line 23-105: The package.json currently points "types" to
"./dist/index.d.cts" (wrong extension) and each subpath export (e.g., exports
keys ".", "./plugin", "./providers/memory", "./providers/redis", "./schemas",
"./superjson", "./types", "./utils") is missing a "types" condition so
TypeScript cannot resolve subpath .d.ts declarations; update the top-level
"types" to "./dist/index.d.ts" and add a "types": "./dist/<entry>.d.ts"
condition for every export subpath entry to match the generated tsdown outputs
(keep publishConfig unchanged as noted).
| "main": "./dist/index.cjs", | ||
| "module": "./dist/index.mjs", | ||
| "types": "./dist/index.d.cts", | ||
| "exports": { | ||
| ".": { | ||
| "@zenstack-cache/source": "./src/index.ts", | ||
| "require": "./dist/index.cjs", | ||
| "import": "./dist/index.mjs" | ||
| }, | ||
| "./plugin": { | ||
| "@zenstack-cache/source": "./src/plugin.ts", | ||
| "require": "./dist/plugin.cjs", | ||
| "import": "./dist/plugin.mjs" | ||
| }, | ||
| "./providers/memory": { | ||
| "@zenstack-cache/source": "./src/providers/memory.ts", | ||
| "require": "./dist/providers/memory.cjs", | ||
| "import": "./dist/providers/memory.mjs" | ||
| }, | ||
| "./providers/redis": { | ||
| "@zenstack-cache/source": "./src/providers/redis.ts", | ||
| "require": "./dist/providers/redis.cjs", | ||
| "import": "./dist/providers/redis.mjs" | ||
| }, | ||
| "./schemas": { | ||
| "@zenstack-cache/source": "./src/schemas.ts", | ||
| "require": "./dist/schemas.cjs", | ||
| "import": "./dist/schemas.mjs" | ||
| }, | ||
| "./superjson": { | ||
| "@zenstack-cache/source": "./src/superjson.ts", | ||
| "require": "./dist/superjson.cjs", | ||
| "import": "./dist/superjson.mjs" | ||
| }, | ||
| "./types": { | ||
| "@zenstack-cache/source": "./src/types.ts", | ||
| "require": "./dist/types.cjs", | ||
| "import": "./dist/types.mjs" | ||
| }, | ||
| "./utils": { | ||
| "@zenstack-cache/source": "./src/utils.ts", | ||
| "require": "./dist/utils.cjs", | ||
| "import": "./dist/utils.mjs" | ||
| }, | ||
| "./package.json": "./package.json" | ||
| }, | ||
| "publishConfig": { | ||
| "exports": { | ||
| ".": { | ||
| "require": "./dist/index.cjs", | ||
| "import": "./dist/index.mjs" | ||
| }, | ||
| "./plugin": { | ||
| "require": "./dist/plugin.cjs", | ||
| "import": "./dist/plugin.mjs" | ||
| }, | ||
| "./providers/memory": { | ||
| "require": "./dist/providers/memory.cjs", | ||
| "import": "./dist/providers/memory.mjs" | ||
| }, | ||
| "./providers/redis": { | ||
| "require": "./dist/providers/redis.cjs", | ||
| "import": "./dist/providers/redis.mjs" | ||
| }, | ||
| "./schemas": { | ||
| "require": "./dist/schemas.cjs", | ||
| "import": "./dist/schemas.mjs" | ||
| }, | ||
| "./superjson": { | ||
| "require": "./dist/superjson.cjs", | ||
| "import": "./dist/superjson.mjs" | ||
| }, | ||
| "./types": { | ||
| "require": "./dist/types.cjs", | ||
| "import": "./dist/types.mjs" | ||
| }, | ||
| "./utils": { | ||
| "require": "./dist/utils.cjs", | ||
| "import": "./dist/utils.mjs" | ||
| }, | ||
| "./package.json": "./package.json" | ||
| } | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Get an overview of the repository structure
ls -la
# Check if tsconfig exists and examine build configuration
fd -t f "tsconfig\|vite\|rollup\|webpack\|esbuild" -e json -e js -e ts | head -20
# Look for the actual generated declaration files
fd -t f "\.(d\.ts|d\.cts|d\.mts)$" dist 2>/dev/null | head -20Repository: visualbravo/zenstack-cache
Length of output: 1553
🏁 Script executed:
# Examine the build tool configuration
cat tsdown.config.ts
# Check tsconfig.json for declaration settings
cat tsconfig.json
# Read the package.json to understand the full context
cat -n package.json
# Check if dist directory exists and list declaration files
find dist -type f 2>/dev/null | grep -E "\.(d\.ts|d\.cts|d\.mts)$" | head -20Repository: visualbravo/zenstack-cache
Length of output: 5890
🏁 Script executed:
# Check what declaration files tsdown actually generates
# First, let's see if dist exists and what files are there
ls -la dist/ 2>/dev/null || echo "dist directory not found"
# Check the src structure to understand what files need declarations
find src -type f \( -name "*.ts" -o -name "*.tsx" \) | sort
# Search for any TypeScript documentation or usage about .d.cts vs .d.ts
grep -r "d\.cts\|d\.ts\|d\.mts" . --include="*.md" --include="*.json" 2>/dev/null | grep -v node_modules | head -20Repository: visualbravo/zenstack-cache
Length of output: 274
🏁 Script executed:
# Check tsdown documentation and configuration
# Look for any type definitions or documentation about tsdown output
grep -A 10 -B 5 "dts\|declaration" tsdown.config.ts
# Check if there's any documentation in the repo about the build process
cat README.md | grep -A 10 -B 5 "build\|types" || echo "No build info in README"
# Search for any GitHub issues or comments about declaration files
find . -name "*.md" -o -name "*.txt" | xargs grep -l "d\.cts\|d\.mts\|declaration" 2>/dev/null | head -5Repository: visualbravo/zenstack-cache
Length of output: 3491
🏁 Script executed:
# Search for tsdown documentation or examples about declaration file output
web_search="what declaration files does tsdown generate .d.ts .d.cts .d.mts"
# Also check if there are any .d.ts or .d.cts files mentioned elsewhere
find . -type f \( -name "*.json" -o -name "*.md" -o -name "*.ts" \) -exec grep -l "\.d\.(ts|cts|mts)" {} \; 2>/dev/null | head -10
# Look at the tsdown package to understand its declaration output behavior
npm list tsdown 2>/dev/null || echo "Checking tsdown details..."
# Check if there's any CI/build workflow that shows what files are generated
find .github -type f -name "*.yml" -o -name "*.yaml" 2>/dev/null | xargs cat 2>/dev/null | head -100Repository: visualbravo/zenstack-cache
Length of output: 2281
🌐 Web query:
tsdown declaration file output .d.cts .d.ts generate types
💡 Result:
-
tsdownonly generates/bundles*.d.tsdeclaration files (enabled via--dts/dts: true, or auto-enabled when yourpackage.jsonhastypes/typingsorexports.*.types). It does this viarolldown-plugin-dts. [1][2] -
*.d.cts/*.d.mtsare TypeScript’s “Node module” declaration extensions, and TypeScript emits them only when the corresponding source files are*.cts/*.mts(introduced in TS 4.7). [3]
For dual ESM/CJS packages, TypeScript also expects the declaration file’s module-kind to match the JS entrypoint (and often you need separate declarations per entry). [4]
How to get *.d.cts with tsdown
tsdown doesn’t currently have a “types extension auto-switch” option—so the usual approach is:
- Keep
tsdownfor JS bundling (esm/cjs). - Generate types with
tsc(emitDeclarationOnly) using*.mtsand/or*.ctsentry files (often thin re-export wrappers), sotscproduces*.d.mts/*.d.cts. [3] - Point
package.jsonexportsconditions to the righttypesfile (e.g."require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" }). [3][4]
Sources: tsdown dts docs [1], tsdown options reference [2], TS 4.7 announcement (new .d.cts/.d.mts + exports.types pattern) [3], TS 4.7 release notes (separate declarations + module-kind matching) [4].
🌐 Web query:
TypeScript subpath exports types condition resolution fallback
💡 Result:
TypeScript can pick up declaration files for exported subpaths via the package.json conditional exports map by using the "types" condition (which Node.js ignores). The practical “fallback” story is:
-
Put
"types"first (highest priority) inside each conditional exports object
Key order matters for conditional exports, and both Node’s docs and TypeScript’s docs recommend"types"be listed first so TypeScript can grab.d.tsbefore falling through to JS conditions. [1], [2] -
Always include a runtime fallback (
"default", plus"import"/"require"as needed)
Node resolves"import","require","default", etc., and expects"default"as the generic last-resort."types"is a community condition meant for type resolvers. [1] -
If TypeScript can’t find types via
exports, it may still resolve the JS (and you’ll getany-typed imports)
TypeScript’s resolver can succeed on the JS path after failing to find a corresponding declaration, which effectively becomes a “no types found” fallback. [3]
Recommended pattern (subpath + ESM/CJS + types)
{
"name": "pkg",
"exports": {
"./feature": {
"import": {
"types": "./dist/feature/index.d.ts",
"default": "./dist/feature/index.js"
},
"require": {
"types": "./dist/feature/index.d.cts",
"default": "./dist/feature/index.cjs"
}
}
},
// fallback for older TypeScript / tooling
"types": "./dist/index.d.ts"
}This mirrors the TypeScript 4.7 guidance: TypeScript reads "types"; Node reads "default"; and you provide separate .d.ts flavors when module-kind differs (ESM vs CJS). [2], [4]
Optional: versioned type-condition fallback
TypeScript also supports versioned type conditions like "types@>=5.2" with a fallback "types" entry. [5]
Sources: Node.js package exports/conditions docs [1]; TypeScript 4.7 release notes/blog guidance on "types" condition ordering and dual ESM/CJS typings [2], [4]; TypeScript module resolution reference describing type lookup/fallback behavior [3]; TypeScript docs example of types@>=... conditional selection [5].
🌐 Web query:
tsdown unbundle declaration files per entry output separate
💡 Result:
tsdown can output separate .d.ts per entry, but it does not support “unbundled”/per-source-file .d.ts output. Its DTS pipeline is based on rolldown-plugin-dts, which generates and bundles declarations. [1] [2]
Separate .d.ts per entry (supported)
Define multiple entries (array or alias-object). Each entry is built as a separate output, and DTS is enabled via dts: true / --dts. [3] [1]
// tsdown.config.ts
import { defineConfig } from "tsdown";
export default defineConfig({
entry: {
index: "src/index.ts",
cli: "src/cli.ts",
},
dts: true,
});Unbundled .d.ts files (per module / per source file)
Not supported by tsdown’s DTS bundling approach (it bundles). [1] [2] If you need “one .d.ts next to each output .js file”, the usual workaround is:
- use
tsdownfor JS (optionallyunbundle: truefor JS output structure), [4] - turn off
tsdownDTS, - run
tsc --emitDeclarationOnly(or a dedicated types build) to emit many.d.tsfiles.
Sources:
[1] https://tsdown.dev/options/dts
[2] https://github.com/sxzz/rolldown-plugin-dts
[3] https://tsdown.dev/options/entry
[4] https://tsdown.dev/options/unbundle
🏁 Script executed:
# Check tsdown's actual behavior with glob entry patterns and unbundle
# Look for any documentation or examples in tsdown about glob entries with unbundle + dts
node -e "console.log('tsdown with glob entry generates bundled DTS. With unbundle for JS only, DTS is still bundled into single files per format (cjs, esm).')" 2>/dev/null
# Verify the exact tsdown config
cat tsdown.config.ts
# Check if there's any output structure information in node_modules or docs
find . -type f \( -name "*.md" -o -name "CHANGELOG*" \) -path "*/tsdown/*" 2>/dev/null | head -5Repository: visualbravo/zenstack-cache
Length of output: 449
🏁 Script executed:
# Understand what tsdown actually outputs with glob + unbundle + dts
# Check if tsdown has any known output patterns for this config
python3 << 'EOF'
import json
config = {
"entry": ["./src/**/*.{ts,tsx}"],
"dts": True,
"format": ["cjs", "esm"],
"unbundle": True,
}
# With unbundle=true for JS, tsdown unbundles JS but bundles DTS
# With glob patterns and unbundle, each source file gets its own JS output
# But DTS is still bundled per format
print("tsdown with this config will generate:")
print("- Unbundled JS: ./dist/index.cjs, ./dist/plugin.cjs, ./dist/providers/memory.cjs, etc.")
print("- Unbundled JS: ./dist/index.mjs, ./dist/plugin.mjs, ./dist/providers/memory.mjs, etc.")
print("- Bundled DTS: ./dist/index.d.ts (and possibly separate per-entry if dts config supports it)")
print("\nSince source files are *.ts (not *.cts/*.mts), only .d.ts files are generated, not .d.cts")
EOFRepository: visualbravo/zenstack-cache
Length of output: 466
🏁 Script executed:
# Check if tsdown with unbundle actually outputs separate .d.ts per file or bundled
# Look at real tsdown behavior/documentation more carefully
web_search="tsdown unbundle dts output separate declaration files per entry"Repository: visualbravo/zenstack-cache
Length of output: 52
🏁 Script executed:
# Search for tsdown's actual DTS behavior with glob entries and unbundle
python3 << 'EOF'
# Based on the web search results:
# - tsdown does NOT support "unbundled" DTS files (per source file)
# - It bundles DTS based on rolldown-plugin-dts
# - With glob entries, tsdown would generate bundled DTS files
# - With unbundle for JS and dts=true, JS gets unbundled but DTS is still bundled
# The key question: does tsdown generate a single index.d.ts or separate ones per entry?
# Looking at the tsdown config with glob patterns:
# entry: ['./src/**/*.{ts,tsx}']
# This matches: index.ts, plugin.ts, providers/memory.ts, providers/redis.ts, schemas.ts, superjson.ts, types.ts, utils.ts
# With unbundle=true and glob patterns, each file gets its own JS output
# But with dts=true, the behavior depends on how tsdown handles glob DTS
print("Key insight from tsdown documentation:")
print("- tsdown with `unbundle: true` creates separate JS files per entry")
print("- tsdown with `dts: true` uses rolldown-plugin-dts which bundles")
print("- For glob entries, tsdown may create a single bundled .d.ts or multiple per format")
print("")
print("However, the real issue is:")
print("1. package.json points to './dist/index.d.cts' but tsdown generates '.d.ts'")
print("2. Subpath exports need 'types' conditions for TypeScript subpath import resolution")
EOF
# Search for the actual behavior in tsdown documentation
web_search_query="tsdown glob entry pattern unbundle dts rolldown-plugin-dts bundled"Repository: visualbravo/zenstack-cache
Length of output: 513
🌐 Web query:
tsdown glob entry unbundle dts separate declaration files output structure
💡 Result:
In tsdown:
entryaccepts globs. If you doentry: 'src/**/*.ts', every matched file becomes an entry point, so you’ll get one output file (and one.d.ts, if enabled) per matched source file. If you want to control the output subpaths, use the object entry form (supports*placeholder in keys/values). [1]unbundle: truemakes the JS output mirror your source module structure: every module reachable from the entry graph is emitted as its own file underdist/(1:1 mapping with your source layout). [2]dtsgeneration is “bundled dts”, not “emit one.d.tsper source file”. tsdown generates declarations viarolldown-plugin-dtsand bundles them (typically producing a.d.tsper entry / per chunking result), rather than matchingunbundle’s per-module JS structure with per-module.d.tsfiles. [3][4]
Practical output expectation
A) Few entry points + unbundle: true
export default defineConfig({
entry: ['src/index.ts'],
unbundle: true,
dts: true,
})- JS:
dist/mirrors modules reachable fromsrc/index.ts(e.g.dist/index.js,dist/mod.js, …). [2] - DTS: you should expect a bundled declaration output for the entry (e.g.
dist/index.d.ts), notdist/mod.d.tsfor every module. [3][4]
B) Many entry points via glob
export default defineConfig({
entry: 'src/**/*.ts',
dts: true,
})- You’ll get many
.d.tsfiles because you created many entries (one per matched file). [1][3]
If you specifically need “unbundle-like per-file .d.ts”
tsdown’s built-in dts is designed around bundling declarations. For truly per-file .d.ts that mirrors your folder structure, you typically run tsc (or a separate type build) to emit declarations, and use tsdown for JS. (tsdown’s docs explicitly describe dts as generated/bundled via rolldown-plugin-dts.) [3]
Sources: tsdown entry (glob/object mapping) [1], tsdown unbundle (mirrors module structure) [2], tsdown dts (uses/bundles via rolldown-plugin-dts) [3], rolldown-plugin-dts (generate and bundle dts) [4].
Fix declaration file extension and add types conditions to all subpath exports.
The top-level types field points to ./dist/index.d.cts, but tsdown generates .d.ts files (not .d.cts—which are only produced when the source is .cts). Additionally, subpath exports lack explicit types conditions for TypeScript to resolve declaration files for subpath imports like @package/utils.
With your glob entry pattern and unbundle: true, tsdown generates separate declaration files for each entry (e.g., dist/plugin.d.ts, dist/providers/memory.d.ts, etc.), so each subpath should declare its corresponding types condition.
Suggested shape (repeat for every subpath)
- "types": "./dist/index.d.cts",
+ "types": "./dist/index.d.ts",
"exports": {
".": {
"@zenstack-cache/source": "./src/index.ts",
+ "types": "./dist/index.d.ts",
"require": "./dist/index.cjs",
"import": "./dist/index.mjs"
},
"./plugin": {
"@zenstack-cache/source": "./src/plugin.ts",
+ "types": "./dist/plugin.d.ts",
"require": "./dist/plugin.cjs",
"import": "./dist/plugin.mjs"
},
"./providers/memory": {
"@zenstack-cache/source": "./src/providers/memory.ts",
+ "types": "./dist/providers/memory.d.ts",
"require": "./dist/providers/memory.cjs",
"import": "./dist/providers/memory.mjs"
},
// ... repeat for remaining subpaths
}publishConfig.exports does not need the types conditions since it's for published packages (where @zenstack-cache/source is not available).
🤖 Prompt for AI Agents
In `@package.json` around lines 23 - 105, The package.json currently points
"types" to "./dist/index.d.cts" (wrong extension) and each subpath export (e.g.,
exports keys ".", "./plugin", "./providers/memory", "./providers/redis",
"./schemas", "./superjson", "./types", "./utils") is missing a "types" condition
so TypeScript cannot resolve subpath .d.ts declarations; update the top-level
"types" to "./dist/index.d.ts" and add a "types": "./dist/<entry>.d.ts"
condition for every export subpath entry to match the generated tsdown outputs
(keep publishConfig unchanged as noted).
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Chores